Merge cogl's cogl-1.22 branch into mutter
https://bugzilla.gnome.org/show_bug.cgi?id=760439
This commit is contained in:
commit
3fcbe1d3ec
107
cogl/.gitignore
vendored
Normal file
107
cogl/.gitignore
vendored
Normal file
@ -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-*
|
37
cogl/Makefile.am
Normal file
37
cogl/Makefile.am
Normal file
@ -0,0 +1,37 @@
|
||||
SUBDIRS = test-fixtures
|
||||
|
||||
SUBDIRS += cogl
|
||||
|
||||
if BUILD_COGL_PATH
|
||||
SUBDIRS += cogl-path
|
||||
endif
|
||||
|
||||
if BUILD_COGL_PANGO
|
||||
SUBDIRS += cogl-pango
|
||||
endif
|
||||
|
||||
if BUILD_COGL_GLES2
|
||||
SUBDIRS += cogl-gles2
|
||||
endif
|
||||
|
||||
SUBDIRS += tests
|
||||
|
||||
ACLOCAL_AMFLAGS = -I build/autotools ${ACLOCAL_FLAGS}
|
||||
|
||||
EXTRA_DIST = \
|
||||
config-custom.h
|
||||
|
||||
# .changelog expects these to be initializes
|
||||
CLEANFILES=
|
||||
DISTCLEANFILES=
|
||||
|
||||
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
|
52
cogl/build/autotools/Makefile.am.enums
Normal file
52
cogl/build/autotools/Makefile.am.enums
Normal file
@ -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
|
62
cogl/build/autotools/as-compiler-flag.m4
Normal file
62
cogl/build/autotools/as-compiler-flag.m4
Normal file
@ -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"
|
||||
])
|
||||
|
94
cogl/build/autotools/introspection.m4
Normal file
94
cogl/build/autotools/introspection.m4
Normal file
@ -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])
|
||||
])
|
169
cogl/cogl-gles2/GLES2/gl2.h
Normal file
169
cogl/cogl-gles2/GLES2/gl2.h
Normal file
@ -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_ */
|
1498
cogl/cogl-gles2/GLES2/gl2ext.h
Normal file
1498
cogl/cogl-gles2/GLES2/gl2ext.h
Normal file
File diff suppressed because it is too large
Load Diff
28
cogl/cogl-gles2/GLES2/gl2platform.h
Normal file
28
cogl/cogl-gles2/GLES2/gl2platform.h
Normal file
@ -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_ */
|
31
cogl/cogl-gles2/Makefile.am
Normal file
31
cogl/cogl-gles2/Makefile.am
Normal file
@ -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)
|
1048
cogl/cogl-gles2/cogl-gles2-api.c
Normal file
1048
cogl/cogl-gles2/cogl-gles2-api.c
Normal file
File diff suppressed because it is too large
Load Diff
13
cogl/cogl-gles2/mutter-cogl-gles2-1.0.pc.in
Normal file
13
cogl/cogl-gles2/mutter-cogl-gles2-1.0.pc.in
Normal file
@ -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}
|
109
cogl/cogl-pango/Makefile.am
Normal file
109
cogl/cogl-pango/Makefile.am
Normal file
@ -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
|
499
cogl/cogl-pango/cogl-pango-display-list.c
Normal file
499
cogl/cogl-pango/cogl-pango-display-list.c
Normal file
@ -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);
|
||||
}
|
84
cogl/cogl-pango/cogl-pango-display-list.h
Normal file
84
cogl/cogl-pango/cogl-pango-display-list.h
Normal file
@ -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__ */
|
184
cogl/cogl-pango/cogl-pango-fontmap.c
Normal file
184
cogl/cogl-pango/cogl-pango-fontmap.c
Normal file
@ -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;
|
||||
}
|
433
cogl/cogl-pango/cogl-pango-glyph-cache.c
Normal file
433
cogl/cogl-pango/cogl-pango-glyph-cache.c
Normal file
@ -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);
|
||||
}
|
100
cogl/cogl-pango/cogl-pango-glyph-cache.h
Normal file
100
cogl/cogl-pango/cogl-pango-glyph-cache.h
Normal file
@ -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__ */
|
242
cogl/cogl-pango/cogl-pango-pipeline-cache.c
Normal file
242
cogl/cogl-pango/cogl-pango-pipeline-cache.c
Normal file
@ -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);
|
||||
}
|
72
cogl/cogl-pango/cogl-pango-pipeline-cache.h
Normal file
72
cogl/cogl-pango/cogl-pango-pipeline-cache.h
Normal file
@ -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__ */
|
65
cogl/cogl-pango/cogl-pango-private.h
Normal file
65
cogl/cogl-pango/cogl-pango-private.h
Normal file
@ -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__ */
|
929
cogl/cogl-pango/cogl-pango-render.c
Normal file
929
cogl/cogl-pango/cogl-pango-render.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
298
cogl/cogl-pango/cogl-pango.h
Normal file
298
cogl/cogl-pango/cogl-pango.h
Normal file
@ -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__ */
|
12
cogl/cogl-pango/cogl-pango.symbols
Normal file
12
cogl/cogl-pango/cogl-pango.symbols
Normal file
@ -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
|
13
cogl/cogl-pango/mutter-cogl-pango-1.0.pc.in
Normal file
13
cogl/cogl-pango/mutter-cogl-pango-1.0.pc.in
Normal file
@ -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}
|
104
cogl/cogl-path/Makefile.am
Normal file
104
cogl/cogl-path/Makefile.am
Normal file
@ -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)
|
50
cogl/cogl-path/cogl-path-enum-types.c.in
Normal file
50
cogl/cogl-path/cogl-path-enum-types.c.in
Normal file
@ -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 ***/
|
25
cogl/cogl-path/cogl-path-enum-types.h.in
Normal file
25
cogl/cogl-path/cogl-path-enum-types.h.in
Normal file
@ -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 ***/
|
126
cogl/cogl-path/cogl-path-private.h
Normal file
126
cogl/cogl-path/cogl-path-private.h
Normal file
@ -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 */
|
85
cogl/cogl-path/cogl-path-types.h
Normal file
85
cogl/cogl-path/cogl-path-types.h
Normal file
@ -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__ */
|
1602
cogl/cogl-path/cogl-path.c
Normal file
1602
cogl/cogl-path/cogl-path.c
Normal file
File diff suppressed because it is too large
Load Diff
68
cogl/cogl-path/cogl-path.h
Normal file
68
cogl/cogl-path/cogl-path.h
Normal file
@ -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__ */
|
||||
|
59
cogl/cogl-path/cogl-path.symbols
Normal file
59
cogl/cogl-path/cogl-path.symbols
Normal file
@ -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
|
467
cogl/cogl-path/cogl1-path-functions.h
Normal file
467
cogl/cogl-path/cogl1-path-functions.h
Normal file
@ -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__ */
|
||||
|
353
cogl/cogl-path/cogl1-path.c
Normal file
353
cogl/cogl-path/cogl1-path.c
Normal file
@ -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 ();
|
||||
}
|
545
cogl/cogl-path/cogl2-path-functions.h
Normal file
545
cogl/cogl-path/cogl2-path-functions.h
Normal file
@ -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__ */
|
||||
|
13
cogl/cogl-path/mutter-cogl-path-1.0.pc.in
Normal file
13
cogl/cogl-path/mutter-cogl-path-1.0.pc.in
Normal file
@ -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}
|
47
cogl/cogl-path/tesselator/GL/glu.h
Normal file
47
cogl/cogl-path/tesselator/GL/glu.h
Normal file
@ -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
|
446
cogl/cogl-path/tesselator/README
Normal file
446
cogl/cogl-path/tesselator/README
Normal file
@ -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
|
100
cogl/cogl-path/tesselator/dict-list.h
Normal file
100
cogl/cogl-path/tesselator/dict-list.h
Normal file
@ -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
|
111
cogl/cogl-path/tesselator/dict.c
Normal file
111
cogl/cogl-path/tesselator/dict.c
Normal file
@ -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;
|
||||
}
|
100
cogl/cogl-path/tesselator/dict.h
Normal file
100
cogl/cogl-path/tesselator/dict.h
Normal file
@ -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
|
264
cogl/cogl-path/tesselator/geom.c
Normal file
264
cogl/cogl-path/tesselator/geom.c
Normal file
@ -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 );
|
||||
}
|
||||
}
|
84
cogl/cogl-path/tesselator/geom.h
Normal file
84
cogl/cogl-path/tesselator/geom.h
Normal file
@ -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
|
1
cogl/cogl-path/tesselator/gluos.h
Normal file
1
cogl/cogl-path/tesselator/gluos.h
Normal file
@ -0,0 +1 @@
|
||||
/* This is a stub header to avoid having to change tess.c */
|
49
cogl/cogl-path/tesselator/memalloc.h
Normal file
49
cogl/cogl-path/tesselator/memalloc.h
Normal file
@ -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__ */
|
798
cogl/cogl-path/tesselator/mesh.c
Normal file
798
cogl/cogl-path/tesselator/mesh.c
Normal file
@ -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
|
266
cogl/cogl-path/tesselator/mesh.h
Normal file
266
cogl/cogl-path/tesselator/mesh.h
Normal file
@ -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
|
257
cogl/cogl-path/tesselator/normal.c
Normal file
257
cogl/cogl-path/tesselator/normal.c
Normal file
@ -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 );
|
||||
}
|
||||
}
|
45
cogl/cogl-path/tesselator/normal.h
Normal file
45
cogl/cogl-path/tesselator/normal.h
Normal file
@ -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
|
256
cogl/cogl-path/tesselator/priorityq-heap.c
Normal file
256
cogl/cogl-path/tesselator/priorityq-heap.c
Normal file
@ -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;
|
||||
}
|
107
cogl/cogl-path/tesselator/priorityq-heap.h
Normal file
107
cogl/cogl-path/tesselator/priorityq-heap.h
Normal file
@ -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
|
117
cogl/cogl-path/tesselator/priorityq-sort.h
Normal file
117
cogl/cogl-path/tesselator/priorityq-sort.h
Normal file
@ -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
|
261
cogl/cogl-path/tesselator/priorityq.c
Normal file
261
cogl/cogl-path/tesselator/priorityq.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
117
cogl/cogl-path/tesselator/priorityq.h
Normal file
117
cogl/cogl-path/tesselator/priorityq.h
Normal file
@ -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
|
502
cogl/cogl-path/tesselator/render.c
Normal file
502
cogl/cogl-path/tesselator/render.c
Normal file
@ -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;
|
||||
}
|
52
cogl/cogl-path/tesselator/render.h
Normal file
52
cogl/cogl-path/tesselator/render.h
Normal file
@ -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
|
1361
cogl/cogl-path/tesselator/sweep.c
Normal file
1361
cogl/cogl-path/tesselator/sweep.c
Normal file
File diff suppressed because it is too large
Load Diff
77
cogl/cogl-path/tesselator/sweep.h
Normal file
77
cogl/cogl-path/tesselator/sweep.h
Normal file
@ -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
|
632
cogl/cogl-path/tesselator/tess.c
Normal file
632
cogl/cogl-path/tesselator/tess.c
Normal file
@ -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 );
|
||||
}
|
165
cogl/cogl-path/tesselator/tess.h
Normal file
165
cogl/cogl-path/tesselator/tess.h
Normal file
@ -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
|
122
cogl/cogl-path/tesselator/tesselator.h
Normal file
122
cogl/cogl-path/tesselator/tesselator.h
Normal file
@ -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__ */
|
201
cogl/cogl-path/tesselator/tessmono.c
Normal file
201
cogl/cogl-path/tesselator/tessmono.c
Normal file
@ -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;
|
||||
}
|
71
cogl/cogl-path/tesselator/tessmono.h
Normal file
71
cogl/cogl-path/tesselator/tessmono.h
Normal file
@ -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
|
547
cogl/cogl/Makefile.am
Normal file
547
cogl/cogl/Makefile.am
Normal file
@ -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
|
81
cogl/cogl/cogl-atlas-texture-private.h
Normal file
81
cogl/cogl/cogl-atlas-texture-private.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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_ATLAS_TEXTURE_PRIVATE_H_
|
||||
#define _COGL_ATLAS_TEXTURE_PRIVATE_H_
|
||||
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-texture-private.h"
|
||||
#include "cogl-rectangle-map.h"
|
||||
#include "cogl-atlas.h"
|
||||
#include "cogl-atlas-texture.h"
|
||||
|
||||
struct _CoglAtlasTexture
|
||||
{
|
||||
CoglTexture _parent;
|
||||
|
||||
/* The format that the texture is in. This isn't necessarily the
|
||||
same format as the atlas texture because we can store
|
||||
pre-multiplied and non-pre-multiplied textures together */
|
||||
CoglPixelFormat internal_format;
|
||||
|
||||
/* The rectangle that was used to add this texture to the
|
||||
atlas. This includes the 1-pixel border */
|
||||
CoglRectangleMapEntry rectangle;
|
||||
|
||||
/* The atlas that this texture is in. If the texture is no longer in
|
||||
an atlas then this will be NULL. A reference is taken on the
|
||||
atlas by the texture (but not vice versa so there is no cycle) */
|
||||
CoglAtlas *atlas;
|
||||
|
||||
/* Either a CoglSubTexture representing the atlas region for easy
|
||||
* rendering or if the texture has been migrated out of the atlas it
|
||||
* may be some other texture type such as CoglTexture2D */
|
||||
CoglTexture *sub_texture;
|
||||
};
|
||||
|
||||
CoglAtlasTexture *
|
||||
_cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp,
|
||||
CoglBool can_convert_in_place);
|
||||
|
||||
void
|
||||
_cogl_atlas_texture_add_reorganize_callback (CoglContext *ctx,
|
||||
GHookFunc callback,
|
||||
void *user_data);
|
||||
|
||||
void
|
||||
_cogl_atlas_texture_remove_reorganize_callback (CoglContext *ctx,
|
||||
GHookFunc callback,
|
||||
void *user_data);
|
||||
|
||||
CoglBool
|
||||
_cogl_is_atlas_texture (void *object);
|
||||
|
||||
#endif /* _COGL_ATLAS_TEXTURE_PRIVATE_H_ */
|
1047
cogl/cogl/cogl-atlas-texture.c
Normal file
1047
cogl/cogl/cogl-atlas-texture.c
Normal file
File diff suppressed because it is too large
Load Diff
258
cogl/cogl/cogl-atlas-texture.h
Normal file
258
cogl/cogl/cogl-atlas-texture.h
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 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_ATLAS_TEXTURE_H_
|
||||
#define _COGL_ATLAS_TEXTURE_H_
|
||||
|
||||
#include <cogl/cogl-context.h>
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
#include <glib-object.h>
|
||||
#endif
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* SECTION:cogl-atlas-texture
|
||||
* @short_description: Functions for managing textures in Cogl's global
|
||||
* set of texture atlases
|
||||
*
|
||||
* A texture atlas is a texture that contains many smaller images that
|
||||
* an application is interested in. These are packed together as a way
|
||||
* of optimizing drawing with those images by avoiding the costs of
|
||||
* repeatedly telling the hardware to change what texture it should
|
||||
* sample from. This can enable more geometry to be batched together
|
||||
* into few draw calls.
|
||||
*
|
||||
* Each #CoglContext has an shared, pool of texture atlases that are
|
||||
* are managed by Cogl.
|
||||
*
|
||||
* This api lets applications upload texture data into one of Cogl's
|
||||
* shared texture atlases using a high-level #CoglAtlasTexture which
|
||||
* represents a sub-region of one of these atlases.
|
||||
*
|
||||
* <note>A #CoglAtlasTexture is a high-level meta texture which has
|
||||
* some limitations to be aware of. Please see the documentation for
|
||||
* #CoglMetaTexture for more details.</note>
|
||||
*/
|
||||
|
||||
|
||||
typedef struct _CoglAtlasTexture CoglAtlasTexture;
|
||||
#define COGL_ATLAS_TEXTURE(tex) ((CoglAtlasTexture *) tex)
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
/**
|
||||
* cogl_atlas_texture_get_gtype:
|
||||
*
|
||||
* Returns: a #GType that can be used with the GLib type system.
|
||||
*/
|
||||
GType cogl_atlas_texture_get_gtype (void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cogl_atlas_texture_new_with_size:
|
||||
* @ctx: A #CoglContext
|
||||
* @width: The width of your atlased texture.
|
||||
* @height: The height of your atlased texture.
|
||||
*
|
||||
* Creates a #CoglAtlasTexture with a given @width and @height. A
|
||||
* #CoglAtlasTexture represents a sub-region within one of Cogl's
|
||||
* shared texture atlases.
|
||||
*
|
||||
* The storage for the texture is not allocated before this function
|
||||
* returns. You can call cogl_texture_allocate() to explicitly
|
||||
* allocate the underlying storage or let Cogl automatically allocate
|
||||
* storage lazily.
|
||||
*
|
||||
* The texture is still configurable until it has been allocated so
|
||||
* for example you can influence the internal format of the texture
|
||||
* using cogl_texture_set_components() and
|
||||
* cogl_texture_set_premultiplied().
|
||||
*
|
||||
* <note>Allocate call can fail if Cogl considers the internal
|
||||
* format to be incompatible with the format of its internal
|
||||
* atlases.</note>
|
||||
*
|
||||
* <note>The returned #CoglAtlasTexture is a high-level meta-texture
|
||||
* with some limitations. See the documentation for #CoglMetaTexture
|
||||
* for more details.</note>
|
||||
*
|
||||
* Returns: (transfer full): A new #CoglAtlasTexture object.
|
||||
* Since: 1.16
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglAtlasTexture *
|
||||
cogl_atlas_texture_new_with_size (CoglContext *ctx,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
/**
|
||||
* cogl_atlas_texture_new_from_file:
|
||||
* @ctx: A #CoglContext
|
||||
* @filename: the file to load
|
||||
* @error: A #CoglError to catch exceptional errors or %NULL
|
||||
*
|
||||
* Creates a #CoglAtlasTexture from an image file. A #CoglAtlasTexture
|
||||
* represents a sub-region within one of Cogl's shared texture
|
||||
* atlases.
|
||||
*
|
||||
* The storage for the texture is not allocated before this function
|
||||
* returns. You can call cogl_texture_allocate() to explicitly
|
||||
* allocate the underlying storage or let Cogl automatically allocate
|
||||
* storage lazily.
|
||||
*
|
||||
* The texture is still configurable until it has been allocated so
|
||||
* for example you can influence the internal format of the texture
|
||||
* using cogl_texture_set_components() and
|
||||
* cogl_texture_set_premultiplied().
|
||||
*
|
||||
* <note>Allocate call can fail if Cogl considers the internal
|
||||
* format to be incompatible with the format of its internal
|
||||
* atlases.</note>
|
||||
*
|
||||
* <note>The returned #CoglAtlasTexture is a high-level meta-texture
|
||||
* with some limitations. See the documentation for #CoglMetaTexture
|
||||
* for more details.</note>
|
||||
*
|
||||
* Return value: (transfer full): A new #CoglAtlasTexture object or
|
||||
* %NULL on failure and @error will be updated.
|
||||
* Since: 1.16
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglAtlasTexture *
|
||||
cogl_atlas_texture_new_from_file (CoglContext *ctx,
|
||||
const char *filename,
|
||||
CoglError **error);
|
||||
|
||||
/**
|
||||
* cogl_atlas_texture_new_from_data:
|
||||
* @ctx: A #CoglContext
|
||||
* @width: width of texture in pixels
|
||||
* @height: height of texture in pixels
|
||||
* @format: the #CoglPixelFormat the buffer is stored in in RAM
|
||||
* @rowstride: the memory offset in bytes between the start of each
|
||||
* row in @data. A value of 0 will make Cogl automatically
|
||||
* calculate @rowstride from @width and @format.
|
||||
* @data: pointer to the memory region where the source buffer resides
|
||||
* @error: A #CoglError to catch exceptional errors or %NULL
|
||||
*
|
||||
* Creates a new #CoglAtlasTexture texture based on data residing in
|
||||
* memory. A #CoglAtlasTexture represents a sub-region within one of
|
||||
* Cogl's shared texture atlases.
|
||||
*
|
||||
* <note>This api will always immediately allocate GPU memory for the
|
||||
* texture and upload the given data so that the @data pointer does
|
||||
* not need to remain valid once this function returns. This means it
|
||||
* is not possible to configure the texture before it is allocated. If
|
||||
* you do need to configure the texture before allocation (to specify
|
||||
* constraints on the internal format for example) then you can
|
||||
* instead create a #CoglBitmap for your data and use
|
||||
* cogl_atlas_texture_new_from_bitmap() or use
|
||||
* cogl_atlas_texture_new_with_size() and then upload data using
|
||||
* cogl_texture_set_data()</note>
|
||||
*
|
||||
* <note>Allocate call can fail if Cogl considers the internal
|
||||
* format to be incompatible with the format of its internal
|
||||
* atlases.</note>
|
||||
*
|
||||
* <note>The returned #CoglAtlasTexture is a high-level
|
||||
* meta-texture with some limitations. See the documentation for
|
||||
* #CoglMetaTexture for more details.</note>
|
||||
*
|
||||
* Return value: (transfer full): A new #CoglAtlasTexture object or
|
||||
* %NULL on failure and @error will be updated.
|
||||
* Since: 1.16
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglAtlasTexture *
|
||||
cogl_atlas_texture_new_from_data (CoglContext *ctx,
|
||||
int width,
|
||||
int height,
|
||||
CoglPixelFormat format,
|
||||
int rowstride,
|
||||
const uint8_t *data,
|
||||
CoglError **error);
|
||||
|
||||
/**
|
||||
* cogl_atlas_texture_new_from_bitmap:
|
||||
* @bitmap: A #CoglBitmap
|
||||
*
|
||||
* Creates a new #CoglAtlasTexture texture based on data residing in a
|
||||
* @bitmap. A #CoglAtlasTexture represents a sub-region within one of
|
||||
* Cogl's shared texture atlases.
|
||||
*
|
||||
* The storage for the texture is not allocated before this function
|
||||
* returns. You can call cogl_texture_allocate() to explicitly
|
||||
* allocate the underlying storage or preferably let Cogl
|
||||
* automatically allocate storage lazily when it may know more about
|
||||
* how the texture is being used and can optimize how it is allocated.
|
||||
*
|
||||
* The texture is still configurable until it has been allocated so
|
||||
* for example you can influence the internal format of the texture
|
||||
* using cogl_texture_set_components() and
|
||||
* cogl_texture_set_premultiplied().
|
||||
*
|
||||
* <note>Allocate call can fail if Cogl considers the internal
|
||||
* format to be incompatible with the format of its internal
|
||||
* atlases.</note>
|
||||
*
|
||||
* <note>The returned #CoglAtlasTexture is a high-level meta-texture
|
||||
* with some limitations. See the documentation for #CoglMetaTexture
|
||||
* for more details.</note>
|
||||
*
|
||||
* Returns: (transfer full): A new #CoglAtlasTexture object.
|
||||
* Since: 1.16
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglAtlasTexture *
|
||||
cogl_atlas_texture_new_from_bitmap (CoglBitmap *bmp);
|
||||
|
||||
/**
|
||||
* cogl_is_atlas_texture:
|
||||
* @object: a #CoglObject
|
||||
*
|
||||
* Checks whether the given object references a #CoglAtlasTexture
|
||||
*
|
||||
* Return value: %TRUE if the passed object represents an atlas
|
||||
* texture and %FALSE otherwise
|
||||
*
|
||||
* Since: 1.16
|
||||
* Stability: Unstable
|
||||
*/
|
||||
CoglBool
|
||||
cogl_is_atlas_texture (void *object);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* _COGL_ATLAS_TEXTURE_H_ */
|
690
cogl/cogl/cogl-atlas.c
Normal file
690
cogl/cogl/cogl-atlas.c
Normal file
@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2010,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 "cogl-atlas.h"
|
||||
#include "cogl-rectangle-map.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-texture-private.h"
|
||||
#include "cogl-texture-2d-private.h"
|
||||
#include "cogl-texture-2d-sliced.h"
|
||||
#include "cogl-texture-driver.h"
|
||||
#include "cogl-pipeline-opengl-private.h"
|
||||
#include "cogl-debug.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-blit.h"
|
||||
#include "cogl-private.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void _cogl_atlas_free (CoglAtlas *atlas);
|
||||
|
||||
COGL_OBJECT_INTERNAL_DEFINE (Atlas, atlas);
|
||||
|
||||
CoglAtlas *
|
||||
_cogl_atlas_new (CoglPixelFormat texture_format,
|
||||
CoglAtlasFlags flags,
|
||||
CoglAtlasUpdatePositionCallback update_position_cb)
|
||||
{
|
||||
CoglAtlas *atlas = g_new (CoglAtlas, 1);
|
||||
|
||||
atlas->update_position_cb = update_position_cb;
|
||||
atlas->map = NULL;
|
||||
atlas->texture = NULL;
|
||||
atlas->flags = flags;
|
||||
atlas->texture_format = texture_format;
|
||||
g_hook_list_init (&atlas->pre_reorganize_callbacks, sizeof (GHook));
|
||||
g_hook_list_init (&atlas->post_reorganize_callbacks, sizeof (GHook));
|
||||
|
||||
return _cogl_atlas_object_new (atlas);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_atlas_free (CoglAtlas *atlas)
|
||||
{
|
||||
COGL_NOTE (ATLAS, "%p: Atlas destroyed", atlas);
|
||||
|
||||
if (atlas->texture)
|
||||
cogl_object_unref (atlas->texture);
|
||||
if (atlas->map)
|
||||
_cogl_rectangle_map_free (atlas->map);
|
||||
|
||||
g_hook_list_clear (&atlas->pre_reorganize_callbacks);
|
||||
g_hook_list_clear (&atlas->post_reorganize_callbacks);
|
||||
|
||||
g_free (atlas);
|
||||
}
|
||||
|
||||
typedef struct _CoglAtlasRepositionData
|
||||
{
|
||||
/* The current user data for this texture */
|
||||
void *user_data;
|
||||
/* The old and new positions of the texture */
|
||||
CoglRectangleMapEntry old_position;
|
||||
CoglRectangleMapEntry new_position;
|
||||
} CoglAtlasRepositionData;
|
||||
|
||||
static void
|
||||
_cogl_atlas_migrate (CoglAtlas *atlas,
|
||||
unsigned int n_textures,
|
||||
CoglAtlasRepositionData *textures,
|
||||
CoglTexture *old_texture,
|
||||
CoglTexture *new_texture,
|
||||
void *skip_user_data)
|
||||
{
|
||||
unsigned int i;
|
||||
CoglBlitData blit_data;
|
||||
|
||||
/* If the 'disable migrate' flag is set then we won't actually copy
|
||||
the textures to their new location. Instead we'll just invoke the
|
||||
callback to update the position */
|
||||
if ((atlas->flags & COGL_ATLAS_DISABLE_MIGRATION))
|
||||
for (i = 0; i < n_textures; i++)
|
||||
/* Update the texture position */
|
||||
atlas->update_position_cb (textures[i].user_data,
|
||||
new_texture,
|
||||
&textures[i].new_position);
|
||||
else
|
||||
{
|
||||
_cogl_blit_begin (&blit_data, new_texture, old_texture);
|
||||
|
||||
for (i = 0; i < n_textures; i++)
|
||||
{
|
||||
/* Skip the texture that is being added because it doesn't contain
|
||||
any data yet */
|
||||
if (textures[i].user_data != skip_user_data)
|
||||
_cogl_blit (&blit_data,
|
||||
textures[i].old_position.x,
|
||||
textures[i].old_position.y,
|
||||
textures[i].new_position.x,
|
||||
textures[i].new_position.y,
|
||||
textures[i].new_position.width,
|
||||
textures[i].new_position.height);
|
||||
|
||||
/* Update the texture position */
|
||||
atlas->update_position_cb (textures[i].user_data,
|
||||
new_texture,
|
||||
&textures[i].new_position);
|
||||
}
|
||||
|
||||
_cogl_blit_end (&blit_data);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _CoglAtlasGetRectanglesData
|
||||
{
|
||||
CoglAtlasRepositionData *textures;
|
||||
/* Number of textures found so far */
|
||||
unsigned int n_textures;
|
||||
} CoglAtlasGetRectanglesData;
|
||||
|
||||
static void
|
||||
_cogl_atlas_get_rectangles_cb (const CoglRectangleMapEntry *rectangle,
|
||||
void *rect_data,
|
||||
void *user_data)
|
||||
{
|
||||
CoglAtlasGetRectanglesData *data = user_data;
|
||||
|
||||
data->textures[data->n_textures].old_position = *rectangle;
|
||||
data->textures[data->n_textures++].user_data = rect_data;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_atlas_get_next_size (unsigned int *map_width,
|
||||
unsigned int *map_height)
|
||||
{
|
||||
/* Double the size of the texture by increasing whichever dimension
|
||||
is smaller */
|
||||
if (*map_width < *map_height)
|
||||
*map_width <<= 1;
|
||||
else
|
||||
*map_height <<= 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_atlas_get_initial_size (CoglPixelFormat format,
|
||||
unsigned int *map_width,
|
||||
unsigned int *map_height)
|
||||
{
|
||||
unsigned int size;
|
||||
GLenum gl_intformat;
|
||||
GLenum gl_format;
|
||||
GLenum gl_type;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
ctx->driver_vtable->pixel_format_to_gl (ctx,
|
||||
format,
|
||||
&gl_intformat,
|
||||
&gl_format,
|
||||
&gl_type);
|
||||
|
||||
/* At least on Intel hardware, the texture size will be rounded up
|
||||
to at least 1MB so we might as well try to aim for that as an
|
||||
initial minimum size. If the format is only 1 byte per pixel we
|
||||
can use 1024x1024, otherwise we'll assume it will take 4 bytes
|
||||
per pixel and use 512x512. */
|
||||
if (_cogl_pixel_format_get_bytes_per_pixel (format) == 1)
|
||||
size = 1024;
|
||||
else
|
||||
size = 512;
|
||||
|
||||
/* Some platforms might not support this large size so we'll
|
||||
decrease the size until it can */
|
||||
while (size > 1 &&
|
||||
!ctx->texture_driver->size_supported (ctx,
|
||||
GL_TEXTURE_2D,
|
||||
gl_intformat,
|
||||
gl_format,
|
||||
gl_type,
|
||||
size, size))
|
||||
size >>= 1;
|
||||
|
||||
*map_width = size;
|
||||
*map_height = size;
|
||||
}
|
||||
|
||||
static CoglRectangleMap *
|
||||
_cogl_atlas_create_map (CoglPixelFormat format,
|
||||
unsigned int map_width,
|
||||
unsigned int map_height,
|
||||
unsigned int n_textures,
|
||||
CoglAtlasRepositionData *textures)
|
||||
{
|
||||
GLenum gl_intformat;
|
||||
GLenum gl_format;
|
||||
GLenum gl_type;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
ctx->driver_vtable->pixel_format_to_gl (ctx,
|
||||
format,
|
||||
&gl_intformat,
|
||||
&gl_format,
|
||||
&gl_type);
|
||||
|
||||
/* Keep trying increasingly larger atlases until we can fit all of
|
||||
the textures */
|
||||
while (ctx->texture_driver->size_supported (ctx,
|
||||
GL_TEXTURE_2D,
|
||||
gl_intformat,
|
||||
gl_format,
|
||||
gl_type,
|
||||
map_width, map_height))
|
||||
{
|
||||
CoglRectangleMap *new_atlas = _cogl_rectangle_map_new (map_width,
|
||||
map_height,
|
||||
NULL);
|
||||
unsigned int i;
|
||||
|
||||
COGL_NOTE (ATLAS, "Trying to resize the atlas to %ux%u",
|
||||
map_width, map_height);
|
||||
|
||||
/* Add all of the textures and keep track of the new position */
|
||||
for (i = 0; i < n_textures; i++)
|
||||
if (!_cogl_rectangle_map_add (new_atlas,
|
||||
textures[i].old_position.width,
|
||||
textures[i].old_position.height,
|
||||
textures[i].user_data,
|
||||
&textures[i].new_position))
|
||||
break;
|
||||
|
||||
/* If the atlas can contain all of the textures then we have a
|
||||
winner */
|
||||
if (i >= n_textures)
|
||||
return new_atlas;
|
||||
else
|
||||
COGL_NOTE (ATLAS, "Atlas size abandoned after trying "
|
||||
"%u out of %u textures",
|
||||
i, n_textures);
|
||||
|
||||
_cogl_rectangle_map_free (new_atlas);
|
||||
_cogl_atlas_get_next_size (&map_width, &map_height);
|
||||
}
|
||||
|
||||
/* If we get here then there's no atlas that can accommodate all of
|
||||
the rectangles */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CoglTexture2D *
|
||||
_cogl_atlas_create_texture (CoglAtlas *atlas,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
CoglTexture2D *tex;
|
||||
CoglError *ignore_error = NULL;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
if ((atlas->flags & COGL_ATLAS_CLEAR_TEXTURE))
|
||||
{
|
||||
uint8_t *clear_data;
|
||||
CoglBitmap *clear_bmp;
|
||||
int bpp = _cogl_pixel_format_get_bytes_per_pixel (atlas->texture_format);
|
||||
|
||||
/* Create a buffer of zeroes to initially clear the texture */
|
||||
clear_data = g_malloc0 (width * height * bpp);
|
||||
clear_bmp = cogl_bitmap_new_for_data (ctx,
|
||||
width,
|
||||
height,
|
||||
atlas->texture_format,
|
||||
width * bpp,
|
||||
clear_data);
|
||||
|
||||
tex = cogl_texture_2d_new_from_bitmap (clear_bmp);
|
||||
|
||||
_cogl_texture_set_internal_format (COGL_TEXTURE (tex),
|
||||
atlas->texture_format);
|
||||
|
||||
if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error))
|
||||
{
|
||||
cogl_error_free (ignore_error);
|
||||
cogl_object_unref (tex);
|
||||
tex = NULL;
|
||||
}
|
||||
|
||||
cogl_object_unref (clear_bmp);
|
||||
|
||||
g_free (clear_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
tex = cogl_texture_2d_new_with_size (ctx, width, height);
|
||||
|
||||
_cogl_texture_set_internal_format (COGL_TEXTURE (tex),
|
||||
atlas->texture_format);
|
||||
|
||||
if (!cogl_texture_allocate (COGL_TEXTURE (tex), &ignore_error))
|
||||
{
|
||||
cogl_error_free (ignore_error);
|
||||
cogl_object_unref (tex);
|
||||
tex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static int
|
||||
_cogl_atlas_compare_size_cb (const void *a,
|
||||
const void *b)
|
||||
{
|
||||
const CoglAtlasRepositionData *ta = a;
|
||||
const CoglAtlasRepositionData *tb = b;
|
||||
unsigned int a_size, b_size;
|
||||
|
||||
a_size = ta->old_position.width * ta->old_position.height;
|
||||
b_size = tb->old_position.width * tb->old_position.height;
|
||||
|
||||
return a_size < b_size ? 1 : a_size > b_size ? -1 : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_atlas_notify_pre_reorganize (CoglAtlas *atlas)
|
||||
{
|
||||
g_hook_list_invoke (&atlas->pre_reorganize_callbacks, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_atlas_notify_post_reorganize (CoglAtlas *atlas)
|
||||
{
|
||||
g_hook_list_invoke (&atlas->post_reorganize_callbacks, FALSE);
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_atlas_reserve_space (CoglAtlas *atlas,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
void *user_data)
|
||||
{
|
||||
CoglAtlasGetRectanglesData data;
|
||||
CoglRectangleMap *new_map;
|
||||
CoglTexture2D *new_tex;
|
||||
unsigned int map_width = 0, map_height = 0;
|
||||
CoglBool ret;
|
||||
CoglRectangleMapEntry new_position;
|
||||
|
||||
/* Check if we can fit the rectangle into the existing map */
|
||||
if (atlas->map &&
|
||||
_cogl_rectangle_map_add (atlas->map, width, height,
|
||||
user_data,
|
||||
&new_position))
|
||||
{
|
||||
COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
|
||||
atlas,
|
||||
_cogl_rectangle_map_get_width (atlas->map),
|
||||
_cogl_rectangle_map_get_height (atlas->map),
|
||||
_cogl_rectangle_map_get_n_rectangles (atlas->map),
|
||||
/* waste as a percentage */
|
||||
_cogl_rectangle_map_get_remaining_space (atlas->map) *
|
||||
100 / (_cogl_rectangle_map_get_width (atlas->map) *
|
||||
_cogl_rectangle_map_get_height (atlas->map)));
|
||||
|
||||
atlas->update_position_cb (user_data,
|
||||
atlas->texture,
|
||||
&new_position);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* If we make it here then we need to reorganize the atlas. First
|
||||
we'll notify any users of the atlas that this is going to happen
|
||||
so that for example in CoglAtlasTexture it can notify that the
|
||||
storage has changed and cause a flush */
|
||||
_cogl_atlas_notify_pre_reorganize (atlas);
|
||||
|
||||
/* Get an array of all the textures currently in the atlas. */
|
||||
data.n_textures = 0;
|
||||
if (atlas->map == NULL)
|
||||
data.textures = g_malloc (sizeof (CoglAtlasRepositionData));
|
||||
else
|
||||
{
|
||||
unsigned int n_rectangles =
|
||||
_cogl_rectangle_map_get_n_rectangles (atlas->map);
|
||||
data.textures = g_malloc (sizeof (CoglAtlasRepositionData) *
|
||||
(n_rectangles + 1));
|
||||
_cogl_rectangle_map_foreach (atlas->map,
|
||||
_cogl_atlas_get_rectangles_cb,
|
||||
&data);
|
||||
}
|
||||
|
||||
/* Add the new rectangle as a dummy texture so that it can be
|
||||
positioned with the rest */
|
||||
data.textures[data.n_textures].old_position.x = 0;
|
||||
data.textures[data.n_textures].old_position.y = 0;
|
||||
data.textures[data.n_textures].old_position.width = width;
|
||||
data.textures[data.n_textures].old_position.height = height;
|
||||
data.textures[data.n_textures++].user_data = user_data;
|
||||
|
||||
/* The atlasing algorithm works a lot better if the rectangles are
|
||||
added in decreasing order of size so we'll first sort the
|
||||
array */
|
||||
qsort (data.textures, data.n_textures,
|
||||
sizeof (CoglAtlasRepositionData),
|
||||
_cogl_atlas_compare_size_cb);
|
||||
|
||||
/* Try to create a new atlas that can contain all of the textures */
|
||||
if (atlas->map)
|
||||
{
|
||||
map_width = _cogl_rectangle_map_get_width (atlas->map);
|
||||
map_height = _cogl_rectangle_map_get_height (atlas->map);
|
||||
|
||||
/* If there is enough space in for the new rectangle in the
|
||||
existing atlas with at least 6% waste we'll start with the
|
||||
same size, otherwise we'll immediately double it */
|
||||
if ((map_width * map_height -
|
||||
_cogl_rectangle_map_get_remaining_space (atlas->map) +
|
||||
width * height) * 53 / 50 >
|
||||
map_width * map_height)
|
||||
_cogl_atlas_get_next_size (&map_width, &map_height);
|
||||
}
|
||||
else
|
||||
_cogl_atlas_get_initial_size (atlas->texture_format,
|
||||
&map_width, &map_height);
|
||||
|
||||
new_map = _cogl_atlas_create_map (atlas->texture_format,
|
||||
map_width, map_height,
|
||||
data.n_textures, data.textures);
|
||||
|
||||
/* If we can't create a map with the texture then give up */
|
||||
if (new_map == NULL)
|
||||
{
|
||||
COGL_NOTE (ATLAS, "%p: Could not fit texture in the atlas", atlas);
|
||||
ret = FALSE;
|
||||
}
|
||||
/* We need to migrate the existing textures into a new texture */
|
||||
else if ((new_tex = _cogl_atlas_create_texture
|
||||
(atlas,
|
||||
_cogl_rectangle_map_get_width (new_map),
|
||||
_cogl_rectangle_map_get_height (new_map))) == NULL)
|
||||
{
|
||||
COGL_NOTE (ATLAS, "%p: Could not create a CoglTexture2D", atlas);
|
||||
_cogl_rectangle_map_free (new_map);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int waste;
|
||||
|
||||
COGL_NOTE (ATLAS,
|
||||
"%p: Atlas %s with size %ix%i",
|
||||
atlas,
|
||||
atlas->map == NULL ||
|
||||
_cogl_rectangle_map_get_width (atlas->map) !=
|
||||
_cogl_rectangle_map_get_width (new_map) ||
|
||||
_cogl_rectangle_map_get_height (atlas->map) !=
|
||||
_cogl_rectangle_map_get_height (new_map) ?
|
||||
"resized" : "reorganized",
|
||||
_cogl_rectangle_map_get_width (new_map),
|
||||
_cogl_rectangle_map_get_height (new_map));
|
||||
|
||||
if (atlas->map)
|
||||
{
|
||||
/* Move all the textures to the right position in the new
|
||||
texture. This will also update the texture's rectangle */
|
||||
_cogl_atlas_migrate (atlas,
|
||||
data.n_textures,
|
||||
data.textures,
|
||||
atlas->texture,
|
||||
COGL_TEXTURE (new_tex),
|
||||
user_data);
|
||||
_cogl_rectangle_map_free (atlas->map);
|
||||
cogl_object_unref (atlas->texture);
|
||||
}
|
||||
else
|
||||
/* We know there's only one texture so we can just directly
|
||||
update the rectangle from its new position */
|
||||
atlas->update_position_cb (data.textures[0].user_data,
|
||||
COGL_TEXTURE (new_tex),
|
||||
&data.textures[0].new_position);
|
||||
|
||||
atlas->map = new_map;
|
||||
atlas->texture = COGL_TEXTURE (new_tex);
|
||||
|
||||
waste = (_cogl_rectangle_map_get_remaining_space (atlas->map) *
|
||||
100 / (_cogl_rectangle_map_get_width (atlas->map) *
|
||||
_cogl_rectangle_map_get_height (atlas->map)));
|
||||
|
||||
COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
|
||||
atlas,
|
||||
_cogl_rectangle_map_get_width (atlas->map),
|
||||
_cogl_rectangle_map_get_height (atlas->map),
|
||||
_cogl_rectangle_map_get_n_rectangles (atlas->map),
|
||||
waste);
|
||||
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
g_free (data.textures);
|
||||
|
||||
_cogl_atlas_notify_post_reorganize (atlas);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_atlas_remove (CoglAtlas *atlas,
|
||||
const CoglRectangleMapEntry *rectangle)
|
||||
{
|
||||
_cogl_rectangle_map_remove (atlas->map, rectangle);
|
||||
|
||||
COGL_NOTE (ATLAS, "%p: Removed rectangle sized %ix%i",
|
||||
atlas,
|
||||
rectangle->width,
|
||||
rectangle->height);
|
||||
COGL_NOTE (ATLAS, "%p: Atlas is %ix%i, has %i textures and is %i%% waste",
|
||||
atlas,
|
||||
_cogl_rectangle_map_get_width (atlas->map),
|
||||
_cogl_rectangle_map_get_height (atlas->map),
|
||||
_cogl_rectangle_map_get_n_rectangles (atlas->map),
|
||||
_cogl_rectangle_map_get_remaining_space (atlas->map) *
|
||||
100 / (_cogl_rectangle_map_get_width (atlas->map) *
|
||||
_cogl_rectangle_map_get_height (atlas->map)));
|
||||
};
|
||||
|
||||
static CoglTexture *
|
||||
create_migration_texture (CoglContext *ctx,
|
||||
int width,
|
||||
int height,
|
||||
CoglPixelFormat internal_format)
|
||||
{
|
||||
CoglTexture *tex;
|
||||
CoglError *skip_error = NULL;
|
||||
|
||||
if ((_cogl_util_is_pot (width) && _cogl_util_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_internal_format (tex, internal_format);
|
||||
|
||||
/* TODO: instead of allocating storage here it would be better
|
||||
* if we had some api that let us just check that the size is
|
||||
* supported by the hardware so storage could be allocated
|
||||
* lazily when uploading data. */
|
||||
if (!cogl_texture_allocate (tex, &skip_error))
|
||||
{
|
||||
cogl_error_free (skip_error);
|
||||
cogl_object_unref (tex);
|
||||
tex = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
tex = NULL;
|
||||
|
||||
if (!tex)
|
||||
{
|
||||
CoglTexture2DSliced *tex_2ds =
|
||||
cogl_texture_2d_sliced_new_with_size (ctx,
|
||||
width,
|
||||
height,
|
||||
COGL_TEXTURE_MAX_WASTE);
|
||||
|
||||
_cogl_texture_set_internal_format (COGL_TEXTURE (tex_2ds),
|
||||
internal_format);
|
||||
|
||||
tex = COGL_TEXTURE (tex_2ds);
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
CoglTexture *
|
||||
_cogl_atlas_copy_rectangle (CoglAtlas *atlas,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
CoglPixelFormat internal_format)
|
||||
{
|
||||
CoglTexture *tex;
|
||||
CoglBlitData blit_data;
|
||||
CoglError *ignore_error = NULL;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
/* Create a new texture at the right size */
|
||||
tex = create_migration_texture (ctx, width, height, internal_format);
|
||||
if (!cogl_texture_allocate (tex, &ignore_error))
|
||||
{
|
||||
cogl_error_free (ignore_error);
|
||||
cogl_object_unref (tex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Blit the data out of the atlas to the new texture. If FBOs
|
||||
aren't available this will end up having to copy the entire
|
||||
atlas texture */
|
||||
_cogl_blit_begin (&blit_data, tex, atlas->texture);
|
||||
_cogl_blit (&blit_data,
|
||||
x, y,
|
||||
0, 0,
|
||||
width, height);
|
||||
_cogl_blit_end (&blit_data);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_atlas_add_reorganize_callback (CoglAtlas *atlas,
|
||||
GHookFunc pre_callback,
|
||||
GHookFunc post_callback,
|
||||
void *user_data)
|
||||
{
|
||||
if (pre_callback)
|
||||
{
|
||||
GHook *hook = g_hook_alloc (&atlas->post_reorganize_callbacks);
|
||||
hook->func = pre_callback;
|
||||
hook->data = user_data;
|
||||
g_hook_prepend (&atlas->pre_reorganize_callbacks, hook);
|
||||
}
|
||||
if (post_callback)
|
||||
{
|
||||
GHook *hook = g_hook_alloc (&atlas->pre_reorganize_callbacks);
|
||||
hook->func = post_callback;
|
||||
hook->data = user_data;
|
||||
g_hook_prepend (&atlas->post_reorganize_callbacks, hook);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_atlas_remove_reorganize_callback (CoglAtlas *atlas,
|
||||
GHookFunc pre_callback,
|
||||
GHookFunc post_callback,
|
||||
void *user_data)
|
||||
{
|
||||
if (pre_callback)
|
||||
{
|
||||
GHook *hook = g_hook_find_func_data (&atlas->pre_reorganize_callbacks,
|
||||
FALSE,
|
||||
pre_callback,
|
||||
user_data);
|
||||
if (hook)
|
||||
g_hook_destroy_link (&atlas->pre_reorganize_callbacks, hook);
|
||||
}
|
||||
if (post_callback)
|
||||
{
|
||||
GHook *hook = g_hook_find_func_data (&atlas->post_reorganize_callbacks,
|
||||
FALSE,
|
||||
post_callback,
|
||||
user_data);
|
||||
if (hook)
|
||||
g_hook_destroy_link (&atlas->post_reorganize_callbacks, hook);
|
||||
}
|
||||
}
|
105
cogl/cogl/cogl-atlas.h
Normal file
105
cogl/cogl/cogl-atlas.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2010,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.
|
||||
*/
|
||||
|
||||
#ifndef __COGL_ATLAS_H
|
||||
#define __COGL_ATLAS_H
|
||||
|
||||
#include "cogl-rectangle-map.h"
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-texture.h"
|
||||
|
||||
typedef void
|
||||
(* CoglAtlasUpdatePositionCallback) (void *user_data,
|
||||
CoglTexture *new_texture,
|
||||
const CoglRectangleMapEntry *rect);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COGL_ATLAS_CLEAR_TEXTURE = (1 << 0),
|
||||
COGL_ATLAS_DISABLE_MIGRATION = (1 << 1)
|
||||
} CoglAtlasFlags;
|
||||
|
||||
typedef struct _CoglAtlas CoglAtlas;
|
||||
|
||||
#define COGL_ATLAS(object) ((CoglAtlas *) object)
|
||||
|
||||
struct _CoglAtlas
|
||||
{
|
||||
CoglObject _parent;
|
||||
|
||||
CoglRectangleMap *map;
|
||||
|
||||
CoglTexture *texture;
|
||||
CoglPixelFormat texture_format;
|
||||
CoglAtlasFlags flags;
|
||||
|
||||
CoglAtlasUpdatePositionCallback update_position_cb;
|
||||
|
||||
GHookList pre_reorganize_callbacks;
|
||||
GHookList post_reorganize_callbacks;
|
||||
};
|
||||
|
||||
CoglAtlas *
|
||||
_cogl_atlas_new (CoglPixelFormat texture_format,
|
||||
CoglAtlasFlags flags,
|
||||
CoglAtlasUpdatePositionCallback update_position_cb);
|
||||
|
||||
CoglBool
|
||||
_cogl_atlas_reserve_space (CoglAtlas *atlas,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
void *user_data);
|
||||
|
||||
void
|
||||
_cogl_atlas_remove (CoglAtlas *atlas,
|
||||
const CoglRectangleMapEntry *rectangle);
|
||||
|
||||
CoglTexture *
|
||||
_cogl_atlas_copy_rectangle (CoglAtlas *atlas,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
CoglPixelFormat format);
|
||||
|
||||
void
|
||||
_cogl_atlas_add_reorganize_callback (CoglAtlas *atlas,
|
||||
GHookFunc pre_callback,
|
||||
GHookFunc post_callback,
|
||||
void *user_data);
|
||||
|
||||
void
|
||||
_cogl_atlas_remove_reorganize_callback (CoglAtlas *atlas,
|
||||
GHookFunc pre_callback,
|
||||
GHookFunc post_callback,
|
||||
void *user_data);
|
||||
|
||||
CoglBool
|
||||
_cogl_is_atlas (void *object);
|
||||
|
||||
#endif /* __COGL_ATLAS_H */
|
44
cogl/cogl/cogl-attribute-buffer-private.h
Normal file
44
cogl/cogl/cogl-attribute-buffer-private.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __COGL_ATTRIBUTE_BUFFER_PRIVATE_H
|
||||
#define __COGL_ATTRIBUTE_BUFFER_PRIVATE_H
|
||||
|
||||
#include "cogl-buffer-private.h"
|
||||
|
||||
struct _CoglAttributeBuffer
|
||||
{
|
||||
CoglBuffer _parent;
|
||||
};
|
||||
|
||||
#endif /* __COGL_ATTRIBUTE_BUFFER_PRIVATE_H */
|
104
cogl/cogl/cogl-attribute-buffer.c
Normal file
104
cogl/cogl/cogl-attribute-buffer.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-attribute-buffer.h"
|
||||
#include "cogl-attribute-buffer-private.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-gtype-private.h"
|
||||
|
||||
static void _cogl_attribute_buffer_free (CoglAttributeBuffer *array);
|
||||
|
||||
COGL_BUFFER_DEFINE (AttributeBuffer, attribute_buffer);
|
||||
COGL_GTYPE_DEFINE_CLASS (AttributeBuffer, attribute_buffer);
|
||||
|
||||
CoglAttributeBuffer *
|
||||
cogl_attribute_buffer_new_with_size (CoglContext *context,
|
||||
size_t bytes)
|
||||
{
|
||||
CoglAttributeBuffer *buffer = g_slice_new (CoglAttributeBuffer);
|
||||
|
||||
/* parent's constructor */
|
||||
_cogl_buffer_initialize (COGL_BUFFER (buffer),
|
||||
context,
|
||||
bytes,
|
||||
COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER,
|
||||
COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER,
|
||||
COGL_BUFFER_UPDATE_HINT_STATIC);
|
||||
|
||||
return _cogl_attribute_buffer_object_new (buffer);
|
||||
}
|
||||
|
||||
CoglAttributeBuffer *
|
||||
cogl_attribute_buffer_new (CoglContext *context,
|
||||
size_t bytes,
|
||||
const void *data)
|
||||
{
|
||||
CoglAttributeBuffer *buffer;
|
||||
|
||||
buffer = cogl_attribute_buffer_new_with_size (context, bytes);
|
||||
|
||||
/* Note: to keep the common cases simple this API doesn't throw
|
||||
* CoglErrors, so developers can assume this function never returns
|
||||
* NULL and we will simply abort on error.
|
||||
*
|
||||
* Developers wanting to catch errors can use
|
||||
* cogl_attribute_buffer_new_with_size() and catch errors when later
|
||||
* calling cogl_buffer_set_data() or cogl_buffer_map().
|
||||
*/
|
||||
|
||||
/* XXX: NB: for Cogl 2.0 we don't allow NULL data here but we can't
|
||||
* break the api for 1.x and so we keep the check for now. */
|
||||
if (data)
|
||||
_cogl_buffer_set_data (COGL_BUFFER (buffer),
|
||||
0,
|
||||
data,
|
||||
bytes,
|
||||
NULL);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_attribute_buffer_free (CoglAttributeBuffer *array)
|
||||
{
|
||||
/* parent's destructor */
|
||||
_cogl_buffer_fini (COGL_BUFFER (array));
|
||||
|
||||
g_slice_free (CoglAttributeBuffer, array);
|
||||
}
|
||||
|
152
cogl/cogl/cogl-attribute-buffer.h
Normal file
152
cogl/cogl/cogl-attribute-buffer.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_ATTRIBUTE_BUFFER_H__
|
||||
#define __COGL_ATTRIBUTE_BUFFER_H__
|
||||
|
||||
/* We forward declare the CoglAttributeBuffer type here to avoid some circular
|
||||
* dependency issues with the following headers.
|
||||
*/
|
||||
typedef struct _CoglAttributeBuffer CoglAttributeBuffer;
|
||||
|
||||
#include <cogl/cogl-context.h>
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
#include <glib-object.h>
|
||||
#endif
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* SECTION:cogl-attribute-buffer
|
||||
* @short_description: Functions for creating and manipulating attribute
|
||||
* buffers
|
||||
*
|
||||
* FIXME
|
||||
*/
|
||||
|
||||
#define COGL_ATTRIBUTE_BUFFER(buffer) ((CoglAttributeBuffer *)(buffer))
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
/**
|
||||
* cogl_attribute_buffer_get_gtype:
|
||||
*
|
||||
* Returns: a #GType that can be used with the GLib type system.
|
||||
*/
|
||||
GType cogl_attribute_buffer_get_gtype (void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cogl_attribute_buffer_new_with_size:
|
||||
* @context: A #CoglContext
|
||||
* @bytes: The number of bytes to allocate for vertex attribute data.
|
||||
*
|
||||
* Describes a new #CoglAttributeBuffer of @size bytes to contain
|
||||
* arrays of vertex attribute data. Afterwards data can be set using
|
||||
* cogl_buffer_set_data() or by mapping it into the application's
|
||||
* address space using cogl_buffer_map().
|
||||
*
|
||||
* The underlying storage of this buffer isn't allocated by this
|
||||
* function so that you have an opportunity to use the
|
||||
* cogl_buffer_set_update_hint() and cogl_buffer_set_usage_hint()
|
||||
* functions which may influence how the storage is allocated. The
|
||||
* storage will be allocated once you upload data to the buffer.
|
||||
*
|
||||
* Note: You can assume this function always succeeds and won't return
|
||||
* %NULL
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttributeBuffer. Never %NULL.
|
||||
*
|
||||
* Stability: Unstable
|
||||
*/
|
||||
CoglAttributeBuffer *
|
||||
cogl_attribute_buffer_new_with_size (CoglContext *context,
|
||||
size_t bytes);
|
||||
|
||||
/**
|
||||
* cogl_attribute_buffer_new:
|
||||
* @context: A #CoglContext
|
||||
* @bytes: The number of bytes to allocate for vertex attribute data.
|
||||
* @data: (array length=bytes): An optional pointer to vertex data to
|
||||
* upload immediately.
|
||||
*
|
||||
* Describes a new #CoglAttributeBuffer of @size bytes to contain
|
||||
* arrays of vertex attribute data and also uploads @size bytes read
|
||||
* from @data to the new buffer.
|
||||
*
|
||||
* You should never pass a %NULL data pointer.
|
||||
*
|
||||
* <note>This function does not report out-of-memory errors back to
|
||||
* the caller by returning %NULL and so you can assume this function
|
||||
* always succeeds.</note>
|
||||
*
|
||||
* <note>In the unlikely case that there is an out of memory problem
|
||||
* then Cogl will abort the application with a message. If your
|
||||
* application needs to gracefully handle out-of-memory errors then
|
||||
* you can use cogl_attribute_buffer_new_with_size() and then
|
||||
* explicitly catch errors with cogl_buffer_set_data() or
|
||||
* cogl_buffer_map().</note>
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttributeBuffer (never %NULL)
|
||||
*
|
||||
* Since: 1.4
|
||||
* Stability: Unstable
|
||||
*/
|
||||
CoglAttributeBuffer *
|
||||
cogl_attribute_buffer_new (CoglContext *context,
|
||||
size_t bytes,
|
||||
const void *data);
|
||||
|
||||
/**
|
||||
* cogl_is_attribute_buffer:
|
||||
* @object: A #CoglObject
|
||||
*
|
||||
* Gets whether the given object references a #CoglAttributeBuffer.
|
||||
*
|
||||
* Returns: %TRUE if @object references a #CoglAttributeBuffer,
|
||||
* %FALSE otherwise
|
||||
*
|
||||
* Since: 1.4
|
||||
* Stability: Unstable
|
||||
*/
|
||||
CoglBool
|
||||
cogl_is_attribute_buffer (void *object);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_ATTRIBUTE_BUFFER_H__ */
|
||||
|
140
cogl/cogl/cogl-attribute-private.h
Normal file
140
cogl/cogl/cogl-attribute-private.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __COGL_ATTRIBUTE_PRIVATE_H
|
||||
#define __COGL_ATTRIBUTE_PRIVATE_H
|
||||
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-attribute.h"
|
||||
#include "cogl-framebuffer.h"
|
||||
#include "cogl-pipeline-private.h"
|
||||
#include "cogl-boxed-value.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY,
|
||||
COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY,
|
||||
COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY,
|
||||
COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY,
|
||||
COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY,
|
||||
COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY
|
||||
} CoglAttributeNameID;
|
||||
|
||||
typedef struct _CoglAttributeNameState
|
||||
{
|
||||
char *name;
|
||||
CoglAttributeNameID name_id;
|
||||
int name_index;
|
||||
CoglBool normalized_default;
|
||||
int layer_number;
|
||||
} CoglAttributeNameState;
|
||||
|
||||
struct _CoglAttribute
|
||||
{
|
||||
CoglObject _parent;
|
||||
|
||||
const CoglAttributeNameState *name_state;
|
||||
CoglBool normalized;
|
||||
|
||||
CoglBool is_buffered;
|
||||
|
||||
union {
|
||||
struct {
|
||||
CoglAttributeBuffer *attribute_buffer;
|
||||
size_t stride;
|
||||
size_t offset;
|
||||
int n_components;
|
||||
CoglAttributeType type;
|
||||
} buffered;
|
||||
struct {
|
||||
CoglContext *context;
|
||||
CoglBoxedValue boxed;
|
||||
} constant;
|
||||
} d;
|
||||
|
||||
int immutable_ref;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COGL_DRAW_SKIP_JOURNAL_FLUSH = 1 << 0,
|
||||
COGL_DRAW_SKIP_PIPELINE_VALIDATION = 1 << 1,
|
||||
COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH = 1 << 2,
|
||||
COGL_DRAW_SKIP_LEGACY_STATE = 1 << 3,
|
||||
/* By default the vertex attribute drawing code will assume that if
|
||||
there is a color attribute array enabled then we can't determine
|
||||
if the colors will be opaque so we need to enabling
|
||||
blending. However when drawing from the journal we know what the
|
||||
contents of the color array is so we can override this by passing
|
||||
this flag. */
|
||||
COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE = 1 << 4,
|
||||
/* This forcibly disables the debug option to divert all drawing to
|
||||
* wireframes */
|
||||
COGL_DRAW_SKIP_DEBUG_WIREFRAME = 1 << 5
|
||||
} CoglDrawFlags;
|
||||
|
||||
/* During CoglContext initialization we register the "cogl_color_in"
|
||||
* attribute name so it gets a global name_index of 0. We need to know
|
||||
* the name_index for "cogl_color_in" in
|
||||
* _cogl_pipeline_flush_gl_state() */
|
||||
#define COGL_ATTRIBUTE_COLOR_NAME_INDEX 0
|
||||
|
||||
CoglAttributeNameState *
|
||||
_cogl_attribute_register_attribute_name (CoglContext *context,
|
||||
const char *name);
|
||||
|
||||
CoglAttribute *
|
||||
_cogl_attribute_immutable_ref (CoglAttribute *attribute);
|
||||
|
||||
void
|
||||
_cogl_attribute_immutable_unref (CoglAttribute *attribute);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int unit;
|
||||
CoglPipelineFlushOptions options;
|
||||
uint32_t fallback_layers;
|
||||
} CoglFlushLayerState;
|
||||
|
||||
void
|
||||
_cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
CoglDrawFlags flags,
|
||||
CoglAttribute **attributes,
|
||||
int n_attributes);
|
||||
|
||||
int
|
||||
_cogl_attribute_get_n_components (CoglAttribute *attribute);
|
||||
|
||||
#endif /* __COGL_ATTRIBUTE_PRIVATE_H */
|
||||
|
687
cogl/cogl/cogl-attribute.c
Normal file
687
cogl/cogl/cogl-attribute.c
Normal file
@ -0,0 +1,687 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-journal-private.h"
|
||||
#include "cogl-attribute.h"
|
||||
#include "cogl-attribute-private.h"
|
||||
#include "cogl-pipeline.h"
|
||||
#include "cogl-pipeline-private.h"
|
||||
#include "cogl-pipeline-opengl-private.h"
|
||||
#include "cogl-texture-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-indices-private.h"
|
||||
#ifdef COGL_PIPELINE_PROGEND_GLSL
|
||||
#include "cogl-pipeline-progend-glsl-private.h"
|
||||
#endif
|
||||
#include "cogl-private.h"
|
||||
#include "cogl-gtype-private.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* This isn't defined in the GLES headers */
|
||||
#ifndef GL_UNSIGNED_INT
|
||||
#define GL_UNSIGNED_INT 0x1405
|
||||
#endif
|
||||
|
||||
static void _cogl_attribute_free (CoglAttribute *attribute);
|
||||
|
||||
COGL_OBJECT_DEFINE (Attribute, attribute);
|
||||
COGL_GTYPE_DEFINE_CLASS (Attribute, attribute);
|
||||
|
||||
static CoglBool
|
||||
validate_cogl_attribute_name (const char *name,
|
||||
char **real_attribute_name,
|
||||
CoglAttributeNameID *name_id,
|
||||
CoglBool *normalized,
|
||||
int *layer_number)
|
||||
{
|
||||
name = name + 5; /* skip "cogl_" */
|
||||
|
||||
*normalized = FALSE;
|
||||
*layer_number = 0;
|
||||
|
||||
if (strcmp (name, "position_in") == 0)
|
||||
*name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
|
||||
else if (strcmp (name, "color_in") == 0)
|
||||
{
|
||||
*name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
|
||||
*normalized = TRUE;
|
||||
}
|
||||
else if (strcmp (name, "tex_coord_in") == 0)
|
||||
{
|
||||
*real_attribute_name = "cogl_tex_coord0_in";
|
||||
*name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
|
||||
}
|
||||
else if (strncmp (name, "tex_coord", strlen ("tex_coord")) == 0)
|
||||
{
|
||||
char *endptr;
|
||||
*layer_number = strtoul (name + 9, &endptr, 10);
|
||||
if (strcmp (endptr, "_in") != 0)
|
||||
{
|
||||
g_warning ("Texture coordinate attributes should either be named "
|
||||
"\"cogl_tex_coord_in\" or named with a texture unit index "
|
||||
"like \"cogl_tex_coord2_in\"\n");
|
||||
return FALSE;
|
||||
}
|
||||
*name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
|
||||
}
|
||||
else if (strcmp (name, "normal_in") == 0)
|
||||
{
|
||||
*name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
|
||||
*normalized = TRUE;
|
||||
}
|
||||
else if (strcmp (name, "point_size_in") == 0)
|
||||
*name_id = COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY;
|
||||
else
|
||||
{
|
||||
g_warning ("Unknown cogl_* attribute name cogl_%s\n", name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CoglAttributeNameState *
|
||||
_cogl_attribute_register_attribute_name (CoglContext *context,
|
||||
const char *name)
|
||||
{
|
||||
CoglAttributeNameState *name_state = g_new (CoglAttributeNameState, 1);
|
||||
int name_index = context->n_attribute_names++;
|
||||
char *name_copy = g_strdup (name);
|
||||
|
||||
name_state->name = NULL;
|
||||
name_state->name_index = name_index;
|
||||
if (strncmp (name, "cogl_", 5) == 0)
|
||||
{
|
||||
if (!validate_cogl_attribute_name (name,
|
||||
&name_state->name,
|
||||
&name_state->name_id,
|
||||
&name_state->normalized_default,
|
||||
&name_state->layer_number))
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
name_state->name_id = COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY;
|
||||
name_state->normalized_default = FALSE;
|
||||
name_state->layer_number = 0;
|
||||
}
|
||||
|
||||
if (name_state->name == NULL)
|
||||
name_state->name = name_copy;
|
||||
|
||||
g_hash_table_insert (context->attribute_name_states_hash,
|
||||
name_copy, name_state);
|
||||
|
||||
if (G_UNLIKELY (context->attribute_name_index_map == NULL))
|
||||
context->attribute_name_index_map =
|
||||
g_array_new (FALSE, FALSE, sizeof (void *));
|
||||
|
||||
g_array_set_size (context->attribute_name_index_map, name_index + 1);
|
||||
|
||||
g_array_index (context->attribute_name_index_map,
|
||||
CoglAttributeNameState *, name_index) = name_state;
|
||||
|
||||
return name_state;
|
||||
|
||||
error:
|
||||
g_free (name_state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
validate_n_components (const CoglAttributeNameState *name_state,
|
||||
int n_components)
|
||||
{
|
||||
switch (name_state->name_id)
|
||||
{
|
||||
case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
|
||||
if (G_UNLIKELY (n_components == 1))
|
||||
{
|
||||
g_critical ("glVertexPointer doesn't allow 1 component vertex "
|
||||
"positions so we currently only support \"cogl_vertex\" "
|
||||
"attributes where n_components == 2, 3 or 4");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
|
||||
if (G_UNLIKELY (n_components != 3 && n_components != 4))
|
||||
{
|
||||
g_critical ("glColorPointer expects 3 or 4 component colors so we "
|
||||
"currently only support \"cogl_color\" attributes where "
|
||||
"n_components == 3 or 4");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
|
||||
break;
|
||||
case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
|
||||
if (G_UNLIKELY (n_components != 3))
|
||||
{
|
||||
g_critical ("glNormalPointer expects 3 component normals so we "
|
||||
"currently only support \"cogl_normal\" attributes "
|
||||
"where n_components == 3");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY:
|
||||
if (G_UNLIKELY (n_components != 1))
|
||||
{
|
||||
g_critical ("The point size attribute can only have one "
|
||||
"component");
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
|
||||
const char *name,
|
||||
size_t stride,
|
||||
size_t offset,
|
||||
int n_components,
|
||||
CoglAttributeType type)
|
||||
{
|
||||
CoglAttribute *attribute = g_slice_new (CoglAttribute);
|
||||
CoglBuffer *buffer = COGL_BUFFER (attribute_buffer);
|
||||
CoglContext *ctx = buffer->context;
|
||||
|
||||
attribute->is_buffered = TRUE;
|
||||
|
||||
attribute->name_state =
|
||||
g_hash_table_lookup (ctx->attribute_name_states_hash, name);
|
||||
if (!attribute->name_state)
|
||||
{
|
||||
CoglAttributeNameState *name_state =
|
||||
_cogl_attribute_register_attribute_name (ctx, name);
|
||||
if (!name_state)
|
||||
goto error;
|
||||
attribute->name_state = name_state;
|
||||
}
|
||||
|
||||
attribute->d.buffered.attribute_buffer = cogl_object_ref (attribute_buffer);
|
||||
attribute->d.buffered.stride = stride;
|
||||
attribute->d.buffered.offset = offset;
|
||||
attribute->d.buffered.n_components = n_components;
|
||||
attribute->d.buffered.type = type;
|
||||
|
||||
attribute->immutable_ref = 0;
|
||||
|
||||
if (attribute->name_state->name_id != COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY)
|
||||
{
|
||||
if (!validate_n_components (attribute->name_state, n_components))
|
||||
return NULL;
|
||||
attribute->normalized =
|
||||
attribute->name_state->normalized_default;
|
||||
}
|
||||
else
|
||||
attribute->normalized = FALSE;
|
||||
|
||||
return _cogl_attribute_object_new (attribute);
|
||||
|
||||
error:
|
||||
_cogl_attribute_free (attribute);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CoglAttribute *
|
||||
_cogl_attribute_new_const (CoglContext *context,
|
||||
const char *name,
|
||||
int n_components,
|
||||
int n_columns,
|
||||
CoglBool transpose,
|
||||
const float *value)
|
||||
{
|
||||
CoglAttribute *attribute = g_slice_new (CoglAttribute);
|
||||
|
||||
attribute->name_state =
|
||||
g_hash_table_lookup (context->attribute_name_states_hash, name);
|
||||
if (!attribute->name_state)
|
||||
{
|
||||
CoglAttributeNameState *name_state =
|
||||
_cogl_attribute_register_attribute_name (context, name);
|
||||
if (!name_state)
|
||||
goto error;
|
||||
attribute->name_state = name_state;
|
||||
}
|
||||
|
||||
if (!validate_n_components (attribute->name_state, n_components))
|
||||
goto error;
|
||||
|
||||
attribute->is_buffered = FALSE;
|
||||
attribute->normalized = FALSE;
|
||||
|
||||
attribute->d.constant.context = cogl_object_ref (context);
|
||||
|
||||
attribute->d.constant.boxed.v.array = NULL;
|
||||
|
||||
if (n_columns == 1)
|
||||
{
|
||||
_cogl_boxed_value_set_float (&attribute->d.constant.boxed,
|
||||
n_components,
|
||||
1,
|
||||
value);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Up until GL[ES] 3 only square matrices were supported
|
||||
* and we don't currently expose non-square matrices in Cogl.
|
||||
*/
|
||||
_COGL_RETURN_VAL_IF_FAIL (n_columns == n_components, NULL);
|
||||
_cogl_boxed_value_set_matrix (&attribute->d.constant.boxed,
|
||||
n_columns,
|
||||
1,
|
||||
transpose,
|
||||
value);
|
||||
}
|
||||
|
||||
return _cogl_attribute_object_new (attribute);
|
||||
|
||||
error:
|
||||
_cogl_attribute_free (attribute);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_1f (CoglContext *context,
|
||||
const char *name,
|
||||
float value)
|
||||
{
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
1, /* n_components */
|
||||
1, /* 1 column vector */
|
||||
FALSE, /* no transpose */
|
||||
&value);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_2fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *value)
|
||||
{
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
2, /* n_components */
|
||||
1, /* 1 column vector */
|
||||
FALSE, /* no transpose */
|
||||
value);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_3fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *value)
|
||||
{
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
3, /* n_components */
|
||||
1, /* 1 column vector */
|
||||
FALSE, /* no transpose */
|
||||
value);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_4fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *value)
|
||||
{
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
4, /* n_components */
|
||||
1, /* 1 column vector */
|
||||
FALSE, /* no transpose */
|
||||
value);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_2f (CoglContext *context,
|
||||
const char *name,
|
||||
float component0,
|
||||
float component1)
|
||||
{
|
||||
float vec2[2] = { component0, component1 };
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
2, /* n_components */
|
||||
1, /* 1 column vector */
|
||||
FALSE, /* no transpose */
|
||||
vec2);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_3f (CoglContext *context,
|
||||
const char *name,
|
||||
float component0,
|
||||
float component1,
|
||||
float component2)
|
||||
{
|
||||
float vec3[3] = { component0, component1, component2 };
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
3, /* n_components */
|
||||
1, /* 1 column vector */
|
||||
FALSE, /* no transpose */
|
||||
vec3);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_4f (CoglContext *context,
|
||||
const char *name,
|
||||
float component0,
|
||||
float component1,
|
||||
float component2,
|
||||
float component3)
|
||||
{
|
||||
float vec4[4] = { component0, component1, component2, component3 };
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
4, /* n_components */
|
||||
1, /* 1 column vector */
|
||||
FALSE, /* no transpose */
|
||||
vec4);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_2x2fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *matrix2x2,
|
||||
CoglBool transpose)
|
||||
{
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
2, /* n_components */
|
||||
2, /* 2 column vector */
|
||||
FALSE, /* no transpose */
|
||||
matrix2x2);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_3x3fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *matrix3x3,
|
||||
CoglBool transpose)
|
||||
{
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
3, /* n_components */
|
||||
3, /* 3 column vector */
|
||||
FALSE, /* no transpose */
|
||||
matrix3x3);
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_4x4fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *matrix4x4,
|
||||
CoglBool transpose)
|
||||
{
|
||||
return _cogl_attribute_new_const (context,
|
||||
name,
|
||||
4, /* n_components */
|
||||
4, /* 4 column vector */
|
||||
FALSE, /* no transpose */
|
||||
matrix4x4);
|
||||
}
|
||||
|
||||
CoglBool
|
||||
cogl_attribute_get_normalized (CoglAttribute *attribute)
|
||||
{
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), FALSE);
|
||||
|
||||
return attribute->normalized;
|
||||
}
|
||||
|
||||
static void
|
||||
warn_about_midscene_changes (void)
|
||||
{
|
||||
static CoglBool seen = FALSE;
|
||||
if (!seen)
|
||||
{
|
||||
g_warning ("Mid-scene modification of attributes has "
|
||||
"undefined results\n");
|
||||
seen = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cogl_attribute_set_normalized (CoglAttribute *attribute,
|
||||
CoglBool normalized)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
|
||||
|
||||
if (G_UNLIKELY (attribute->immutable_ref))
|
||||
warn_about_midscene_changes ();
|
||||
|
||||
attribute->normalized = normalized;
|
||||
}
|
||||
|
||||
CoglAttributeBuffer *
|
||||
cogl_attribute_get_buffer (CoglAttribute *attribute)
|
||||
{
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL);
|
||||
_COGL_RETURN_VAL_IF_FAIL (attribute->is_buffered, NULL);
|
||||
|
||||
return attribute->d.buffered.attribute_buffer;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_attribute_set_buffer (CoglAttribute *attribute,
|
||||
CoglAttributeBuffer *attribute_buffer)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
|
||||
_COGL_RETURN_IF_FAIL (attribute->is_buffered);
|
||||
|
||||
if (G_UNLIKELY (attribute->immutable_ref))
|
||||
warn_about_midscene_changes ();
|
||||
|
||||
cogl_object_ref (attribute_buffer);
|
||||
|
||||
cogl_object_unref (attribute->d.buffered.attribute_buffer);
|
||||
attribute->d.buffered.attribute_buffer = attribute_buffer;
|
||||
}
|
||||
|
||||
CoglAttribute *
|
||||
_cogl_attribute_immutable_ref (CoglAttribute *attribute)
|
||||
{
|
||||
CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer);
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL);
|
||||
|
||||
attribute->immutable_ref++;
|
||||
_cogl_buffer_immutable_ref (buffer);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_attribute_immutable_unref (CoglAttribute *attribute)
|
||||
{
|
||||
CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer);
|
||||
|
||||
_COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
|
||||
_COGL_RETURN_IF_FAIL (attribute->immutable_ref > 0);
|
||||
|
||||
attribute->immutable_ref--;
|
||||
_cogl_buffer_immutable_unref (buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_attribute_free (CoglAttribute *attribute)
|
||||
{
|
||||
if (attribute->is_buffered)
|
||||
cogl_object_unref (attribute->d.buffered.attribute_buffer);
|
||||
else
|
||||
_cogl_boxed_value_destroy (&attribute->d.constant.boxed);
|
||||
|
||||
g_slice_free (CoglAttribute, attribute);
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
validate_layer_cb (CoglPipeline *pipeline,
|
||||
int layer_index,
|
||||
void *user_data)
|
||||
{
|
||||
CoglTexture *texture =
|
||||
cogl_pipeline_get_layer_texture (pipeline, layer_index);
|
||||
CoglFlushLayerState *state = user_data;
|
||||
CoglBool status = TRUE;
|
||||
|
||||
/* invalid textures will be handled correctly in
|
||||
* _cogl_pipeline_flush_layers_gl_state */
|
||||
if (texture == NULL)
|
||||
goto validated;
|
||||
|
||||
_cogl_texture_flush_journal_rendering (texture);
|
||||
|
||||
/* Give the texture a chance to know that we're rendering
|
||||
non-quad shaped primitives. If the texture is in an atlas it
|
||||
will be migrated */
|
||||
_cogl_texture_ensure_non_quad_rendering (texture);
|
||||
|
||||
/* We need to ensure the mipmaps are ready before deciding
|
||||
* anything else about the texture because the texture storate
|
||||
* could completely change if it needs to be migrated out of the
|
||||
* atlas and will affect how we validate the layer.
|
||||
*/
|
||||
_cogl_pipeline_pre_paint_for_layer (pipeline, layer_index);
|
||||
|
||||
if (!_cogl_texture_can_hardware_repeat (texture))
|
||||
{
|
||||
g_warning ("Disabling layer %d of the current source material, "
|
||||
"because texturing with the vertex buffer API is not "
|
||||
"currently supported using sliced textures, or textures "
|
||||
"with waste\n", layer_index);
|
||||
|
||||
/* XXX: maybe we can add a mechanism for users to forcibly use
|
||||
* textures with waste where it would be their responsability to use
|
||||
* texture coords in the range [0,1] such that sampling outside isn't
|
||||
* required. We can then use a texture matrix (or a modification of
|
||||
* the users own matrix) to map 1 to the edge of the texture data.
|
||||
*
|
||||
* Potentially, given the same guarantee as above we could also
|
||||
* support a single sliced layer too. We would have to redraw the
|
||||
* vertices once for each layer, each time with a fiddled texture
|
||||
* matrix.
|
||||
*/
|
||||
state->fallback_layers |= (1 << state->unit);
|
||||
state->options.flags |= COGL_PIPELINE_FLUSH_FALLBACK_MASK;
|
||||
}
|
||||
|
||||
validated:
|
||||
state->unit++;
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
|
||||
CoglPipeline *pipeline,
|
||||
CoglDrawFlags flags,
|
||||
CoglAttribute **attributes,
|
||||
int n_attributes)
|
||||
{
|
||||
CoglContext *ctx = framebuffer->context;
|
||||
CoglFlushLayerState layers_state;
|
||||
CoglPipeline *copy = NULL;
|
||||
|
||||
if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
|
||||
_cogl_journal_flush (framebuffer->journal);
|
||||
|
||||
layers_state.unit = 0;
|
||||
layers_state.options.flags = 0;
|
||||
layers_state.fallback_layers = 0;
|
||||
|
||||
if (!(flags & COGL_DRAW_SKIP_PIPELINE_VALIDATION))
|
||||
cogl_pipeline_foreach_layer (pipeline,
|
||||
validate_layer_cb,
|
||||
&layers_state);
|
||||
|
||||
/* NB: _cogl_framebuffer_flush_state may disrupt various state (such
|
||||
* as the pipeline state) when flushing the clip stack, so should
|
||||
* always be done first when preparing to draw. We need to do this
|
||||
* before setting up the array pointers because setting up the clip
|
||||
* stack can cause some drawing which would change the array
|
||||
* pointers. */
|
||||
if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
|
||||
_cogl_framebuffer_flush_state (framebuffer,
|
||||
framebuffer,
|
||||
COGL_FRAMEBUFFER_STATE_ALL);
|
||||
|
||||
/* In cogl_read_pixels we have a fast-path when reading a single
|
||||
* pixel and the scene is just comprised of simple rectangles still
|
||||
* in the journal. For this optimization to work we need to track
|
||||
* when the framebuffer really does get drawn to. */
|
||||
_cogl_framebuffer_mark_mid_scene (framebuffer);
|
||||
_cogl_framebuffer_mark_clear_clip_dirty (framebuffer);
|
||||
|
||||
if (G_UNLIKELY (!(flags & COGL_DRAW_SKIP_LEGACY_STATE)) &&
|
||||
G_UNLIKELY (ctx->legacy_state_set) &&
|
||||
_cogl_get_enable_legacy_state ())
|
||||
{
|
||||
copy = cogl_pipeline_copy (pipeline);
|
||||
pipeline = copy;
|
||||
_cogl_pipeline_apply_legacy_state (pipeline);
|
||||
}
|
||||
|
||||
ctx->driver_vtable->flush_attributes_state (framebuffer,
|
||||
pipeline,
|
||||
&layers_state,
|
||||
flags,
|
||||
attributes,
|
||||
n_attributes);
|
||||
|
||||
if (copy)
|
||||
cogl_object_unref (copy);
|
||||
}
|
||||
|
||||
int
|
||||
_cogl_attribute_get_n_components (CoglAttribute *attribute)
|
||||
{
|
||||
if (attribute->is_buffered)
|
||||
return attribute->d.buffered.n_components;
|
||||
else
|
||||
return attribute->d.constant.boxed.size;
|
||||
}
|
558
cogl/cogl/cogl-attribute.h
Normal file
558
cogl/cogl/cogl-attribute.h
Normal file
@ -0,0 +1,558 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_ATTRIBUTE_H__
|
||||
#define __COGL_ATTRIBUTE_H__
|
||||
|
||||
/* We forward declare the CoglAttribute type here to avoid some circular
|
||||
* dependency issues with the following headers.
|
||||
*/
|
||||
typedef struct _CoglAttribute CoglAttribute;
|
||||
|
||||
#include <cogl/cogl-attribute-buffer.h>
|
||||
#include <cogl/cogl-indices.h>
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
#include <glib-object.h>
|
||||
#endif
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* SECTION:cogl-attribute
|
||||
* @short_description: Functions for declaring and drawing vertex
|
||||
* attributes
|
||||
*
|
||||
* FIXME
|
||||
*/
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
/**
|
||||
* cogl_attribute_get_gtype:
|
||||
*
|
||||
* Returns: a #GType that can be used with the GLib type system.
|
||||
*/
|
||||
GType cogl_attribute_get_gtype (void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cogl_attribute_new: (constructor)
|
||||
* @attribute_buffer: The #CoglAttributeBuffer containing the actual
|
||||
* attribute data
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @stride: The number of bytes to jump to get to the next attribute
|
||||
* value for the next vertex. (Usually
|
||||
* <literal>sizeof (MyVertex)</literal>)
|
||||
* @offset: The byte offset from the start of @attribute_buffer for
|
||||
* the first attribute value. (Usually
|
||||
* <literal>offsetof (MyVertex, component0)</literal>
|
||||
* @components: The number of components (e.g. 4 for an rgba color or
|
||||
* 3 for and (x,y,z) position)
|
||||
* @type: FIXME
|
||||
*
|
||||
* Describes the layout for a list of vertex attribute values (For
|
||||
* example, a list of texture coordinates or colors).
|
||||
*
|
||||
* The @name is used to access the attribute inside a GLSL vertex
|
||||
* shader and there are some special names you should use if they are
|
||||
* applicable:
|
||||
* <itemizedlist>
|
||||
* <listitem>"cogl_position_in" (used for vertex positions)</listitem>
|
||||
* <listitem>"cogl_color_in" (used for vertex colors)</listitem>
|
||||
* <listitem>"cogl_tex_coord0_in", "cogl_tex_coord1", ...
|
||||
* (used for vertex texture coordinates)</listitem>
|
||||
* <listitem>"cogl_normal_in" (used for vertex normals)</listitem>
|
||||
* <listitem>"cogl_point_size_in" (used to set the size of points
|
||||
* per-vertex. Note this can only be used if
|
||||
* %COGL_FEATURE_ID_POINT_SIZE_ATTRIBUTE is advertised and
|
||||
* cogl_pipeline_set_per_vertex_point_size() is called on the pipeline.
|
||||
* </listitem>
|
||||
* </itemizedlist>
|
||||
*
|
||||
* The attribute values corresponding to different vertices can either
|
||||
* be tightly packed or interleaved with other attribute values. For
|
||||
* example it's common to define a structure for a single vertex like:
|
||||
* |[
|
||||
* typedef struct
|
||||
* {
|
||||
* float x, y, z; /<!-- -->* position attribute *<!-- -->/
|
||||
* float s, t; /<!-- -->* texture coordinate attribute *<!-- -->/
|
||||
* } MyVertex;
|
||||
* ]|
|
||||
*
|
||||
* And then create an array of vertex data something like:
|
||||
* |[
|
||||
* MyVertex vertices[100] = { .... }
|
||||
* ]|
|
||||
*
|
||||
* In this case, to describe either the position or texture coordinate
|
||||
* attribute you have to move <literal>sizeof (MyVertex)</literal> bytes to
|
||||
* move from one vertex to the next. This is called the attribute
|
||||
* @stride. If you weren't interleving attributes and you instead had
|
||||
* a packed array of float x, y pairs then the attribute stride would
|
||||
* be <literal>(2 * sizeof (float))</literal>. So the @stride is the number of
|
||||
* bytes to move to find the attribute value of the next vertex.
|
||||
*
|
||||
* Normally a list of attributes starts at the beginning of an array.
|
||||
* So for the <literal>MyVertex</literal> example above the @offset is the
|
||||
* offset inside the <literal>MyVertex</literal> structure to the first
|
||||
* component of the attribute. For the texture coordinate attribute
|
||||
* the offset would be <literal>offsetof (MyVertex, s)</literal> or instead of
|
||||
* using the offsetof macro you could use <literal>sizeof (float) *
|
||||
* 3</literal>. If you've divided your @array into blocks of non-interleved
|
||||
* attributes then you will need to calculate the @offset as the number of
|
||||
* bytes in blocks preceding the attribute you're describing.
|
||||
*
|
||||
* An attribute often has more than one component. For example a color
|
||||
* is often comprised of 4 red, green, blue and alpha @components, and a
|
||||
* position may be comprised of 2 x and y @components. You should aim
|
||||
* to keep the number of components to a minimum as more components
|
||||
* means more data needs to be mapped into the GPU which can be a
|
||||
* bottlneck when dealing with a large number of vertices.
|
||||
*
|
||||
* Finally you need to specify the component data type. Here you
|
||||
* should aim to use the smallest type that meets your precision
|
||||
* requirements. Again the larger the type then more data needs to be
|
||||
* mapped into the GPU which can be a bottlneck when dealing with
|
||||
* a large number of vertices.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* describing the layout for a list of attribute values
|
||||
* stored in @array.
|
||||
*
|
||||
* Since: 1.4
|
||||
* Stability: Unstable
|
||||
*/
|
||||
/* XXX: look for a precedent to see if the stride/offset args should
|
||||
* have a different order. */
|
||||
CoglAttribute *
|
||||
cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
|
||||
const char *name,
|
||||
size_t stride,
|
||||
size_t offset,
|
||||
int components,
|
||||
CoglAttributeType type);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_1f:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @value: The constant value for the attribute
|
||||
*
|
||||
* Creates a new, single component, attribute whose value remains
|
||||
* constant across all the vertices of a primitive without needing to
|
||||
* duplicate the value for each vertex.
|
||||
*
|
||||
* The constant @value is a single precision floating point scalar
|
||||
* which should have a corresponding declaration in GLSL code like:
|
||||
*
|
||||
* [|
|
||||
* attribute float name;
|
||||
* |]
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant @value.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_1f (CoglContext *context,
|
||||
const char *name,
|
||||
float value);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_2f:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @component0: The first component of a 2 component vector
|
||||
* @component1: The second component of a 2 component vector
|
||||
*
|
||||
* Creates a new, 2 component, attribute whose value remains
|
||||
* constant across all the vertices of a primitive without needing to
|
||||
* duplicate the value for each vertex.
|
||||
*
|
||||
* The constants (@component0, @component1) represent a 2 component
|
||||
* float vector which should have a corresponding declaration in GLSL
|
||||
* code like:
|
||||
*
|
||||
* [|
|
||||
* attribute vec2 name;
|
||||
* |]
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant vector.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_2f (CoglContext *context,
|
||||
const char *name,
|
||||
float component0,
|
||||
float component1);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_3f:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @component0: The first component of a 3 component vector
|
||||
* @component1: The second component of a 3 component vector
|
||||
* @component2: The third component of a 3 component vector
|
||||
*
|
||||
* Creates a new, 3 component, attribute whose value remains
|
||||
* constant across all the vertices of a primitive without needing to
|
||||
* duplicate the value for each vertex.
|
||||
*
|
||||
* The constants (@component0, @component1, @component2) represent a 3
|
||||
* component float vector which should have a corresponding
|
||||
* declaration in GLSL code like:
|
||||
*
|
||||
* [|
|
||||
* attribute vec3 name;
|
||||
* |]
|
||||
*
|
||||
* unless the built in name "cogl_normal_in" is being used where no
|
||||
* explicit GLSL declaration need be made.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant vector.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_3f (CoglContext *context,
|
||||
const char *name,
|
||||
float component0,
|
||||
float component1,
|
||||
float component2);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_4f:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @component0: The first component of a 4 component vector
|
||||
* @component1: The second component of a 4 component vector
|
||||
* @component2: The third component of a 4 component vector
|
||||
* @component3: The fourth component of a 4 component vector
|
||||
*
|
||||
* Creates a new, 4 component, attribute whose value remains
|
||||
* constant across all the vertices of a primitive without needing to
|
||||
* duplicate the value for each vertex.
|
||||
*
|
||||
* The constants (@component0, @component1, @component2, @constant3)
|
||||
* represent a 4 component float vector which should have a
|
||||
* corresponding declaration in GLSL code like:
|
||||
*
|
||||
* [|
|
||||
* attribute vec4 name;
|
||||
* |]
|
||||
*
|
||||
* unless one of the built in names "cogl_color_in",
|
||||
* "cogl_tex_coord0_in or "cogl_tex_coord1_in" etc is being used where
|
||||
* no explicit GLSL declaration need be made.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant vector.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_4f (CoglContext *context,
|
||||
const char *name,
|
||||
float component0,
|
||||
float component1,
|
||||
float component2,
|
||||
float component3);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_2fv:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @value: A pointer to a 2 component float vector
|
||||
*
|
||||
* Creates a new, 2 component, attribute whose value remains
|
||||
* constant across all the vertices of a primitive without needing to
|
||||
* duplicate the value for each vertex.
|
||||
*
|
||||
* The constants (value[0], value[1]) represent a 2 component float
|
||||
* vector which should have a corresponding declaration in GLSL code
|
||||
* like:
|
||||
*
|
||||
* [|
|
||||
* attribute vec2 name;
|
||||
* |]
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant vector.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_2fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *value);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_3fv:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @value: A pointer to a 3 component float vector
|
||||
*
|
||||
* Creates a new, 3 component, attribute whose value remains
|
||||
* constant across all the vertices of a primitive without needing to
|
||||
* duplicate the value for each vertex.
|
||||
*
|
||||
* The constants (value[0], value[1], value[2]) represent a 3
|
||||
* component float vector which should have a corresponding
|
||||
* declaration in GLSL code like:
|
||||
*
|
||||
* [|
|
||||
* attribute vec3 name;
|
||||
* |]
|
||||
*
|
||||
* unless the built in name "cogl_normal_in" is being used where no
|
||||
* explicit GLSL declaration need be made.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant vector.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_3fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *value);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_4fv:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @value: A pointer to a 4 component float vector
|
||||
*
|
||||
* Creates a new, 4 component, attribute whose value remains
|
||||
* constant across all the vertices of a primitive without needing to
|
||||
* duplicate the value for each vertex.
|
||||
*
|
||||
* The constants (value[0], value[1], value[2], value[3]) represent a
|
||||
* 4 component float vector which should have a corresponding
|
||||
* declaration in GLSL code like:
|
||||
*
|
||||
* [|
|
||||
* attribute vec4 name;
|
||||
* |]
|
||||
*
|
||||
* unless one of the built in names "cogl_color_in",
|
||||
* "cogl_tex_coord0_in or "cogl_tex_coord1_in" etc is being used where
|
||||
* no explicit GLSL declaration need be made.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant vector.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_4fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *value);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_2x2fv:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @matrix2x2: A pointer to a 2 by 2 matrix
|
||||
* @transpose: Whether the matrix should be transposed on upload or
|
||||
* not
|
||||
*
|
||||
* Creates a new matrix attribute whose value remains constant
|
||||
* across all the vertices of a primitive without needing to duplicate
|
||||
* the value for each vertex.
|
||||
*
|
||||
* @matrix2x2 represent a square 2 by 2 matrix specified in
|
||||
* column-major order (each pair of consecutive numbers represents a
|
||||
* column) which should have a corresponding declaration in GLSL code
|
||||
* like:
|
||||
*
|
||||
* [|
|
||||
* attribute mat2 name;
|
||||
* |]
|
||||
*
|
||||
* If @transpose is %TRUE then all matrix components are rotated
|
||||
* around the diagonal of the matrix such that the first column
|
||||
* becomes the first row and the second column becomes the second row.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant matrix.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_2x2fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *matrix2x2,
|
||||
CoglBool transpose);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_3x3fv:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @matrix3x3: A pointer to a 3 by 3 matrix
|
||||
* @transpose: Whether the matrix should be transposed on upload or
|
||||
* not
|
||||
*
|
||||
* Creates a new matrix attribute whose value remains constant
|
||||
* across all the vertices of a primitive without needing to duplicate
|
||||
* the value for each vertex.
|
||||
*
|
||||
* @matrix3x3 represent a square 3 by 3 matrix specified in
|
||||
* column-major order (each triple of consecutive numbers represents a
|
||||
* column) which should have a corresponding declaration in GLSL code
|
||||
* like:
|
||||
*
|
||||
* [|
|
||||
* attribute mat3 name;
|
||||
* |]
|
||||
*
|
||||
* If @transpose is %TRUE then all matrix components are rotated
|
||||
* around the diagonal of the matrix such that the first column
|
||||
* becomes the first row and the second column becomes the second row
|
||||
* etc.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant matrix.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_3x3fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *matrix3x3,
|
||||
CoglBool transpose);
|
||||
|
||||
/**
|
||||
* cogl_attribute_new_const_4x4fv:
|
||||
* @context: A #CoglContext
|
||||
* @name: The name of the attribute (used to reference it from GLSL)
|
||||
* @matrix4x4: A pointer to a 4 by 4 matrix
|
||||
* @transpose: Whether the matrix should be transposed on upload or
|
||||
* not
|
||||
*
|
||||
* Creates a new matrix attribute whose value remains constant
|
||||
* across all the vertices of a primitive without needing to duplicate
|
||||
* the value for each vertex.
|
||||
*
|
||||
* @matrix4x4 represent a square 4 by 4 matrix specified in
|
||||
* column-major order (each 4-tuple of consecutive numbers represents a
|
||||
* column) which should have a corresponding declaration in GLSL code
|
||||
* like:
|
||||
*
|
||||
* [|
|
||||
* attribute mat4 name;
|
||||
* |]
|
||||
*
|
||||
* If @transpose is %TRUE then all matrix components are rotated
|
||||
* around the diagonal of the matrix such that the first column
|
||||
* becomes the first row and the second column becomes the second row
|
||||
* etc.
|
||||
*
|
||||
* Return value: (transfer full): A newly allocated #CoglAttribute
|
||||
* representing the given constant matrix.
|
||||
*/
|
||||
CoglAttribute *
|
||||
cogl_attribute_new_const_4x4fv (CoglContext *context,
|
||||
const char *name,
|
||||
const float *matrix4x4,
|
||||
CoglBool transpose);
|
||||
|
||||
/**
|
||||
* cogl_attribute_set_normalized:
|
||||
* @attribute: A #CoglAttribute
|
||||
* @normalized: The new value for the normalized property.
|
||||
*
|
||||
* Sets whether fixed point attribute types are mapped to the range
|
||||
* 0→1. For example when this property is TRUE and a
|
||||
* %COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE type is used then the value 255
|
||||
* will be mapped to 1.0.
|
||||
*
|
||||
* The default value of this property depends on the name of the
|
||||
* attribute. For the builtin properties cogl_color_in and
|
||||
* cogl_normal_in it will default to TRUE and for all other names it
|
||||
* will default to FALSE.
|
||||
*
|
||||
* Stability: unstable
|
||||
* Since: 1.10
|
||||
*/
|
||||
void
|
||||
cogl_attribute_set_normalized (CoglAttribute *attribute,
|
||||
CoglBool normalized);
|
||||
|
||||
/**
|
||||
* cogl_attribute_get_normalized:
|
||||
* @attribute: A #CoglAttribute
|
||||
*
|
||||
* Return value: the value of the normalized property set with
|
||||
* cogl_attribute_set_normalized().
|
||||
*
|
||||
* Stability: unstable
|
||||
* Since: 1.10
|
||||
*/
|
||||
CoglBool
|
||||
cogl_attribute_get_normalized (CoglAttribute *attribute);
|
||||
|
||||
/**
|
||||
* cogl_attribute_get_buffer:
|
||||
* @attribute: A #CoglAttribute
|
||||
*
|
||||
* Return value: (transfer none): the #CoglAttributeBuffer that was
|
||||
* set with cogl_attribute_set_buffer() or cogl_attribute_new().
|
||||
*
|
||||
* Stability: unstable
|
||||
* Since: 1.10
|
||||
*/
|
||||
CoglAttributeBuffer *
|
||||
cogl_attribute_get_buffer (CoglAttribute *attribute);
|
||||
|
||||
/**
|
||||
* cogl_attribute_set_buffer:
|
||||
* @attribute: A #CoglAttribute
|
||||
* @attribute_buffer: A #CoglAttributeBuffer
|
||||
*
|
||||
* Sets a new #CoglAttributeBuffer for the attribute.
|
||||
*
|
||||
* Stability: unstable
|
||||
* Since: 1.10
|
||||
*/
|
||||
void
|
||||
cogl_attribute_set_buffer (CoglAttribute *attribute,
|
||||
CoglAttributeBuffer *attribute_buffer);
|
||||
|
||||
/**
|
||||
* cogl_is_attribute:
|
||||
* @object: A #CoglObject
|
||||
*
|
||||
* Gets whether the given object references a #CoglAttribute.
|
||||
*
|
||||
* Return value: %TRUE if the @object references a #CoglAttribute,
|
||||
* %FALSE otherwise
|
||||
*/
|
||||
CoglBool
|
||||
cogl_is_attribute (void *object);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_ATTRIBUTE_H__ */
|
||||
|
748
cogl/cogl/cogl-bitmap-conversion.c
Normal file
748
cogl/cogl/cogl-bitmap-conversion.c
Normal file
@ -0,0 +1,748 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2007,2008,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 "cogl-private.h"
|
||||
#include "cogl-bitmap-private.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-texture-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define component_type uint8_t
|
||||
#define component_size 8
|
||||
/* We want to specially optimise the packing when we are converting
|
||||
to/from an 8-bit type so that it won't do anything. That way for
|
||||
example if we are just doing a swizzle conversion then the inner
|
||||
loop for the conversion will be really simple */
|
||||
#define UNPACK_BYTE(b) (b)
|
||||
#define PACK_BYTE(b) (b)
|
||||
#include "cogl-bitmap-packing.h"
|
||||
#undef PACK_BYTE
|
||||
#undef UNPACK_BYTE
|
||||
#undef component_type
|
||||
#undef component_size
|
||||
|
||||
#define component_type uint16_t
|
||||
#define component_size 16
|
||||
#define UNPACK_BYTE(b) (((b) * 65535 + 127) / 255)
|
||||
#define PACK_BYTE(b) (((b) * 255 + 32767) / 65535)
|
||||
#include "cogl-bitmap-packing.h"
|
||||
#undef PACK_BYTE
|
||||
#undef UNPACK_BYTE
|
||||
#undef component_type
|
||||
#undef component_size
|
||||
|
||||
/* (Un)Premultiplication */
|
||||
|
||||
inline static void
|
||||
_cogl_unpremult_alpha_0 (uint8_t *dst)
|
||||
{
|
||||
dst[0] = 0;
|
||||
dst[1] = 0;
|
||||
dst[2] = 0;
|
||||
dst[3] = 0;
|
||||
}
|
||||
|
||||
inline static void
|
||||
_cogl_unpremult_alpha_last (uint8_t *dst)
|
||||
{
|
||||
uint8_t alpha = dst[3];
|
||||
|
||||
dst[0] = (dst[0] * 255) / alpha;
|
||||
dst[1] = (dst[1] * 255) / alpha;
|
||||
dst[2] = (dst[2] * 255) / alpha;
|
||||
}
|
||||
|
||||
inline static void
|
||||
_cogl_unpremult_alpha_first (uint8_t *dst)
|
||||
{
|
||||
uint8_t alpha = dst[0];
|
||||
|
||||
dst[1] = (dst[1] * 255) / alpha;
|
||||
dst[2] = (dst[2] * 255) / alpha;
|
||||
dst[3] = (dst[3] * 255) / alpha;
|
||||
}
|
||||
|
||||
/* No division form of floor((c*a + 128)/255) (I first encountered
|
||||
* this in the RENDER implementation in the X server.) Being exact
|
||||
* is important for a == 255 - we want to get exactly c.
|
||||
*/
|
||||
#define MULT(d,a,t) \
|
||||
G_STMT_START { \
|
||||
t = d * a + 128; \
|
||||
d = ((t >> 8) + t) >> 8; \
|
||||
} G_STMT_END
|
||||
|
||||
inline static void
|
||||
_cogl_premult_alpha_last (uint8_t *dst)
|
||||
{
|
||||
uint8_t alpha = dst[3];
|
||||
/* Using a separate temporary per component has given slightly better
|
||||
* code generation with GCC in the past; it shouldn't do any worse in
|
||||
* any case.
|
||||
*/
|
||||
unsigned int t1, t2, t3;
|
||||
MULT(dst[0], alpha, t1);
|
||||
MULT(dst[1], alpha, t2);
|
||||
MULT(dst[2], alpha, t3);
|
||||
}
|
||||
|
||||
inline static void
|
||||
_cogl_premult_alpha_first (uint8_t *dst)
|
||||
{
|
||||
uint8_t alpha = dst[0];
|
||||
unsigned int t1, t2, t3;
|
||||
|
||||
MULT(dst[1], alpha, t1);
|
||||
MULT(dst[2], alpha, t2);
|
||||
MULT(dst[3], alpha, t3);
|
||||
}
|
||||
|
||||
#undef MULT
|
||||
|
||||
/* Use the SSE optimized version to premult four pixels at once when
|
||||
it is available. The same assembler code works for x86 and x86-64
|
||||
because it doesn't refer to any non-SSE registers directly */
|
||||
#if defined(__SSE2__) && defined(__GNUC__) \
|
||||
&& (defined(__x86_64) || defined(__i386))
|
||||
#define COGL_USE_PREMULT_SSE2
|
||||
#endif
|
||||
|
||||
#ifdef COGL_USE_PREMULT_SSE2
|
||||
|
||||
inline static void
|
||||
_cogl_premult_alpha_last_four_pixels_sse2 (uint8_t *p)
|
||||
{
|
||||
/* 8 copies of 128 used below */
|
||||
static const int16_t eight_halves[8] __attribute__ ((aligned (16))) =
|
||||
{ 128, 128, 128, 128, 128, 128, 128, 128 };
|
||||
/* Mask of the rgb components of the four pixels */
|
||||
static const int8_t just_rgb[16] __attribute__ ((aligned (16))) =
|
||||
{ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
|
||||
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00 };
|
||||
/* Each SSE register only holds two pixels because we need to work
|
||||
with 16-bit intermediate values. We still do four pixels by
|
||||
interleaving two registers in the hope that it will pipeline
|
||||
better */
|
||||
asm (/* Load eight_halves into xmm5 for later */
|
||||
"movdqa (%1), %%xmm5\n"
|
||||
/* Clear xmm3 */
|
||||
"pxor %%xmm3, %%xmm3\n"
|
||||
/* Load two pixels from p into the low half of xmm0 */
|
||||
"movlps (%0), %%xmm0\n"
|
||||
/* Load the next set of two pixels from p into the low half of xmm1 */
|
||||
"movlps 8(%0), %%xmm1\n"
|
||||
/* Unpack 8 bytes from the low quad-words in each register to 8
|
||||
16-bit values */
|
||||
"punpcklbw %%xmm3, %%xmm0\n"
|
||||
"punpcklbw %%xmm3, %%xmm1\n"
|
||||
/* Copy alpha values of the first pixel in xmm0 to all
|
||||
components of the first pixel in xmm2 */
|
||||
"pshuflw $255, %%xmm0, %%xmm2\n"
|
||||
/* same for xmm1 and xmm3 */
|
||||
"pshuflw $255, %%xmm1, %%xmm3\n"
|
||||
/* The above also copies the second pixel directly so we now
|
||||
want to replace the RGB components with copies of the alpha
|
||||
components */
|
||||
"pshufhw $255, %%xmm2, %%xmm2\n"
|
||||
"pshufhw $255, %%xmm3, %%xmm3\n"
|
||||
/* Multiply the rgb components by the alpha */
|
||||
"pmullw %%xmm2, %%xmm0\n"
|
||||
"pmullw %%xmm3, %%xmm1\n"
|
||||
/* Add 128 to each component */
|
||||
"paddw %%xmm5, %%xmm0\n"
|
||||
"paddw %%xmm5, %%xmm1\n"
|
||||
/* Copy the results to temporary registers xmm4 and xmm5 */
|
||||
"movdqa %%xmm0, %%xmm4\n"
|
||||
"movdqa %%xmm1, %%xmm5\n"
|
||||
/* Divide the results by 256 */
|
||||
"psrlw $8, %%xmm0\n"
|
||||
"psrlw $8, %%xmm1\n"
|
||||
/* Add the temporaries back in */
|
||||
"paddw %%xmm4, %%xmm0\n"
|
||||
"paddw %%xmm5, %%xmm1\n"
|
||||
/* Divide again */
|
||||
"psrlw $8, %%xmm0\n"
|
||||
"psrlw $8, %%xmm1\n"
|
||||
/* Pack the results back as bytes */
|
||||
"packuswb %%xmm1, %%xmm0\n"
|
||||
/* Load just_rgb into xmm3 for later */
|
||||
"movdqa (%2), %%xmm3\n"
|
||||
/* Reload all four pixels into xmm2 */
|
||||
"movups (%0), %%xmm2\n"
|
||||
/* Mask out the alpha from the results */
|
||||
"andps %%xmm3, %%xmm0\n"
|
||||
/* Mask out the RGB from the original four pixels */
|
||||
"andnps %%xmm2, %%xmm3\n"
|
||||
/* Combine the two to get the right alpha values */
|
||||
"orps %%xmm3, %%xmm0\n"
|
||||
/* Write to memory */
|
||||
"movdqu %%xmm0, (%0)\n"
|
||||
: /* no outputs */
|
||||
: "r" (p), "r" (eight_halves), "r" (just_rgb)
|
||||
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5");
|
||||
}
|
||||
|
||||
#endif /* COGL_USE_PREMULT_SSE2 */
|
||||
|
||||
static void
|
||||
_cogl_bitmap_premult_unpacked_span_8 (uint8_t *data,
|
||||
int width)
|
||||
{
|
||||
#ifdef COGL_USE_PREMULT_SSE2
|
||||
|
||||
/* Process 4 pixels at a time */
|
||||
while (width >= 4)
|
||||
{
|
||||
_cogl_premult_alpha_last_four_pixels_sse2 (data);
|
||||
data += 4 * 4;
|
||||
width -= 4;
|
||||
}
|
||||
|
||||
/* If there are any pixels left we will fall through and
|
||||
handle them below */
|
||||
|
||||
#endif /* COGL_USE_PREMULT_SSE2 */
|
||||
|
||||
while (width-- > 0)
|
||||
{
|
||||
_cogl_premult_alpha_last (data);
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_bitmap_unpremult_unpacked_span_8 (uint8_t *data,
|
||||
int width)
|
||||
{
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
if (data[3] == 0)
|
||||
_cogl_unpremult_alpha_0 (data);
|
||||
else
|
||||
_cogl_unpremult_alpha_last (data);
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_bitmap_unpremult_unpacked_span_16 (uint16_t *data,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t alpha = data[3];
|
||||
|
||||
if (alpha == 0)
|
||||
memset (data, 0, sizeof (uint16_t) * 3);
|
||||
else
|
||||
{
|
||||
data[0] = (data[0] * 65535) / alpha;
|
||||
data[1] = (data[1] * 65535) / alpha;
|
||||
data[2] = (data[2] * 65535) / alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_bitmap_premult_unpacked_span_16 (uint16_t *data,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t alpha = data[3];
|
||||
|
||||
data[0] = (data[0] * alpha) / 65535;
|
||||
data[1] = (data[1] * alpha) / 65535;
|
||||
data[2] = (data[2] * alpha) / 65535;
|
||||
}
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
_cogl_bitmap_can_fast_premult (CoglPixelFormat format)
|
||||
{
|
||||
switch (format & ~COGL_PREMULT_BIT)
|
||||
{
|
||||
case COGL_PIXEL_FORMAT_RGBA_8888:
|
||||
case COGL_PIXEL_FORMAT_BGRA_8888:
|
||||
case COGL_PIXEL_FORMAT_ARGB_8888:
|
||||
case COGL_PIXEL_FORMAT_ABGR_8888:
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
_cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format)
|
||||
{
|
||||
/* If the format is using more than 8 bits per component then we'll
|
||||
unpack into a 16-bit per component buffer instead of 8-bit so we
|
||||
won't lose as much precision. If we ever add support for formats
|
||||
with more than 16 bits for at least one of the components then we
|
||||
should probably do something else here, maybe convert to
|
||||
floats */
|
||||
switch (format)
|
||||
{
|
||||
case COGL_PIXEL_FORMAT_DEPTH_16:
|
||||
case COGL_PIXEL_FORMAT_DEPTH_32:
|
||||
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
|
||||
case COGL_PIXEL_FORMAT_ANY:
|
||||
case COGL_PIXEL_FORMAT_YUV:
|
||||
g_assert_not_reached ();
|
||||
|
||||
case COGL_PIXEL_FORMAT_A_8:
|
||||
case COGL_PIXEL_FORMAT_RG_88:
|
||||
case COGL_PIXEL_FORMAT_RGB_565:
|
||||
case COGL_PIXEL_FORMAT_RGBA_4444:
|
||||
case COGL_PIXEL_FORMAT_RGBA_5551:
|
||||
case COGL_PIXEL_FORMAT_G_8:
|
||||
case COGL_PIXEL_FORMAT_RGB_888:
|
||||
case COGL_PIXEL_FORMAT_BGR_888:
|
||||
case COGL_PIXEL_FORMAT_RGBA_8888:
|
||||
case COGL_PIXEL_FORMAT_BGRA_8888:
|
||||
case COGL_PIXEL_FORMAT_ARGB_8888:
|
||||
case COGL_PIXEL_FORMAT_ABGR_8888:
|
||||
case COGL_PIXEL_FORMAT_RGBA_8888_PRE:
|
||||
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
|
||||
case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
|
||||
case COGL_PIXEL_FORMAT_ABGR_8888_PRE:
|
||||
case COGL_PIXEL_FORMAT_RGBA_4444_PRE:
|
||||
case COGL_PIXEL_FORMAT_RGBA_5551_PRE:
|
||||
return FALSE;
|
||||
|
||||
case COGL_PIXEL_FORMAT_RGBA_1010102:
|
||||
case COGL_PIXEL_FORMAT_BGRA_1010102:
|
||||
case COGL_PIXEL_FORMAT_ARGB_2101010:
|
||||
case COGL_PIXEL_FORMAT_ABGR_2101010:
|
||||
case COGL_PIXEL_FORMAT_RGBA_1010102_PRE:
|
||||
case COGL_PIXEL_FORMAT_BGRA_1010102_PRE:
|
||||
case COGL_PIXEL_FORMAT_ARGB_2101010_PRE:
|
||||
case COGL_PIXEL_FORMAT_ABGR_2101010_PRE:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
|
||||
CoglBitmap *dst_bmp,
|
||||
CoglError **error)
|
||||
{
|
||||
uint8_t *src_data;
|
||||
uint8_t *dst_data;
|
||||
uint8_t *src;
|
||||
uint8_t *dst;
|
||||
void *tmp_row;
|
||||
int src_rowstride;
|
||||
int dst_rowstride;
|
||||
int y;
|
||||
int width, height;
|
||||
CoglPixelFormat src_format;
|
||||
CoglPixelFormat dst_format;
|
||||
CoglBool use_16;
|
||||
CoglBool need_premult;
|
||||
|
||||
src_format = cogl_bitmap_get_format (src_bmp);
|
||||
src_rowstride = cogl_bitmap_get_rowstride (src_bmp);
|
||||
dst_format = cogl_bitmap_get_format (dst_bmp);
|
||||
dst_rowstride = cogl_bitmap_get_rowstride (dst_bmp);
|
||||
width = cogl_bitmap_get_width (src_bmp);
|
||||
height = cogl_bitmap_get_height (src_bmp);
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (width == cogl_bitmap_get_width (dst_bmp), FALSE);
|
||||
_COGL_RETURN_VAL_IF_FAIL (height == cogl_bitmap_get_height (dst_bmp), FALSE);
|
||||
|
||||
need_premult
|
||||
= ((src_format & COGL_PREMULT_BIT) != (dst_format & COGL_PREMULT_BIT) &&
|
||||
src_format != COGL_PIXEL_FORMAT_A_8 &&
|
||||
dst_format != COGL_PIXEL_FORMAT_A_8 &&
|
||||
(src_format & dst_format & COGL_A_BIT));
|
||||
|
||||
/* If the base format is the same then we can just copy the bitmap
|
||||
instead */
|
||||
if ((src_format & ~COGL_PREMULT_BIT) == (dst_format & ~COGL_PREMULT_BIT) &&
|
||||
(!need_premult || _cogl_bitmap_can_fast_premult (dst_format)))
|
||||
{
|
||||
if (!_cogl_bitmap_copy_subregion (src_bmp, dst_bmp,
|
||||
0, 0, /* src_x / src_y */
|
||||
0, 0, /* dst_x / dst_y */
|
||||
width, height,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
if (need_premult)
|
||||
{
|
||||
if ((dst_format & COGL_PREMULT_BIT))
|
||||
{
|
||||
if (!_cogl_bitmap_premult (dst_bmp, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_cogl_bitmap_unpremult (dst_bmp, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
src_data = _cogl_bitmap_map (src_bmp, COGL_BUFFER_ACCESS_READ, 0, error);
|
||||
if (src_data == NULL)
|
||||
return FALSE;
|
||||
dst_data = _cogl_bitmap_map (dst_bmp,
|
||||
COGL_BUFFER_ACCESS_WRITE,
|
||||
COGL_BUFFER_MAP_HINT_DISCARD,
|
||||
error);
|
||||
if (dst_data == NULL)
|
||||
{
|
||||
_cogl_bitmap_unmap (src_bmp);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
use_16 = _cogl_bitmap_needs_short_temp_buffer (dst_format);
|
||||
|
||||
/* Allocate a buffer to hold a temporary RGBA row */
|
||||
tmp_row = g_malloc (width *
|
||||
(use_16 ? sizeof (uint16_t) : sizeof (uint8_t)) * 4);
|
||||
|
||||
/* FIXME: Optimize */
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src = src_data + y * src_rowstride;
|
||||
dst = dst_data + y * dst_rowstride;
|
||||
|
||||
if (use_16)
|
||||
_cogl_unpack_16 (src_format, src, tmp_row, width);
|
||||
else
|
||||
_cogl_unpack_8 (src_format, src, tmp_row, width);
|
||||
|
||||
/* Handle premultiplication */
|
||||
if (need_premult)
|
||||
{
|
||||
if (dst_format & COGL_PREMULT_BIT)
|
||||
{
|
||||
if (use_16)
|
||||
_cogl_bitmap_premult_unpacked_span_16 (tmp_row, width);
|
||||
else
|
||||
_cogl_bitmap_premult_unpacked_span_8 (tmp_row, width);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (use_16)
|
||||
_cogl_bitmap_unpremult_unpacked_span_16 (tmp_row, width);
|
||||
else
|
||||
_cogl_bitmap_unpremult_unpacked_span_8 (tmp_row, width);
|
||||
}
|
||||
}
|
||||
|
||||
if (use_16)
|
||||
_cogl_pack_16 (dst_format, tmp_row, dst, width);
|
||||
else
|
||||
_cogl_pack_8 (dst_format, tmp_row, dst, width);
|
||||
}
|
||||
|
||||
_cogl_bitmap_unmap (src_bmp);
|
||||
_cogl_bitmap_unmap (dst_bmp);
|
||||
|
||||
g_free (tmp_row);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_convert (CoglBitmap *src_bmp,
|
||||
CoglPixelFormat dst_format,
|
||||
CoglError **error)
|
||||
{
|
||||
CoglBitmap *dst_bmp;
|
||||
int width, height;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
width = cogl_bitmap_get_width (src_bmp);
|
||||
height = cogl_bitmap_get_height (src_bmp);
|
||||
|
||||
dst_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
|
||||
width, height,
|
||||
dst_format,
|
||||
error);
|
||||
if (!dst_bmp)
|
||||
return NULL;
|
||||
|
||||
if (!_cogl_bitmap_convert_into_bitmap (src_bmp, dst_bmp, error))
|
||||
{
|
||||
cogl_object_unref (dst_bmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dst_bmp;
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
driver_can_convert (CoglContext *ctx,
|
||||
CoglPixelFormat src_format,
|
||||
CoglPixelFormat internal_format)
|
||||
{
|
||||
if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_FORMAT_CONVERSION))
|
||||
return FALSE;
|
||||
|
||||
if (src_format == internal_format)
|
||||
return TRUE;
|
||||
|
||||
/* If the driver doesn't natively support alpha textures then it
|
||||
* won't work correctly to convert to/from component-alpha
|
||||
* textures */
|
||||
if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) &&
|
||||
(src_format == COGL_PIXEL_FORMAT_A_8 ||
|
||||
internal_format == COGL_PIXEL_FORMAT_A_8))
|
||||
return FALSE;
|
||||
|
||||
/* Same for red-green textures. If red-green textures aren't
|
||||
* supported then the internal format should never be RG_88 but we
|
||||
* should still be able to convert from an RG source image */
|
||||
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RG) &&
|
||||
src_format == COGL_PIXEL_FORMAT_RG_88)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp,
|
||||
CoglPixelFormat internal_format,
|
||||
CoglBool can_convert_in_place,
|
||||
CoglError **error)
|
||||
{
|
||||
CoglContext *ctx = _cogl_bitmap_get_context (src_bmp);
|
||||
CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp);
|
||||
CoglBitmap *dst_bmp;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (internal_format != COGL_PIXEL_FORMAT_ANY, NULL);
|
||||
|
||||
/* OpenGL supports specifying a different format for the internal
|
||||
format when uploading texture data. We should use this to convert
|
||||
formats because it is likely to be faster and support more types
|
||||
than the Cogl bitmap code. However under GLES the internal format
|
||||
must be the same as the bitmap format and it only supports a
|
||||
limited number of formats so we must convert using the Cogl
|
||||
bitmap code instead */
|
||||
|
||||
if (driver_can_convert (ctx, src_format, internal_format))
|
||||
{
|
||||
/* If the source format does not have the same premult flag as the
|
||||
internal_format then we need to copy and convert it */
|
||||
if (_cogl_texture_needs_premult_conversion (src_format,
|
||||
internal_format))
|
||||
{
|
||||
if (can_convert_in_place)
|
||||
{
|
||||
if (_cogl_bitmap_convert_premult_status (src_bmp,
|
||||
(src_format ^
|
||||
COGL_PREMULT_BIT),
|
||||
error))
|
||||
{
|
||||
dst_bmp = cogl_object_ref (src_bmp);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_bmp = _cogl_bitmap_convert (src_bmp,
|
||||
src_format ^ COGL_PREMULT_BIT,
|
||||
error);
|
||||
if (dst_bmp == NULL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
dst_bmp = cogl_object_ref (src_bmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
CoglPixelFormat closest_format;
|
||||
|
||||
closest_format =
|
||||
ctx->driver_vtable->pixel_format_to_gl (ctx,
|
||||
internal_format,
|
||||
NULL, /* ignore gl intformat */
|
||||
NULL, /* ignore gl format */
|
||||
NULL); /* ignore gl type */
|
||||
|
||||
if (closest_format != src_format)
|
||||
dst_bmp = _cogl_bitmap_convert (src_bmp, closest_format, error);
|
||||
else
|
||||
dst_bmp = cogl_object_ref (src_bmp);
|
||||
}
|
||||
|
||||
return dst_bmp;
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_unpremult (CoglBitmap *bmp,
|
||||
CoglError **error)
|
||||
{
|
||||
uint8_t *p, *data;
|
||||
uint16_t *tmp_row;
|
||||
int x,y;
|
||||
CoglPixelFormat format;
|
||||
int width, height;
|
||||
int rowstride;
|
||||
|
||||
format = cogl_bitmap_get_format (bmp);
|
||||
width = cogl_bitmap_get_width (bmp);
|
||||
height = cogl_bitmap_get_height (bmp);
|
||||
rowstride = cogl_bitmap_get_rowstride (bmp);
|
||||
|
||||
if ((data = _cogl_bitmap_map (bmp,
|
||||
COGL_BUFFER_ACCESS_READ |
|
||||
COGL_BUFFER_ACCESS_WRITE,
|
||||
0,
|
||||
error)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* If we can't directly unpremult the data inline then we'll
|
||||
allocate a temporary row and unpack the data. This assumes if we
|
||||
can fast premult then we can also fast unpremult */
|
||||
if (_cogl_bitmap_can_fast_premult (format))
|
||||
tmp_row = NULL;
|
||||
else
|
||||
tmp_row = g_malloc (sizeof (uint16_t) * 4 * width);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
p = (uint8_t*) data + y * rowstride;
|
||||
|
||||
if (tmp_row)
|
||||
{
|
||||
_cogl_unpack_16 (format, p, tmp_row, width);
|
||||
_cogl_bitmap_unpremult_unpacked_span_16 (tmp_row, width);
|
||||
_cogl_pack_16 (format, tmp_row, p, width);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (format & COGL_AFIRST_BIT)
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
if (p[0] == 0)
|
||||
_cogl_unpremult_alpha_0 (p);
|
||||
else
|
||||
_cogl_unpremult_alpha_first (p);
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
_cogl_bitmap_unpremult_unpacked_span_8 (p, width);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (tmp_row);
|
||||
|
||||
_cogl_bitmap_unmap (bmp);
|
||||
|
||||
_cogl_bitmap_set_format (bmp, format & ~COGL_PREMULT_BIT);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_premult (CoglBitmap *bmp,
|
||||
CoglError **error)
|
||||
{
|
||||
uint8_t *p, *data;
|
||||
uint16_t *tmp_row;
|
||||
int x,y;
|
||||
CoglPixelFormat format;
|
||||
int width, height;
|
||||
int rowstride;
|
||||
|
||||
format = cogl_bitmap_get_format (bmp);
|
||||
width = cogl_bitmap_get_width (bmp);
|
||||
height = cogl_bitmap_get_height (bmp);
|
||||
rowstride = cogl_bitmap_get_rowstride (bmp);
|
||||
|
||||
if ((data = _cogl_bitmap_map (bmp,
|
||||
COGL_BUFFER_ACCESS_READ |
|
||||
COGL_BUFFER_ACCESS_WRITE,
|
||||
0,
|
||||
error)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* If we can't directly premult the data inline then we'll allocate
|
||||
a temporary row and unpack the data. */
|
||||
if (_cogl_bitmap_can_fast_premult (format))
|
||||
tmp_row = NULL;
|
||||
else
|
||||
tmp_row = g_malloc (sizeof (uint16_t) * 4 * width);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
p = (uint8_t*) data + y * rowstride;
|
||||
|
||||
if (tmp_row)
|
||||
{
|
||||
_cogl_unpack_16 (format, p, tmp_row, width);
|
||||
_cogl_bitmap_premult_unpacked_span_16 (tmp_row, width);
|
||||
_cogl_pack_16 (format, tmp_row, p, width);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (format & COGL_AFIRST_BIT)
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
_cogl_premult_alpha_first (p);
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
_cogl_bitmap_premult_unpacked_span_8 (p, width);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (tmp_row);
|
||||
|
||||
_cogl_bitmap_unmap (bmp);
|
||||
|
||||
_cogl_bitmap_set_format (bmp, format | COGL_PREMULT_BIT);
|
||||
|
||||
return TRUE;
|
||||
}
|
767
cogl/cogl/cogl-bitmap-packing.h
Normal file
767
cogl/cogl/cogl-bitmap-packing.h
Normal file
@ -0,0 +1,767 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* This file is included multiple times with different definitions for
|
||||
the component_type type (either uint8_t or uint16_t). The code ends
|
||||
up exactly the same for both but we only want to end up hitting the
|
||||
16-bit path when one of the types in the conversion is > 8 bits per
|
||||
component. */
|
||||
|
||||
/* Unpacking to RGBA */
|
||||
|
||||
#define UNPACK_1(b) ((b) * ((1 << (sizeof (component_type) * 8)) - 1))
|
||||
#define UNPACK_2(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
|
||||
1) / 3)
|
||||
#define UNPACK_4(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
|
||||
7) / 15)
|
||||
#define UNPACK_5(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
|
||||
15) / 31)
|
||||
#define UNPACK_6(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
|
||||
31) / 63)
|
||||
#define UNPACK_10(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
|
||||
511) / 1023)
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_a_8_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = 0;
|
||||
dst[1] = 0;
|
||||
dst[2] = 0;
|
||||
dst[3] = UNPACK_BYTE (*src);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_g_8_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
/* FIXME: I'm not sure if this is right. It looks like Nvidia and
|
||||
Mesa handle luminance textures differently. Maybe we should
|
||||
consider just removing luminance textures for Cogl 2.0 because
|
||||
they have been removed in GL 3.0 */
|
||||
while (width-- > 0)
|
||||
{
|
||||
component_type v = UNPACK_BYTE (src[0]);
|
||||
dst[0] = v;
|
||||
dst[1] = v;
|
||||
dst[2] = v;
|
||||
dst[3] = UNPACK_BYTE (255);
|
||||
dst += 4;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_rg_88_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = UNPACK_BYTE (src[0]);
|
||||
dst[1] = UNPACK_BYTE (src[1]);
|
||||
dst[2] = 0;
|
||||
dst[3] = UNPACK_BYTE (255);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_rgb_888_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = UNPACK_BYTE (src[0]);
|
||||
dst[1] = UNPACK_BYTE (src[1]);
|
||||
dst[2] = UNPACK_BYTE (src[2]);
|
||||
dst[3] = UNPACK_BYTE (255);
|
||||
dst += 4;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_bgr_888_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = UNPACK_BYTE (src[2]);
|
||||
dst[1] = UNPACK_BYTE (src[1]);
|
||||
dst[2] = UNPACK_BYTE (src[0]);
|
||||
dst[3] = UNPACK_BYTE (255);
|
||||
dst += 4;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_bgra_8888_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = UNPACK_BYTE (src[2]);
|
||||
dst[1] = UNPACK_BYTE (src[1]);
|
||||
dst[2] = UNPACK_BYTE (src[0]);
|
||||
dst[3] = UNPACK_BYTE (src[3]);
|
||||
dst += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_argb_8888_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = UNPACK_BYTE (src[1]);
|
||||
dst[1] = UNPACK_BYTE (src[2]);
|
||||
dst[2] = UNPACK_BYTE (src[3]);
|
||||
dst[3] = UNPACK_BYTE (src[0]);
|
||||
dst += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_abgr_8888_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = UNPACK_BYTE (src[3]);
|
||||
dst[1] = UNPACK_BYTE (src[2]);
|
||||
dst[2] = UNPACK_BYTE (src[1]);
|
||||
dst[3] = UNPACK_BYTE (src[0]);
|
||||
dst += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_rgba_8888_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = UNPACK_BYTE (src[0]);
|
||||
dst[1] = UNPACK_BYTE (src[1]);
|
||||
dst[2] = UNPACK_BYTE (src[2]);
|
||||
dst[3] = UNPACK_BYTE (src[3]);
|
||||
dst += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_rgb_565_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t v = *(const uint16_t *) src;
|
||||
|
||||
dst[0] = UNPACK_5 (v >> 11);
|
||||
dst[1] = UNPACK_6 ((v >> 5) & 63);
|
||||
dst[2] = UNPACK_5 (v & 31);
|
||||
dst[3] = UNPACK_BYTE (255);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_rgba_4444_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t v = *(const uint16_t *) src;
|
||||
|
||||
dst[0] = UNPACK_4 (v >> 12);
|
||||
dst[1] = UNPACK_4 ((v >> 8) & 15);
|
||||
dst[2] = UNPACK_4 ((v >> 4) & 15);
|
||||
dst[3] = UNPACK_4 (v & 15);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_rgba_5551_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t v = *(const uint16_t *) src;
|
||||
|
||||
dst[0] = UNPACK_5 (v >> 11);
|
||||
dst[1] = UNPACK_5 ((v >> 6) & 31);
|
||||
dst[2] = UNPACK_5 ((v >> 1) & 31);
|
||||
dst[3] = UNPACK_1 (v & 1);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_rgba_1010102_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t v = *(const uint32_t *) src;
|
||||
|
||||
dst[0] = UNPACK_10 (v >> 22);
|
||||
dst[1] = UNPACK_10 ((v >> 12) & 1023);
|
||||
dst[2] = UNPACK_10 ((v >> 2) & 1023);
|
||||
dst[3] = UNPACK_2 (v & 3);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_bgra_1010102_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t v = *(const uint32_t *) src;
|
||||
|
||||
dst[2] = UNPACK_10 (v >> 22);
|
||||
dst[1] = UNPACK_10 ((v >> 12) & 1023);
|
||||
dst[0] = UNPACK_10 ((v >> 2) & 1023);
|
||||
dst[3] = UNPACK_2 (v & 3);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_argb_2101010_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t v = *(const uint32_t *) src;
|
||||
|
||||
dst[3] = UNPACK_2 (v >> 30);
|
||||
dst[0] = UNPACK_10 ((v >> 20) & 1023);
|
||||
dst[1] = UNPACK_10 ((v >> 10) & 1023);
|
||||
dst[2] = UNPACK_10 (v & 1023);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_abgr_2101010_, component_size) (const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t v = *(const uint32_t *) src;
|
||||
|
||||
dst[3] = UNPACK_2 (v >> 30);
|
||||
dst[2] = UNPACK_10 ((v >> 20) & 1023);
|
||||
dst[1] = UNPACK_10 ((v >> 10) & 1023);
|
||||
dst[0] = UNPACK_10 (v & 1023);
|
||||
dst += 4;
|
||||
src += 2;
|
||||
}
|
||||
}
|
||||
|
||||
#undef UNPACK_1
|
||||
#undef UNPACK_2
|
||||
#undef UNPACK_4
|
||||
#undef UNPACK_5
|
||||
#undef UNPACK_6
|
||||
#undef UNPACK_10
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format,
|
||||
const uint8_t *src,
|
||||
component_type *dst,
|
||||
int width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case COGL_PIXEL_FORMAT_A_8:
|
||||
G_PASTE (_cogl_unpack_a_8_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_G_8:
|
||||
G_PASTE (_cogl_unpack_g_8_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RG_88:
|
||||
G_PASTE (_cogl_unpack_rg_88_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGB_888:
|
||||
G_PASTE (_cogl_unpack_rgb_888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_BGR_888:
|
||||
G_PASTE (_cogl_unpack_bgr_888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_8888:
|
||||
case COGL_PIXEL_FORMAT_RGBA_8888_PRE:
|
||||
G_PASTE (_cogl_unpack_rgba_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_BGRA_8888:
|
||||
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
|
||||
G_PASTE (_cogl_unpack_bgra_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ARGB_8888:
|
||||
case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
|
||||
G_PASTE (_cogl_unpack_argb_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ABGR_8888:
|
||||
case COGL_PIXEL_FORMAT_ABGR_8888_PRE:
|
||||
G_PASTE (_cogl_unpack_abgr_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGB_565:
|
||||
G_PASTE (_cogl_unpack_rgb_565_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_4444:
|
||||
case COGL_PIXEL_FORMAT_RGBA_4444_PRE:
|
||||
G_PASTE (_cogl_unpack_rgba_4444_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_5551:
|
||||
case COGL_PIXEL_FORMAT_RGBA_5551_PRE:
|
||||
G_PASTE (_cogl_unpack_rgba_5551_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_1010102:
|
||||
case COGL_PIXEL_FORMAT_RGBA_1010102_PRE:
|
||||
G_PASTE (_cogl_unpack_rgba_1010102_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_BGRA_1010102:
|
||||
case COGL_PIXEL_FORMAT_BGRA_1010102_PRE:
|
||||
G_PASTE (_cogl_unpack_bgra_1010102_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ARGB_2101010:
|
||||
case COGL_PIXEL_FORMAT_ARGB_2101010_PRE:
|
||||
G_PASTE (_cogl_unpack_argb_2101010_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ABGR_2101010:
|
||||
case COGL_PIXEL_FORMAT_ABGR_2101010_PRE:
|
||||
G_PASTE (_cogl_unpack_abgr_2101010_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_DEPTH_16:
|
||||
case COGL_PIXEL_FORMAT_DEPTH_32:
|
||||
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
|
||||
case COGL_PIXEL_FORMAT_ANY:
|
||||
case COGL_PIXEL_FORMAT_YUV:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Packing from RGBA */
|
||||
|
||||
/* Pack and round to nearest */
|
||||
#define PACK_SIZE(b, max) \
|
||||
(((b) * (max) + (1 << (sizeof (component_type) * 8 - 1)) - 1) / \
|
||||
((1 << (sizeof (component_type) * 8)) - 1))
|
||||
|
||||
#define PACK_1(b) PACK_SIZE (b, 1)
|
||||
#define PACK_2(b) PACK_SIZE (b, 3)
|
||||
#define PACK_4(b) PACK_SIZE (b, 15)
|
||||
#define PACK_5(b) PACK_SIZE (b, 31)
|
||||
#define PACK_6(b) PACK_SIZE (b, 63)
|
||||
#define PACK_10(b) PACK_SIZE (b, 1023)
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_a_8_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
*dst = PACK_BYTE (src[3]);
|
||||
src += 4;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_g_8_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
/* FIXME: I'm not sure if this is right. It looks like Nvidia and
|
||||
Mesa handle luminance textures differently. Maybe we should
|
||||
consider just removing luminance textures for Cogl 2.0 because
|
||||
they have been removed in GL 3.0 */
|
||||
while (width-- > 0)
|
||||
{
|
||||
component_type v = (src[0] + src[1] + src[2]) / 3;
|
||||
*dst = PACK_BYTE (v);
|
||||
src += 4;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_rg_88_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = PACK_BYTE (src[0]);
|
||||
dst[1] = PACK_BYTE (src[1]);
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_rgb_888_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = PACK_BYTE (src[0]);
|
||||
dst[1] = PACK_BYTE (src[1]);
|
||||
dst[2] = PACK_BYTE (src[2]);
|
||||
src += 4;
|
||||
dst += 3;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_bgr_888_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[2] = PACK_BYTE (src[0]);
|
||||
dst[1] = PACK_BYTE (src[1]);
|
||||
dst[0] = PACK_BYTE (src[2]);
|
||||
src += 4;
|
||||
dst += 3;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_bgra_8888_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[2] = PACK_BYTE (src[0]);
|
||||
dst[1] = PACK_BYTE (src[1]);
|
||||
dst[0] = PACK_BYTE (src[2]);
|
||||
dst[3] = PACK_BYTE (src[3]);
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_argb_8888_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[1] = PACK_BYTE (src[0]);
|
||||
dst[2] = PACK_BYTE (src[1]);
|
||||
dst[3] = PACK_BYTE (src[2]);
|
||||
dst[0] = PACK_BYTE (src[3]);
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_abgr_8888_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[3] = PACK_BYTE (src[0]);
|
||||
dst[2] = PACK_BYTE (src[1]);
|
||||
dst[1] = PACK_BYTE (src[2]);
|
||||
dst[0] = PACK_BYTE (src[3]);
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_rgba_8888_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
dst[0] = PACK_BYTE (src[0]);
|
||||
dst[1] = PACK_BYTE (src[1]);
|
||||
dst[2] = PACK_BYTE (src[2]);
|
||||
dst[3] = PACK_BYTE (src[3]);
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_rgb_565_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t *v = (uint16_t *) dst;
|
||||
|
||||
*v = ((PACK_5 (src[0]) << 11) |
|
||||
(PACK_6 (src[1]) << 5) |
|
||||
PACK_5 (src[2]));
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_rgba_4444_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t *v = (uint16_t *) dst;
|
||||
|
||||
*v = ((PACK_4 (src[0]) << 12) |
|
||||
(PACK_4 (src[1]) << 8) |
|
||||
(PACK_4 (src[2]) << 4) |
|
||||
PACK_4 (src[3]));
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_rgba_5551_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint16_t *v = (uint16_t *) dst;
|
||||
|
||||
*v = ((PACK_5 (src[0]) << 11) |
|
||||
(PACK_5 (src[1]) << 6) |
|
||||
(PACK_5 (src[2]) << 1) |
|
||||
PACK_1 (src[3]));
|
||||
src += 4;
|
||||
dst += 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_rgba_1010102_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t *v = (uint32_t *) dst;
|
||||
|
||||
*v = ((PACK_10 (src[0]) << 22) |
|
||||
(PACK_10 (src[1]) << 12) |
|
||||
(PACK_10 (src[2]) << 2) |
|
||||
PACK_2 (src[3]));
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_bgra_1010102_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t *v = (uint32_t *) dst;
|
||||
|
||||
*v = ((PACK_10 (src[2]) << 22) |
|
||||
(PACK_10 (src[1]) << 12) |
|
||||
(PACK_10 (src[0]) << 2) |
|
||||
PACK_2 (src[3]));
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_argb_2101010_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t *v = (uint32_t *) dst;
|
||||
|
||||
*v = ((PACK_2 (src[3]) << 30) |
|
||||
(PACK_10 (src[0]) << 20) |
|
||||
(PACK_10 (src[1]) << 10) |
|
||||
PACK_10 (src[2]));
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_abgr_2101010_, component_size) (const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
while (width-- > 0)
|
||||
{
|
||||
uint32_t *v = (uint32_t *) dst;
|
||||
|
||||
*v = ((PACK_2 (src[3]) << 30) |
|
||||
(PACK_10 (src[2]) << 20) |
|
||||
(PACK_10 (src[1]) << 10) |
|
||||
PACK_10 (src[0]));
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
#undef PACK_SIZE
|
||||
#undef PACK_1
|
||||
#undef PACK_2
|
||||
#undef PACK_4
|
||||
#undef PACK_5
|
||||
#undef PACK_6
|
||||
#undef PACK_10
|
||||
|
||||
inline static void
|
||||
G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format,
|
||||
const component_type *src,
|
||||
uint8_t *dst,
|
||||
int width)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case COGL_PIXEL_FORMAT_A_8:
|
||||
G_PASTE (_cogl_pack_a_8_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_G_8:
|
||||
G_PASTE (_cogl_pack_g_8_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RG_88:
|
||||
G_PASTE (_cogl_pack_rg_88_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGB_888:
|
||||
G_PASTE (_cogl_pack_rgb_888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_BGR_888:
|
||||
G_PASTE (_cogl_pack_bgr_888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_8888:
|
||||
case COGL_PIXEL_FORMAT_RGBA_8888_PRE:
|
||||
G_PASTE (_cogl_pack_rgba_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_BGRA_8888:
|
||||
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
|
||||
G_PASTE (_cogl_pack_bgra_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ARGB_8888:
|
||||
case COGL_PIXEL_FORMAT_ARGB_8888_PRE:
|
||||
G_PASTE (_cogl_pack_argb_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ABGR_8888:
|
||||
case COGL_PIXEL_FORMAT_ABGR_8888_PRE:
|
||||
G_PASTE (_cogl_pack_abgr_8888_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGB_565:
|
||||
G_PASTE (_cogl_pack_rgb_565_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_4444:
|
||||
case COGL_PIXEL_FORMAT_RGBA_4444_PRE:
|
||||
G_PASTE (_cogl_pack_rgba_4444_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_5551:
|
||||
case COGL_PIXEL_FORMAT_RGBA_5551_PRE:
|
||||
G_PASTE (_cogl_pack_rgba_5551_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_RGBA_1010102:
|
||||
case COGL_PIXEL_FORMAT_RGBA_1010102_PRE:
|
||||
G_PASTE (_cogl_pack_rgba_1010102_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_BGRA_1010102:
|
||||
case COGL_PIXEL_FORMAT_BGRA_1010102_PRE:
|
||||
G_PASTE (_cogl_pack_bgra_1010102_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ARGB_2101010:
|
||||
case COGL_PIXEL_FORMAT_ARGB_2101010_PRE:
|
||||
G_PASTE (_cogl_pack_argb_2101010_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_ABGR_2101010:
|
||||
case COGL_PIXEL_FORMAT_ABGR_2101010_PRE:
|
||||
G_PASTE (_cogl_pack_abgr_2101010_, component_size) (src, dst, width);
|
||||
break;
|
||||
case COGL_PIXEL_FORMAT_DEPTH_16:
|
||||
case COGL_PIXEL_FORMAT_DEPTH_32:
|
||||
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
|
||||
case COGL_PIXEL_FORMAT_ANY:
|
||||
case COGL_PIXEL_FORMAT_YUV:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
136
cogl/cogl/cogl-bitmap-pixbuf.c
Normal file
136
cogl/cogl/cogl-bitmap-pixbuf.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2007,2008,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 "cogl-util.h"
|
||||
#include "cogl-bitmap-private.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-private.h"
|
||||
#include "cogl-error-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_get_size_from_file (const char *filename,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
_COGL_RETURN_VAL_IF_FAIL (filename != NULL, FALSE);
|
||||
|
||||
if (gdk_pixbuf_get_file_info (filename, width, height) != NULL)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_from_file (CoglContext *ctx,
|
||||
const char *filename,
|
||||
CoglError **error)
|
||||
{
|
||||
static CoglUserDataKey pixbuf_key;
|
||||
GdkPixbuf *pixbuf;
|
||||
CoglBool has_alpha;
|
||||
GdkColorspace color_space;
|
||||
CoglPixelFormat pixel_format;
|
||||
int width;
|
||||
int height;
|
||||
int rowstride;
|
||||
int bits_per_sample;
|
||||
int n_channels;
|
||||
CoglBitmap *bmp;
|
||||
GError *glib_error = NULL;
|
||||
|
||||
/* Load from file using GdkPixbuf */
|
||||
pixbuf = gdk_pixbuf_new_from_file (filename, &glib_error);
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
_cogl_propagate_gerror (error, glib_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Get pixbuf properties */
|
||||
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
||||
color_space = gdk_pixbuf_get_colorspace (pixbuf);
|
||||
width = gdk_pixbuf_get_width (pixbuf);
|
||||
height = gdk_pixbuf_get_height (pixbuf);
|
||||
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
||||
bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
|
||||
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
|
||||
|
||||
/* According to current docs this should be true and so
|
||||
* the translation to cogl pixel format below valid */
|
||||
g_assert (bits_per_sample == 8);
|
||||
|
||||
if (has_alpha)
|
||||
g_assert (n_channels == 4);
|
||||
else
|
||||
g_assert (n_channels == 3);
|
||||
|
||||
/* Translate to cogl pixel format */
|
||||
switch (color_space)
|
||||
{
|
||||
case GDK_COLORSPACE_RGB:
|
||||
/* The only format supported by GdkPixbuf so far */
|
||||
pixel_format = has_alpha ?
|
||||
COGL_PIXEL_FORMAT_RGBA_8888 :
|
||||
COGL_PIXEL_FORMAT_RGB_888;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Ouch, spec changed! */
|
||||
g_object_unref (pixbuf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* We just use the data directly from the pixbuf so that we don't
|
||||
have to copy to a seperate buffer. Note that Cogl is expected not
|
||||
to read past the end of bpp*width on the last row even if the
|
||||
rowstride is much larger so we don't need to worry about
|
||||
GdkPixbuf's semantics that it may under-allocate the buffer. */
|
||||
bmp = cogl_bitmap_new_for_data (ctx,
|
||||
width,
|
||||
height,
|
||||
pixel_format,
|
||||
rowstride,
|
||||
gdk_pixbuf_get_pixels (pixbuf));
|
||||
|
||||
cogl_object_set_user_data (COGL_OBJECT (bmp),
|
||||
&pixbuf_key,
|
||||
pixbuf,
|
||||
g_object_unref);
|
||||
|
||||
return bmp;
|
||||
}
|
201
cogl/cogl/cogl-bitmap-private.h
Normal file
201
cogl/cogl/cogl-bitmap-private.h
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2007 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_BITMAP_H
|
||||
#define __COGL_BITMAP_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-buffer.h"
|
||||
#include "cogl-bitmap.h"
|
||||
|
||||
struct _CoglBitmap
|
||||
{
|
||||
CoglObject _parent;
|
||||
|
||||
/* Pointer back to the context that this bitmap was created with */
|
||||
CoglContext *context;
|
||||
|
||||
CoglPixelFormat format;
|
||||
int width;
|
||||
int height;
|
||||
int rowstride;
|
||||
|
||||
uint8_t *data;
|
||||
|
||||
CoglBool mapped;
|
||||
CoglBool bound;
|
||||
|
||||
/* If this is non-null then 'data' is ignored and instead it is
|
||||
fetched from this shared bitmap. */
|
||||
CoglBitmap *shared_bmp;
|
||||
|
||||
/* If this is non-null then 'data' is treated as an offset into the
|
||||
buffer and map will divert to mapping the buffer */
|
||||
CoglBuffer *buffer;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* _cogl_bitmap_new_with_malloc_buffer:
|
||||
* @context: A #CoglContext
|
||||
* @width: width of the bitmap in pixels
|
||||
* @height: height of the bitmap in pixels
|
||||
* @format: the format of the pixels the array will store
|
||||
* @error: A #CoglError for catching exceptional errors or %NULL
|
||||
*
|
||||
* This is equivalent to cogl_bitmap_new_with_size() except that it
|
||||
* allocated the buffer using g_malloc() instead of creating a
|
||||
* #CoglPixelBuffer. The buffer will be automatically destroyed when
|
||||
* the bitmap is freed.
|
||||
*
|
||||
* Return value: a #CoglPixelBuffer representing the newly created array
|
||||
*
|
||||
* Since: 1.10
|
||||
* Stability: Unstable
|
||||
*/
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_new_with_malloc_buffer (CoglContext *context,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
CoglPixelFormat format,
|
||||
CoglError **error);
|
||||
|
||||
/* The idea of this function is that it will create a bitmap that
|
||||
shares the actual data with another bitmap. This is needed for the
|
||||
atlas texture backend because it needs upload a bitmap to a sub
|
||||
texture but override the format so that it ignores the premult
|
||||
flag. */
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_new_shared (CoglBitmap *shared_bmp,
|
||||
CoglPixelFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int rowstride);
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_convert (CoglBitmap *bmp,
|
||||
CoglPixelFormat dst_format,
|
||||
CoglError **error);
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_convert_for_upload (CoglBitmap *src_bmp,
|
||||
CoglPixelFormat internal_format,
|
||||
CoglBool can_convert_in_place,
|
||||
CoglError **error);
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
|
||||
CoglBitmap *dst_bmp,
|
||||
CoglError **error);
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_from_file (CoglContext *ctx,
|
||||
const char *filename,
|
||||
CoglError **error);
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_unpremult (CoglBitmap *dst_bmp,
|
||||
CoglError **error);
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_premult (CoglBitmap *dst_bmp,
|
||||
CoglError **error);
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
|
||||
CoglPixelFormat dst_format,
|
||||
CoglError **error);
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_copy_subregion (CoglBitmap *src,
|
||||
CoglBitmap *dst,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height,
|
||||
CoglError **error);
|
||||
|
||||
/* Creates a deep copy of the source bitmap */
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_copy (CoglBitmap *src_bmp,
|
||||
CoglError **error);
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_get_size_from_file (const char *filename,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
void
|
||||
_cogl_bitmap_set_format (CoglBitmap *bitmap,
|
||||
CoglPixelFormat format);
|
||||
|
||||
/* Maps the bitmap so that the pixels can be accessed directly or if
|
||||
the bitmap is just a memory bitmap then it just returns the pointer
|
||||
to memory. Note that the bitmap isn't guaranteed to allocated to
|
||||
the full size of rowstride*height so it is not safe to read up to
|
||||
the rowstride of the last row. This will be the case if the user
|
||||
uploads data using gdk_pixbuf_new_subpixbuf with a sub region
|
||||
containing the last row of the pixbuf because in that case the
|
||||
rowstride can be much larger than the width of the image */
|
||||
uint8_t *
|
||||
_cogl_bitmap_map (CoglBitmap *bitmap,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error);
|
||||
|
||||
void
|
||||
_cogl_bitmap_unmap (CoglBitmap *bitmap);
|
||||
|
||||
/* These two are replacements for map and unmap that should used when
|
||||
* the pointer is going to be passed to GL for pixel packing or
|
||||
* unpacking. The address might not be valid for reading if the bitmap
|
||||
* was created with new_from_buffer but it will however be good to
|
||||
* pass to glTexImage2D for example. The access should be READ for
|
||||
* unpacking and WRITE for packing. It can not be both
|
||||
*
|
||||
* TODO: split this bind/unbind functions out into a GL specific file
|
||||
*/
|
||||
uint8_t *
|
||||
_cogl_bitmap_gl_bind (CoglBitmap *bitmap,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error);
|
||||
|
||||
void
|
||||
_cogl_bitmap_gl_unbind (CoglBitmap *bitmap);
|
||||
|
||||
CoglContext *
|
||||
_cogl_bitmap_get_context (CoglBitmap *bitmap);
|
||||
|
||||
#endif /* __COGL_BITMAP_H */
|
522
cogl/cogl/cogl-bitmap.c
Normal file
522
cogl/cogl/cogl-bitmap.c
Normal file
@ -0,0 +1,522 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2007,2008,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 "cogl-util.h"
|
||||
#include "cogl-debug.h"
|
||||
#include "cogl-private.h"
|
||||
#include "cogl-bitmap-private.h"
|
||||
#include "cogl-buffer-private.h"
|
||||
#include "cogl-pixel-buffer.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-buffer-gl-private.h"
|
||||
#include "cogl-error-private.h"
|
||||
#include "cogl-gtype-private.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void _cogl_bitmap_free (CoglBitmap *bmp);
|
||||
|
||||
COGL_OBJECT_DEFINE (Bitmap, bitmap);
|
||||
COGL_GTYPE_DEFINE_CLASS (Bitmap, bitmap);
|
||||
|
||||
static void
|
||||
_cogl_bitmap_free (CoglBitmap *bmp)
|
||||
{
|
||||
g_assert (!bmp->mapped);
|
||||
g_assert (!bmp->bound);
|
||||
|
||||
if (bmp->shared_bmp)
|
||||
cogl_object_unref (bmp->shared_bmp);
|
||||
|
||||
if (bmp->buffer)
|
||||
cogl_object_unref (bmp->buffer);
|
||||
|
||||
g_slice_free (CoglBitmap, bmp);
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_convert_premult_status (CoglBitmap *bmp,
|
||||
CoglPixelFormat dst_format,
|
||||
CoglError **error)
|
||||
{
|
||||
/* Do we need to unpremultiply? */
|
||||
if ((bmp->format & COGL_PREMULT_BIT) > 0 &&
|
||||
(dst_format & COGL_PREMULT_BIT) == 0 &&
|
||||
COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (dst_format))
|
||||
return _cogl_bitmap_unpremult (bmp, error);
|
||||
|
||||
/* Do we need to premultiply? */
|
||||
if ((bmp->format & COGL_PREMULT_BIT) == 0 &&
|
||||
COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (bmp->format) &&
|
||||
(dst_format & COGL_PREMULT_BIT) > 0)
|
||||
/* Try premultiplying using imaging library */
|
||||
return _cogl_bitmap_premult (bmp, error);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_copy (CoglBitmap *src_bmp,
|
||||
CoglError **error)
|
||||
{
|
||||
CoglBitmap *dst_bmp;
|
||||
CoglPixelFormat src_format = cogl_bitmap_get_format (src_bmp);
|
||||
int width = cogl_bitmap_get_width (src_bmp);
|
||||
int height = cogl_bitmap_get_height (src_bmp);
|
||||
|
||||
dst_bmp =
|
||||
_cogl_bitmap_new_with_malloc_buffer (src_bmp->context,
|
||||
width, height,
|
||||
src_format,
|
||||
error);
|
||||
if (!dst_bmp)
|
||||
return NULL;
|
||||
|
||||
if (!_cogl_bitmap_copy_subregion (src_bmp,
|
||||
dst_bmp,
|
||||
0, 0, /* src_x/y */
|
||||
0, 0, /* dst_x/y */
|
||||
width, height,
|
||||
error))
|
||||
{
|
||||
cogl_object_unref (dst_bmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dst_bmp;
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmap_copy_subregion (CoglBitmap *src,
|
||||
CoglBitmap *dst,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height,
|
||||
CoglError **error)
|
||||
{
|
||||
uint8_t *srcdata;
|
||||
uint8_t *dstdata;
|
||||
int bpp;
|
||||
int line;
|
||||
CoglBool succeeded = FALSE;
|
||||
|
||||
/* Intended only for fast copies when format is equal! */
|
||||
_COGL_RETURN_VAL_IF_FAIL ((src->format & ~COGL_PREMULT_BIT) ==
|
||||
(dst->format & ~COGL_PREMULT_BIT),
|
||||
FALSE);
|
||||
|
||||
bpp = _cogl_pixel_format_get_bytes_per_pixel (src->format);
|
||||
|
||||
if ((srcdata = _cogl_bitmap_map (src, COGL_BUFFER_ACCESS_READ, 0, error)))
|
||||
{
|
||||
if ((dstdata =
|
||||
_cogl_bitmap_map (dst, COGL_BUFFER_ACCESS_WRITE, 0, error)))
|
||||
{
|
||||
srcdata += src_y * src->rowstride + src_x * bpp;
|
||||
dstdata += dst_y * dst->rowstride + dst_x * bpp;
|
||||
|
||||
for (line = 0; line < height; ++line)
|
||||
{
|
||||
memcpy (dstdata, srcdata, width * bpp);
|
||||
srcdata += src->rowstride;
|
||||
dstdata += dst->rowstride;
|
||||
}
|
||||
|
||||
succeeded = TRUE;
|
||||
|
||||
_cogl_bitmap_unmap (dst);
|
||||
}
|
||||
|
||||
_cogl_bitmap_unmap (src);
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
CoglBool
|
||||
cogl_bitmap_get_size_from_file (const char *filename,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
return _cogl_bitmap_get_size_from_file (filename, width, height);
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_for_data (CoglContext *context,
|
||||
int width,
|
||||
int height,
|
||||
CoglPixelFormat format,
|
||||
int rowstride,
|
||||
uint8_t *data)
|
||||
{
|
||||
CoglBitmap *bmp;
|
||||
|
||||
g_return_val_if_fail (cogl_is_context (context), NULL);
|
||||
|
||||
/* Rowstride from width if not given */
|
||||
if (rowstride == 0)
|
||||
rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
|
||||
|
||||
bmp = g_slice_new (CoglBitmap);
|
||||
bmp->context = context;
|
||||
bmp->format = format;
|
||||
bmp->width = width;
|
||||
bmp->height = height;
|
||||
bmp->rowstride = rowstride;
|
||||
bmp->data = data;
|
||||
bmp->mapped = FALSE;
|
||||
bmp->bound = FALSE;
|
||||
bmp->shared_bmp = NULL;
|
||||
bmp->buffer = NULL;
|
||||
|
||||
return _cogl_bitmap_object_new (bmp);
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_new_with_malloc_buffer (CoglContext *context,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
CoglPixelFormat format,
|
||||
CoglError **error)
|
||||
{
|
||||
static CoglUserDataKey bitmap_free_key;
|
||||
int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
|
||||
int rowstride = ((width * bpp) + 3) & ~3;
|
||||
uint8_t *data = g_try_malloc (rowstride * height);
|
||||
CoglBitmap *bitmap;
|
||||
|
||||
if (!data)
|
||||
{
|
||||
_cogl_set_error (error,
|
||||
COGL_SYSTEM_ERROR,
|
||||
COGL_SYSTEM_ERROR_NO_MEMORY,
|
||||
"Failed to allocate memory for bitmap");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bitmap = cogl_bitmap_new_for_data (context,
|
||||
width, height,
|
||||
format,
|
||||
rowstride,
|
||||
data);
|
||||
cogl_object_set_user_data (COGL_OBJECT (bitmap),
|
||||
&bitmap_free_key,
|
||||
data,
|
||||
g_free);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
_cogl_bitmap_new_shared (CoglBitmap *shared_bmp,
|
||||
CoglPixelFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int rowstride)
|
||||
{
|
||||
CoglBitmap *bmp;
|
||||
|
||||
bmp = cogl_bitmap_new_for_data (shared_bmp->context,
|
||||
width, height,
|
||||
format,
|
||||
rowstride,
|
||||
NULL /* data */);
|
||||
|
||||
bmp->shared_bmp = cogl_object_ref (shared_bmp);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_from_file (const char *filename,
|
||||
CoglError **error)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (filename != NULL, NULL);
|
||||
_COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL);
|
||||
|
||||
return _cogl_bitmap_from_file (ctx, filename, error);
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_from_buffer (CoglBuffer *buffer,
|
||||
CoglPixelFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int rowstride,
|
||||
int offset)
|
||||
{
|
||||
CoglBitmap *bmp;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL);
|
||||
|
||||
bmp = cogl_bitmap_new_for_data (buffer->context,
|
||||
width, height,
|
||||
format,
|
||||
rowstride,
|
||||
NULL /* data */);
|
||||
|
||||
bmp->buffer = cogl_object_ref (buffer);
|
||||
bmp->data = GINT_TO_POINTER (offset);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_with_size (CoglContext *context,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
CoglPixelFormat format)
|
||||
{
|
||||
CoglPixelBuffer *pixel_buffer;
|
||||
CoglBitmap *bitmap;
|
||||
unsigned int rowstride;
|
||||
|
||||
/* creating a buffer to store "any" format does not make sense */
|
||||
_COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
|
||||
|
||||
/* for now we fallback to cogl_pixel_buffer_new, later, we could ask
|
||||
* libdrm a tiled buffer for instance */
|
||||
rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
|
||||
|
||||
pixel_buffer =
|
||||
cogl_pixel_buffer_new (context,
|
||||
height * rowstride,
|
||||
NULL); /* data */
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (pixel_buffer != NULL, NULL);
|
||||
|
||||
bitmap = cogl_bitmap_new_from_buffer (COGL_BUFFER (pixel_buffer),
|
||||
format,
|
||||
width, height,
|
||||
rowstride,
|
||||
0 /* offset */);
|
||||
|
||||
cogl_object_unref (pixel_buffer);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
CoglPixelFormat
|
||||
cogl_bitmap_get_format (CoglBitmap *bitmap)
|
||||
{
|
||||
return bitmap->format;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmap_set_format (CoglBitmap *bitmap,
|
||||
CoglPixelFormat format)
|
||||
{
|
||||
bitmap->format = format;
|
||||
}
|
||||
|
||||
int
|
||||
cogl_bitmap_get_width (CoglBitmap *bitmap)
|
||||
{
|
||||
return bitmap->width;
|
||||
}
|
||||
|
||||
int
|
||||
cogl_bitmap_get_height (CoglBitmap *bitmap)
|
||||
{
|
||||
return bitmap->height;
|
||||
}
|
||||
|
||||
int
|
||||
cogl_bitmap_get_rowstride (CoglBitmap *bitmap)
|
||||
{
|
||||
return bitmap->rowstride;
|
||||
}
|
||||
|
||||
CoglPixelBuffer *
|
||||
cogl_bitmap_get_buffer (CoglBitmap *bitmap)
|
||||
{
|
||||
while (bitmap->shared_bmp)
|
||||
bitmap = bitmap->shared_bmp;
|
||||
|
||||
return COGL_PIXEL_BUFFER (bitmap->buffer);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
cogl_bitmap_error_quark (void)
|
||||
{
|
||||
return g_quark_from_static_string ("cogl-bitmap-error-quark");
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
_cogl_bitmap_map (CoglBitmap *bitmap,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error)
|
||||
{
|
||||
/* Divert to another bitmap if this data is shared */
|
||||
if (bitmap->shared_bmp)
|
||||
return _cogl_bitmap_map (bitmap->shared_bmp, access, hints, error);
|
||||
|
||||
g_assert (!bitmap->mapped);
|
||||
|
||||
if (bitmap->buffer)
|
||||
{
|
||||
uint8_t *data = _cogl_buffer_map (bitmap->buffer,
|
||||
access,
|
||||
hints,
|
||||
error);
|
||||
|
||||
COGL_NOTE (BITMAP, "A pixel array is being mapped from a bitmap. This "
|
||||
"usually means that some conversion on the pixel array is "
|
||||
"needed so a sub-optimal format is being used.");
|
||||
|
||||
if (data)
|
||||
{
|
||||
bitmap->mapped = TRUE;
|
||||
|
||||
return data + GPOINTER_TO_INT (bitmap->data);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap->mapped = TRUE;
|
||||
|
||||
return bitmap->data;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmap_unmap (CoglBitmap *bitmap)
|
||||
{
|
||||
/* Divert to another bitmap if this data is shared */
|
||||
if (bitmap->shared_bmp)
|
||||
{
|
||||
_cogl_bitmap_unmap (bitmap->shared_bmp);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (bitmap->mapped);
|
||||
bitmap->mapped = FALSE;
|
||||
|
||||
if (bitmap->buffer)
|
||||
cogl_buffer_unmap (bitmap->buffer);
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
_cogl_bitmap_gl_bind (CoglBitmap *bitmap,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
CoglError *internal_error = NULL;
|
||||
|
||||
g_return_val_if_fail (access & (COGL_BUFFER_ACCESS_READ |
|
||||
COGL_BUFFER_ACCESS_WRITE),
|
||||
NULL);
|
||||
|
||||
/* Divert to another bitmap if this data is shared */
|
||||
if (bitmap->shared_bmp)
|
||||
return _cogl_bitmap_gl_bind (bitmap->shared_bmp, access, hints, error);
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (!bitmap->bound, NULL);
|
||||
|
||||
/* If the bitmap wasn't created from a buffer then the
|
||||
implementation of bind is the same as map */
|
||||
if (bitmap->buffer == NULL)
|
||||
{
|
||||
uint8_t *data = _cogl_bitmap_map (bitmap, access, hints, error);
|
||||
if (data)
|
||||
bitmap->bound = TRUE;
|
||||
return data;
|
||||
}
|
||||
|
||||
if (access == COGL_BUFFER_ACCESS_READ)
|
||||
ptr = _cogl_buffer_gl_bind (bitmap->buffer,
|
||||
COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK,
|
||||
&internal_error);
|
||||
else if (access == COGL_BUFFER_ACCESS_WRITE)
|
||||
ptr = _cogl_buffer_gl_bind (bitmap->buffer,
|
||||
COGL_BUFFER_BIND_TARGET_PIXEL_PACK,
|
||||
&internal_error);
|
||||
else
|
||||
{
|
||||
ptr = NULL;
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* NB: _cogl_buffer_gl_bind() may return NULL in non-error
|
||||
* conditions so we have to explicitly check internal_error to see
|
||||
* if an exception was thrown */
|
||||
if (internal_error)
|
||||
{
|
||||
_cogl_propagate_error (error, internal_error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bitmap->bound = TRUE;
|
||||
|
||||
/* The data pointer actually stores the offset */
|
||||
return ptr + GPOINTER_TO_INT (bitmap->data);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmap_gl_unbind (CoglBitmap *bitmap)
|
||||
{
|
||||
/* Divert to another bitmap if this data is shared */
|
||||
if (bitmap->shared_bmp)
|
||||
{
|
||||
_cogl_bitmap_gl_unbind (bitmap->shared_bmp);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (bitmap->bound);
|
||||
bitmap->bound = FALSE;
|
||||
|
||||
/* If the bitmap wasn't created from a pixel array then the
|
||||
implementation of unbind is the same as unmap */
|
||||
if (bitmap->buffer)
|
||||
_cogl_buffer_gl_unbind (bitmap->buffer);
|
||||
else
|
||||
_cogl_bitmap_unmap (bitmap);
|
||||
}
|
||||
|
||||
CoglContext *
|
||||
_cogl_bitmap_get_context (CoglBitmap *bitmap)
|
||||
{
|
||||
return bitmap->context;
|
||||
}
|
310
cogl/cogl/cogl-bitmap.h
Normal file
310
cogl/cogl/cogl-bitmap.h
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2007,2008,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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_BITMAP_H__
|
||||
#define __COGL_BITMAP_H__
|
||||
|
||||
/* XXX: We forward declare CoglBitmap here to allow for circular
|
||||
* dependencies between some headers */
|
||||
typedef struct _CoglBitmap CoglBitmap;
|
||||
|
||||
#include <cogl/cogl-types.h>
|
||||
#include <cogl/cogl-buffer.h>
|
||||
#include <cogl/cogl-context.h>
|
||||
#include <cogl/cogl-pixel-buffer.h>
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
#include <glib-object.h>
|
||||
#endif
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
/**
|
||||
* cogl_bitmap_get_gtype:
|
||||
*
|
||||
* Returns: a #GType that can be used with the GLib type system.
|
||||
*/
|
||||
GType cogl_bitmap_get_gtype (void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION:cogl-bitmap
|
||||
* @short_description: Functions for loading images
|
||||
*
|
||||
* Cogl allows loading image data into memory as CoglBitmaps without
|
||||
* loading them immediately into GPU textures.
|
||||
*
|
||||
* #CoglBitmap is available since Cogl 1.0
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* cogl_bitmap_new_from_file:
|
||||
* @filename: the file to load.
|
||||
* @error: a #CoglError or %NULL.
|
||||
*
|
||||
* Loads an image file from disk. This function can be safely called from
|
||||
* within a thread.
|
||||
*
|
||||
* Return value: (transfer full): a #CoglBitmap to the new loaded
|
||||
* image data, or %NULL if loading the image failed.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_from_file (const char *filename,
|
||||
CoglError **error);
|
||||
|
||||
#if defined (COGL_ENABLE_EXPERIMENTAL_API)
|
||||
|
||||
/**
|
||||
* cogl_bitmap_new_from_buffer:
|
||||
* @buffer: A #CoglBuffer containing image data
|
||||
* @format: The #CoglPixelFormat defining the format of the image data
|
||||
* in the given @buffer.
|
||||
* @width: The width of the image data in the given @buffer.
|
||||
* @height: The height of the image data in the given @buffer.
|
||||
* @rowstride: The rowstride in bytes of the image data in the given @buffer.
|
||||
* @offset: The offset into the given @buffer to the first pixel that
|
||||
* should be considered part of the #CoglBitmap.
|
||||
*
|
||||
* Wraps some image data that has been uploaded into a #CoglBuffer as
|
||||
* a #CoglBitmap. The data is not copied in this process.
|
||||
*
|
||||
* Return value: (transfer full): a #CoglBitmap encapsulating the given @buffer.
|
||||
*
|
||||
* Since: 1.8
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_from_buffer (CoglBuffer *buffer,
|
||||
CoglPixelFormat format,
|
||||
int width,
|
||||
int height,
|
||||
int rowstride,
|
||||
int offset);
|
||||
|
||||
/**
|
||||
* cogl_bitmap_new_with_size:
|
||||
* @context: A #CoglContext
|
||||
* @width: width of the bitmap in pixels
|
||||
* @height: height of the bitmap in pixels
|
||||
* @format: the format of the pixels the array will store
|
||||
*
|
||||
* Creates a new #CoglBitmap with the given width, height and format.
|
||||
* The initial contents of the bitmap are undefined.
|
||||
*
|
||||
* The data for the bitmap will be stored in a newly created
|
||||
* #CoglPixelBuffer. You can get a pointer to the pixel buffer using
|
||||
* cogl_bitmap_get_buffer(). The #CoglBuffer API can then be
|
||||
* used to fill the bitmap with data.
|
||||
*
|
||||
* <note>Cogl will try its best to provide a hardware array you can
|
||||
* map, write into and effectively do a zero copy upload when creating
|
||||
* a texture from it with cogl_texture_new_from_bitmap(). For various
|
||||
* reasons, such arrays are likely to have a stride larger than width
|
||||
* * bytes_per_pixel. The user must take the stride into account when
|
||||
* writing into it. The stride can be retrieved with
|
||||
* cogl_bitmap_get_rowstride().</note>
|
||||
*
|
||||
* Return value: (transfer full): a #CoglPixelBuffer representing the
|
||||
* newly created array or %NULL on failure
|
||||
*
|
||||
* Since: 1.10
|
||||
* Stability: Unstable
|
||||
*/
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_with_size (CoglContext *context,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
CoglPixelFormat format);
|
||||
|
||||
/**
|
||||
* cogl_bitmap_new_for_data:
|
||||
* @context: A #CoglContext
|
||||
* @width: The width of the bitmap.
|
||||
* @height: The height of the bitmap.
|
||||
* @format: The format of the pixel data.
|
||||
* @rowstride: The rowstride of the bitmap (the number of bytes from
|
||||
* the start of one row of the bitmap to the next).
|
||||
* @data: A pointer to the data. The bitmap will take ownership of this data.
|
||||
*
|
||||
* Creates a bitmap using some existing data. The data is not copied
|
||||
* so the application must keep the buffer alive for the lifetime of
|
||||
* the #CoglBitmap. This can be used for example with
|
||||
* cogl_framebuffer_read_pixels_into_bitmap() to read data directly
|
||||
* into an application buffer with the specified rowstride.
|
||||
*
|
||||
* Return value: (transfer full): A new #CoglBitmap.
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglBitmap *
|
||||
cogl_bitmap_new_for_data (CoglContext *context,
|
||||
int width,
|
||||
int height,
|
||||
CoglPixelFormat format,
|
||||
int rowstride,
|
||||
uint8_t *data);
|
||||
|
||||
/**
|
||||
* cogl_bitmap_get_format:
|
||||
* @bitmap: A #CoglBitmap
|
||||
*
|
||||
* Return value: the #CoglPixelFormat that the data for the bitmap is in.
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglPixelFormat
|
||||
cogl_bitmap_get_format (CoglBitmap *bitmap);
|
||||
|
||||
/**
|
||||
* cogl_bitmap_get_width:
|
||||
* @bitmap: A #CoglBitmap
|
||||
*
|
||||
* Return value: the width of the bitmap
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
*/
|
||||
int
|
||||
cogl_bitmap_get_width (CoglBitmap *bitmap);
|
||||
|
||||
/**
|
||||
* cogl_bitmap_get_height:
|
||||
* @bitmap: A #CoglBitmap
|
||||
*
|
||||
* Return value: the height of the bitmap
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
*/
|
||||
int
|
||||
cogl_bitmap_get_height (CoglBitmap *bitmap);
|
||||
|
||||
/**
|
||||
* cogl_bitmap_get_rowstride:
|
||||
* @bitmap: A #CoglBitmap
|
||||
*
|
||||
* Return value: the rowstride of the bitmap. This is the number of
|
||||
* bytes between the address of start of one row to the address of the
|
||||
* next row in the image.
|
||||
* Since: 1.10
|
||||
* Stability: unstable
|
||||
*/
|
||||
int
|
||||
cogl_bitmap_get_rowstride (CoglBitmap *bitmap);
|
||||
|
||||
/**
|
||||
* cogl_bitmap_get_buffer:
|
||||
* @bitmap: A #CoglBitmap
|
||||
*
|
||||
* Return value: (transfer none): the #CoglPixelBuffer that this
|
||||
* buffer uses for storage. Note that if the bitmap was created with
|
||||
* cogl_bitmap_new_from_file() then it will not actually be using a
|
||||
* pixel buffer and this function will return %NULL.
|
||||
* Stability: unstable
|
||||
* Since: 1.10
|
||||
*/
|
||||
CoglPixelBuffer *
|
||||
cogl_bitmap_get_buffer (CoglBitmap *bitmap);
|
||||
|
||||
#endif /* COGL_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
/**
|
||||
* cogl_bitmap_get_size_from_file:
|
||||
* @filename: the file to check
|
||||
* @width: (out): return location for the bitmap width, or %NULL
|
||||
* @height: (out): return location for the bitmap height, or %NULL
|
||||
*
|
||||
* Parses an image file enough to extract the width and height
|
||||
* of the bitmap.
|
||||
*
|
||||
* Return value: %TRUE if the image was successfully parsed
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
CoglBool
|
||||
cogl_bitmap_get_size_from_file (const char *filename,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
/**
|
||||
* cogl_is_bitmap:
|
||||
* @object: a #CoglObject pointer
|
||||
*
|
||||
* Checks whether @object is a #CoglBitmap
|
||||
*
|
||||
* Return value: %TRUE if the passed @object represents a bitmap,
|
||||
* and %FALSE otherwise
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
CoglBool
|
||||
cogl_is_bitmap (void *object);
|
||||
|
||||
/**
|
||||
* COGL_BITMAP_ERROR:
|
||||
*
|
||||
* #CoglError domain for bitmap errors.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
#define COGL_BITMAP_ERROR (cogl_bitmap_error_quark ())
|
||||
|
||||
/**
|
||||
* CoglBitmapError:
|
||||
* @COGL_BITMAP_ERROR_FAILED: Generic failure code, something went
|
||||
* wrong.
|
||||
* @COGL_BITMAP_ERROR_UNKNOWN_TYPE: Unknown image type.
|
||||
* @COGL_BITMAP_ERROR_CORRUPT_IMAGE: An image file was broken somehow.
|
||||
*
|
||||
* Error codes that can be thrown when performing bitmap
|
||||
* operations. Note that gdk_pixbuf_new_from_file() can also throw
|
||||
* errors directly from the underlying image loading library. For
|
||||
* example, if GdkPixbuf is used then errors #GdkPixbufError<!-- -->s
|
||||
* will be used directly.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
typedef enum {
|
||||
COGL_BITMAP_ERROR_FAILED,
|
||||
COGL_BITMAP_ERROR_UNKNOWN_TYPE,
|
||||
COGL_BITMAP_ERROR_CORRUPT_IMAGE
|
||||
} CoglBitmapError;
|
||||
|
||||
uint32_t cogl_bitmap_error_quark (void);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_BITMAP_H__ */
|
489
cogl/cogl/cogl-bitmask.c
Normal file
489
cogl/cogl/cogl-bitmask.c
Normal file
@ -0,0 +1,489 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Neil Roberts <neil@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <test-fixtures/test-unit.h>
|
||||
|
||||
#include "cogl-bitmask.h"
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-flags.h"
|
||||
|
||||
/* This code assumes that we can cast an unsigned long to a pointer
|
||||
and back without losing any data */
|
||||
_COGL_STATIC_ASSERT (sizeof (unsigned long) <= sizeof (void *),
|
||||
"This toolchain breaks Cogl's assumption that it can "
|
||||
"safely cast an unsigned long to a pointer without "
|
||||
"loosing data");
|
||||
|
||||
#define ARRAY_INDEX(bit_num) \
|
||||
((bit_num) / (sizeof (unsigned long) * 8))
|
||||
#define BIT_INDEX(bit_num) \
|
||||
((bit_num) & (sizeof (unsigned long) * 8 - 1))
|
||||
#define BIT_MASK(bit_num) \
|
||||
(1UL << BIT_INDEX (bit_num))
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmask_get_from_array (const CoglBitmask *bitmask,
|
||||
unsigned int bit_num)
|
||||
{
|
||||
GArray *array = (GArray *) *bitmask;
|
||||
|
||||
/* If the index is off the end of the array then assume the bit is
|
||||
not set */
|
||||
if (bit_num >= sizeof (unsigned long) * 8 * array->len)
|
||||
return FALSE;
|
||||
else
|
||||
return !!(g_array_index (array, unsigned long, ARRAY_INDEX (bit_num)) &
|
||||
BIT_MASK (bit_num));
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_bitmask_convert_to_array (CoglBitmask *bitmask)
|
||||
{
|
||||
GArray *array;
|
||||
/* Fetch the old values */
|
||||
unsigned long old_values = _cogl_bitmask_to_bits (bitmask);
|
||||
|
||||
array = g_array_new (FALSE, /* not zero-terminated */
|
||||
TRUE, /* do clear new entries */
|
||||
sizeof (unsigned long));
|
||||
/* Copy the old values back in */
|
||||
g_array_append_val (array, old_values);
|
||||
|
||||
*bitmask = (struct _CoglBitmaskImaginaryType *) array;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmask_set_in_array (CoglBitmask *bitmask,
|
||||
unsigned int bit_num,
|
||||
CoglBool value)
|
||||
{
|
||||
GArray *array;
|
||||
unsigned int array_index;
|
||||
unsigned long new_value_mask;
|
||||
|
||||
/* If the bitmask is not already an array then we need to allocate one */
|
||||
if (!_cogl_bitmask_has_array (bitmask))
|
||||
_cogl_bitmask_convert_to_array (bitmask);
|
||||
|
||||
array = (GArray *) *bitmask;
|
||||
|
||||
array_index = ARRAY_INDEX (bit_num);
|
||||
/* Grow the array if necessary. This will clear the new data */
|
||||
if (array_index >= array->len)
|
||||
g_array_set_size (array, array_index + 1);
|
||||
|
||||
new_value_mask = BIT_MASK (bit_num);
|
||||
|
||||
if (value)
|
||||
g_array_index (array, unsigned long, array_index) |= new_value_mask;
|
||||
else
|
||||
g_array_index (array, unsigned long, array_index) &= ~new_value_mask;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmask_set_bits (CoglBitmask *dst,
|
||||
const CoglBitmask *src)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (src))
|
||||
{
|
||||
GArray *src_array, *dst_array;
|
||||
int i;
|
||||
|
||||
if (!_cogl_bitmask_has_array (dst))
|
||||
_cogl_bitmask_convert_to_array (dst);
|
||||
|
||||
dst_array = (GArray *) *dst;
|
||||
src_array = (GArray *) *src;
|
||||
|
||||
if (dst_array->len < src_array->len)
|
||||
g_array_set_size (dst_array, src_array->len);
|
||||
|
||||
for (i = 0; i < src_array->len; i++)
|
||||
g_array_index (dst_array, unsigned long, i) |=
|
||||
g_array_index (src_array, unsigned long, i);
|
||||
}
|
||||
else if (_cogl_bitmask_has_array (dst))
|
||||
{
|
||||
GArray *dst_array;
|
||||
|
||||
dst_array = (GArray *) *dst;
|
||||
|
||||
g_array_index (dst_array, unsigned long, 0) |=
|
||||
_cogl_bitmask_to_bits (src);
|
||||
}
|
||||
else
|
||||
*dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) |
|
||||
_cogl_bitmask_to_bits (src));
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmask_set_range_in_array (CoglBitmask *bitmask,
|
||||
unsigned int n_bits,
|
||||
CoglBool value)
|
||||
{
|
||||
GArray *array;
|
||||
unsigned int array_index, bit_index;
|
||||
|
||||
if (n_bits == 0)
|
||||
return;
|
||||
|
||||
/* If the bitmask is not already an array then we need to allocate one */
|
||||
if (!_cogl_bitmask_has_array (bitmask))
|
||||
_cogl_bitmask_convert_to_array (bitmask);
|
||||
|
||||
array = (GArray *) *bitmask;
|
||||
|
||||
/* Get the array index of the top most value that will be touched */
|
||||
array_index = ARRAY_INDEX (n_bits - 1);
|
||||
/* Get the bit index of the top most value */
|
||||
bit_index = BIT_INDEX (n_bits - 1);
|
||||
/* Grow the array if necessary. This will clear the new data */
|
||||
if (array_index >= array->len)
|
||||
g_array_set_size (array, array_index + 1);
|
||||
|
||||
if (value)
|
||||
{
|
||||
/* Set the bits that are touching this index */
|
||||
g_array_index (array, unsigned long, array_index) |=
|
||||
~0UL >> (sizeof (unsigned long) * 8 - 1 - bit_index);
|
||||
|
||||
/* Set all of the bits in any lesser indices */
|
||||
memset (array->data, 0xff, sizeof (unsigned long) * array_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear the bits that are touching this index */
|
||||
g_array_index (array, unsigned long, array_index) &= ~1UL << bit_index;
|
||||
|
||||
/* Clear all of the bits in any lesser indices */
|
||||
memset (array->data, 0x00, sizeof (unsigned long) * array_index);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmask_xor_bits (CoglBitmask *dst,
|
||||
const CoglBitmask *src)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (src))
|
||||
{
|
||||
GArray *src_array, *dst_array;
|
||||
int i;
|
||||
|
||||
if (!_cogl_bitmask_has_array (dst))
|
||||
_cogl_bitmask_convert_to_array (dst);
|
||||
|
||||
dst_array = (GArray *) *dst;
|
||||
src_array = (GArray *) *src;
|
||||
|
||||
if (dst_array->len < src_array->len)
|
||||
g_array_set_size (dst_array, src_array->len);
|
||||
|
||||
for (i = 0; i < src_array->len; i++)
|
||||
g_array_index (dst_array, unsigned long, i) ^=
|
||||
g_array_index (src_array, unsigned long, i);
|
||||
}
|
||||
else if (_cogl_bitmask_has_array (dst))
|
||||
{
|
||||
GArray *dst_array;
|
||||
|
||||
dst_array = (GArray *) *dst;
|
||||
|
||||
g_array_index (dst_array, unsigned long, 0) ^=
|
||||
_cogl_bitmask_to_bits (src);
|
||||
}
|
||||
else
|
||||
*dst = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (dst) ^
|
||||
_cogl_bitmask_to_bits (src));
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask)
|
||||
{
|
||||
GArray *array = (GArray *) *bitmask;
|
||||
|
||||
memset (array->data, 0, sizeof (unsigned long) * array->len);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmask_foreach (const CoglBitmask *bitmask,
|
||||
CoglBitmaskForeachFunc func,
|
||||
void *user_data)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask))
|
||||
{
|
||||
GArray *array = (GArray *) *bitmask;
|
||||
const unsigned long *values = &g_array_index (array, unsigned long, 0);
|
||||
int bit_num;
|
||||
|
||||
COGL_FLAGS_FOREACH_START (values, array->len, bit_num)
|
||||
{
|
||||
if (!func (bit_num, user_data))
|
||||
return;
|
||||
}
|
||||
COGL_FLAGS_FOREACH_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long mask = _cogl_bitmask_to_bits (bitmask);
|
||||
int bit_num;
|
||||
|
||||
COGL_FLAGS_FOREACH_START (&mask, 1, bit_num)
|
||||
{
|
||||
if (!func (bit_num, user_data))
|
||||
return;
|
||||
}
|
||||
COGL_FLAGS_FOREACH_END;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_bitmask_set_flags_array (const CoglBitmask *bitmask,
|
||||
unsigned long *flags)
|
||||
{
|
||||
const GArray *array = (const GArray *) *bitmask;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < array->len; i++)
|
||||
flags[i] |= g_array_index (array, unsigned long, i);
|
||||
}
|
||||
|
||||
int
|
||||
_cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask)
|
||||
{
|
||||
const GArray *array = (const GArray *) *bitmask;
|
||||
int pop = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < array->len; i++)
|
||||
pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i));
|
||||
|
||||
return pop;
|
||||
}
|
||||
|
||||
int
|
||||
_cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask,
|
||||
int upto)
|
||||
{
|
||||
const GArray *array = (const GArray *) *bitmask;
|
||||
|
||||
if (upto >= array->len * sizeof (unsigned long) * 8)
|
||||
return _cogl_bitmask_popcount_in_array (bitmask);
|
||||
else
|
||||
{
|
||||
unsigned long top_mask;
|
||||
int array_index = ARRAY_INDEX (upto);
|
||||
int bit_index = BIT_INDEX (upto);
|
||||
int pop = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < array_index; i++)
|
||||
pop += _cogl_util_popcountl (g_array_index (array, unsigned long, i));
|
||||
|
||||
top_mask = g_array_index (array, unsigned long, array_index);
|
||||
|
||||
return pop + _cogl_util_popcountl (top_mask & ((1UL << bit_index) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int n_bits;
|
||||
int *bits;
|
||||
} CheckData;
|
||||
|
||||
static CoglBool
|
||||
check_bit (int bit_num, void *user_data)
|
||||
{
|
||||
CheckData *data = user_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data->n_bits; i++)
|
||||
if (data->bits[i] == bit_num)
|
||||
{
|
||||
data->bits[i] = -1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
verify_bits (const CoglBitmask *bitmask,
|
||||
...)
|
||||
{
|
||||
CheckData data;
|
||||
va_list ap, ap_copy;
|
||||
int i;
|
||||
|
||||
va_start (ap, bitmask);
|
||||
G_VA_COPY (ap_copy, ap);
|
||||
|
||||
for (data.n_bits = 0; va_arg (ap, int) != -1; data.n_bits++);
|
||||
|
||||
data.bits = alloca (data.n_bits * (sizeof (int)));
|
||||
|
||||
G_VA_COPY (ap, ap_copy);
|
||||
|
||||
for (i = 0; i < data.n_bits; i++)
|
||||
data.bits[i] = va_arg (ap, int);
|
||||
|
||||
_cogl_bitmask_foreach (bitmask, check_bit, &data);
|
||||
|
||||
for (i = 0; i < data.n_bits; i++)
|
||||
g_assert_cmpint (data.bits[i], ==, -1);
|
||||
|
||||
g_assert_cmpint (_cogl_bitmask_popcount (bitmask), ==, data.n_bits);
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
int upto_popcount = 0;
|
||||
int j;
|
||||
|
||||
G_VA_COPY (ap, ap_copy);
|
||||
|
||||
for (j = 0; j < data.n_bits; j++)
|
||||
if (va_arg (ap, int) < i)
|
||||
upto_popcount++;
|
||||
|
||||
g_assert_cmpint (_cogl_bitmask_popcount_upto (bitmask, i),
|
||||
==,
|
||||
upto_popcount);
|
||||
|
||||
G_VA_COPY (ap, ap_copy);
|
||||
|
||||
for (j = 0; j < data.n_bits; j++)
|
||||
if (va_arg (ap, int) == i)
|
||||
break;
|
||||
|
||||
g_assert_cmpint (_cogl_bitmask_get (bitmask, i), ==, (j < data.n_bits));
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST (check_bitmask_api,
|
||||
0 /* no requirements */,
|
||||
0 /* no failure cases */)
|
||||
{
|
||||
CoglBitmask bitmask;
|
||||
CoglBitmask other_bitmask;
|
||||
/* A dummy bit to make it use arrays sometimes */
|
||||
int dummy_bit;
|
||||
int i;
|
||||
|
||||
for (dummy_bit = -1; dummy_bit < 256; dummy_bit += 40)
|
||||
{
|
||||
_cogl_bitmask_init (&bitmask);
|
||||
_cogl_bitmask_init (&other_bitmask);
|
||||
|
||||
if (dummy_bit != -1)
|
||||
_cogl_bitmask_set (&bitmask, dummy_bit, TRUE);
|
||||
|
||||
verify_bits (&bitmask, dummy_bit, -1);
|
||||
|
||||
_cogl_bitmask_set (&bitmask, 1, TRUE);
|
||||
_cogl_bitmask_set (&bitmask, 4, TRUE);
|
||||
_cogl_bitmask_set (&bitmask, 5, TRUE);
|
||||
|
||||
verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1);
|
||||
|
||||
_cogl_bitmask_set (&bitmask, 4, FALSE);
|
||||
|
||||
verify_bits (&bitmask, 1, 5, dummy_bit, -1);
|
||||
|
||||
_cogl_bitmask_clear_all (&bitmask);
|
||||
|
||||
verify_bits (&bitmask, -1);
|
||||
|
||||
if (dummy_bit != -1)
|
||||
_cogl_bitmask_set (&bitmask, dummy_bit, TRUE);
|
||||
|
||||
verify_bits (&bitmask, dummy_bit, -1);
|
||||
|
||||
_cogl_bitmask_set (&bitmask, 1, TRUE);
|
||||
_cogl_bitmask_set (&bitmask, 4, TRUE);
|
||||
_cogl_bitmask_set (&bitmask, 5, TRUE);
|
||||
_cogl_bitmask_set (&other_bitmask, 5, TRUE);
|
||||
_cogl_bitmask_set (&other_bitmask, 6, TRUE);
|
||||
|
||||
_cogl_bitmask_set_bits (&bitmask, &other_bitmask);
|
||||
|
||||
verify_bits (&bitmask, 1, 4, 5, 6, dummy_bit, -1);
|
||||
verify_bits (&other_bitmask, 5, 6, -1);
|
||||
|
||||
_cogl_bitmask_set (&bitmask, 6, FALSE);
|
||||
|
||||
verify_bits (&bitmask, 1, 4, 5, dummy_bit, -1);
|
||||
|
||||
_cogl_bitmask_xor_bits (&bitmask, &other_bitmask);
|
||||
|
||||
verify_bits (&bitmask, 1, 4, 6, dummy_bit, -1);
|
||||
verify_bits (&other_bitmask, 5, 6, -1);
|
||||
|
||||
_cogl_bitmask_set_range (&bitmask, 5, TRUE);
|
||||
|
||||
verify_bits (&bitmask, 0, 1, 2, 3, 4, 6, dummy_bit, -1);
|
||||
|
||||
_cogl_bitmask_set_range (&bitmask, 4, FALSE);
|
||||
|
||||
verify_bits (&bitmask, 4, 6, dummy_bit, -1);
|
||||
|
||||
_cogl_bitmask_destroy (&other_bitmask);
|
||||
_cogl_bitmask_destroy (&bitmask);
|
||||
}
|
||||
|
||||
/* Extra tests for really long bitmasks */
|
||||
_cogl_bitmask_init (&bitmask);
|
||||
_cogl_bitmask_set_range (&bitmask, 400, TRUE);
|
||||
_cogl_bitmask_init (&other_bitmask);
|
||||
_cogl_bitmask_set (&other_bitmask, 5, TRUE);
|
||||
_cogl_bitmask_xor_bits (&bitmask, &other_bitmask);
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
g_assert_cmpint (_cogl_bitmask_get (&bitmask, i),
|
||||
==,
|
||||
(i == 5 ? FALSE :
|
||||
i < 400 ? TRUE :
|
||||
FALSE));
|
||||
|
||||
_cogl_bitmask_set_range (&other_bitmask, 500, TRUE);
|
||||
_cogl_bitmask_set_bits (&bitmask, &other_bitmask);
|
||||
|
||||
for (i = 0; i < 1024; i++)
|
||||
g_assert_cmpint (_cogl_bitmask_get (&bitmask, i), ==, (i < 500));
|
||||
}
|
312
cogl/cogl/cogl-bitmask.h
Normal file
312
cogl/cogl/cogl-bitmask.h
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Authors:
|
||||
* Neil Roberts <neil@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __COGL_BITMASK_H
|
||||
#define __COGL_BITMASK_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "cogl-util.h"
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* CoglBitmask implements a growable array of bits. A CoglBitmask can
|
||||
* be allocated on the stack but it must be initialised with
|
||||
* _cogl_bitmask_init() before use and then destroyed with
|
||||
* _cogl_bitmask_destroy(). A CoglBitmask will try to avoid allocating
|
||||
* any memory unless more than the number of bits in a long - 1 bits
|
||||
* are needed.
|
||||
*
|
||||
* Internally a CoglBitmask is a pointer. If the least significant bit
|
||||
* of the pointer is 1 then the rest of the bits are directly used as
|
||||
* part of the bitmask, otherwise it is a pointer to a GArray of
|
||||
* unsigned ints. This relies on the fact the g_malloc will return a
|
||||
* pointer aligned to at least two bytes (so that the least
|
||||
* significant bit of the address is always 0). It also assumes that
|
||||
* the size of a pointer is always greater than or equal to the size
|
||||
* of a long (although there is a compile time assert to verify this).
|
||||
*
|
||||
* If the maximum possible bit number in the set is known at compile
|
||||
* time, it may make more sense to use the macros in cogl-flags.h
|
||||
* instead of this type.
|
||||
*/
|
||||
|
||||
typedef struct _CoglBitmaskImaginaryType *CoglBitmask;
|
||||
|
||||
/* These are internal helper macros */
|
||||
#define _cogl_bitmask_to_number(bitmask) \
|
||||
((unsigned long) (*bitmask))
|
||||
#define _cogl_bitmask_to_bits(bitmask) \
|
||||
(_cogl_bitmask_to_number (bitmask) >> 1UL)
|
||||
/* The least significant bit is set to mark that no array has been
|
||||
allocated yet */
|
||||
#define _cogl_bitmask_from_bits(bits) \
|
||||
((void *) ((((unsigned long) (bits)) << 1UL) | 1UL))
|
||||
|
||||
/* Internal helper macro to determine whether this bitmask has a
|
||||
GArray allocated or whether the pointer is just used directly */
|
||||
#define _cogl_bitmask_has_array(bitmask) \
|
||||
(!(_cogl_bitmask_to_number (bitmask) & 1UL))
|
||||
|
||||
/* Number of bits we can use before needing to allocate an array */
|
||||
#define COGL_BITMASK_MAX_DIRECT_BITS (sizeof (unsigned long) * 8 - 1)
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_init:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
*
|
||||
* Initialises the cogl bitmask. This must be called before any other
|
||||
* bitmask functions are called. Initially all of the values are
|
||||
* zero
|
||||
*/
|
||||
#define _cogl_bitmask_init(bitmask) \
|
||||
G_STMT_START { *(bitmask) = _cogl_bitmask_from_bits (0); } G_STMT_END
|
||||
|
||||
CoglBool
|
||||
_cogl_bitmask_get_from_array (const CoglBitmask *bitmask,
|
||||
unsigned int bit_num);
|
||||
|
||||
void
|
||||
_cogl_bitmask_set_in_array (CoglBitmask *bitmask,
|
||||
unsigned int bit_num,
|
||||
CoglBool value);
|
||||
|
||||
void
|
||||
_cogl_bitmask_set_range_in_array (CoglBitmask *bitmask,
|
||||
unsigned int n_bits,
|
||||
CoglBool value);
|
||||
|
||||
void
|
||||
_cogl_bitmask_clear_all_in_array (CoglBitmask *bitmask);
|
||||
|
||||
void
|
||||
_cogl_bitmask_set_flags_array (const CoglBitmask *bitmask,
|
||||
unsigned long *flags);
|
||||
|
||||
int
|
||||
_cogl_bitmask_popcount_in_array (const CoglBitmask *bitmask);
|
||||
|
||||
int
|
||||
_cogl_bitmask_popcount_upto_in_array (const CoglBitmask *bitmask,
|
||||
int upto);
|
||||
|
||||
/*
|
||||
* cogl_bitmask_set_bits:
|
||||
* @dst: The bitmask to modify
|
||||
* @src: The bitmask to copy bits from
|
||||
*
|
||||
* This makes sure that all of the bits that are set in @src are also
|
||||
* set in @dst. Any unset bits in @src are left alone in @dst.
|
||||
*/
|
||||
void
|
||||
_cogl_bitmask_set_bits (CoglBitmask *dst,
|
||||
const CoglBitmask *src);
|
||||
|
||||
/*
|
||||
* cogl_bitmask_xor_bits:
|
||||
* @dst: The bitmask to modify
|
||||
* @src: The bitmask to copy bits from
|
||||
*
|
||||
* For every bit that is set in src, the corresponding bit in dst is
|
||||
* inverted.
|
||||
*/
|
||||
void
|
||||
_cogl_bitmask_xor_bits (CoglBitmask *dst,
|
||||
const CoglBitmask *src);
|
||||
|
||||
/* The foreach function can return FALSE to stop iteration */
|
||||
typedef CoglBool (* CoglBitmaskForeachFunc) (int bit_num, void *user_data);
|
||||
|
||||
/*
|
||||
* cogl_bitmask_foreach:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
* @func: A callback function
|
||||
* @user_data: A pointer to pass to the callback
|
||||
*
|
||||
* This calls @func for each bit that is set in @bitmask.
|
||||
*/
|
||||
void
|
||||
_cogl_bitmask_foreach (const CoglBitmask *bitmask,
|
||||
CoglBitmaskForeachFunc func,
|
||||
void *user_data);
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_get:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
* @bit_num: A bit number
|
||||
*
|
||||
* Return value: whether bit number @bit_num is set in @bitmask
|
||||
*/
|
||||
static inline CoglBool
|
||||
_cogl_bitmask_get (const CoglBitmask *bitmask, unsigned int bit_num)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask))
|
||||
return _cogl_bitmask_get_from_array (bitmask, bit_num);
|
||||
else if (bit_num >= COGL_BITMASK_MAX_DIRECT_BITS)
|
||||
return FALSE;
|
||||
else
|
||||
return !!(_cogl_bitmask_to_bits (bitmask) & (1UL << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_set:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
* @bit_num: A bit number
|
||||
* @value: The new value
|
||||
*
|
||||
* Sets or resets a bit number @bit_num in @bitmask according to @value.
|
||||
*/
|
||||
static inline void
|
||||
_cogl_bitmask_set (CoglBitmask *bitmask, unsigned int bit_num, CoglBool value)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask) ||
|
||||
bit_num >= COGL_BITMASK_MAX_DIRECT_BITS)
|
||||
_cogl_bitmask_set_in_array (bitmask, bit_num, value);
|
||||
else if (value)
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) |
|
||||
(1UL << bit_num));
|
||||
else
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) &
|
||||
~(1UL << bit_num));
|
||||
}
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_set_range:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
* @n_bits: The number of bits to set
|
||||
* @value: The value to set
|
||||
*
|
||||
* Sets the first @n_bits in @bitmask to @value.
|
||||
*/
|
||||
static inline void
|
||||
_cogl_bitmask_set_range (CoglBitmask *bitmask,
|
||||
unsigned int n_bits,
|
||||
CoglBool value)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask) ||
|
||||
n_bits > COGL_BITMASK_MAX_DIRECT_BITS)
|
||||
_cogl_bitmask_set_range_in_array (bitmask, n_bits, value);
|
||||
else if (value)
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) |
|
||||
~(~0UL << n_bits));
|
||||
else
|
||||
*bitmask = _cogl_bitmask_from_bits (_cogl_bitmask_to_bits (bitmask) &
|
||||
(~0UL << n_bits));
|
||||
}
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_destroy:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
*
|
||||
* Destroys any resources allocated by the bitmask
|
||||
*/
|
||||
static inline void
|
||||
_cogl_bitmask_destroy (CoglBitmask *bitmask)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask))
|
||||
g_array_free ((GArray *) *bitmask, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_clear_all:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
*
|
||||
* Clears all the bits in a bitmask without destroying any resources.
|
||||
*/
|
||||
static inline void
|
||||
_cogl_bitmask_clear_all (CoglBitmask *bitmask)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask))
|
||||
_cogl_bitmask_clear_all_in_array (bitmask);
|
||||
else
|
||||
*bitmask = _cogl_bitmask_from_bits (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_set_flags:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
* @flags: An array of flags
|
||||
*
|
||||
* Bitwise or's the bits from @bitmask into the flags array (see
|
||||
* cogl-flags) pointed to by @flags.
|
||||
*/
|
||||
static inline void
|
||||
_cogl_bitmask_set_flags (const CoglBitmask *bitmask,
|
||||
unsigned long *flags)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask))
|
||||
_cogl_bitmask_set_flags_array (bitmask, flags);
|
||||
else
|
||||
flags[0] |= _cogl_bitmask_to_bits (bitmask);
|
||||
}
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_popcount:
|
||||
* @bitmask: A pointer to a bitmask
|
||||
*
|
||||
* Counts the number of bits that are set in the bitmask.
|
||||
*
|
||||
* Return value: the number of bits set in @bitmask.
|
||||
*/
|
||||
static inline int
|
||||
_cogl_bitmask_popcount (const CoglBitmask *bitmask)
|
||||
{
|
||||
return (_cogl_bitmask_has_array (bitmask) ?
|
||||
_cogl_bitmask_popcount_in_array (bitmask) :
|
||||
_cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask)));
|
||||
}
|
||||
|
||||
/*
|
||||
* _cogl_bitmask_popcount:
|
||||
* @Bitmask: A pointer to a bitmask
|
||||
* @upto: The maximum bit index to consider
|
||||
*
|
||||
* Counts the number of bits that are set and have an index which is
|
||||
* less than @upto.
|
||||
*
|
||||
* Return value: the number of bits set in @bitmask that are less than @upto.
|
||||
*/
|
||||
static inline int
|
||||
_cogl_bitmask_popcount_upto (const CoglBitmask *bitmask,
|
||||
int upto)
|
||||
{
|
||||
if (_cogl_bitmask_has_array (bitmask))
|
||||
return _cogl_bitmask_popcount_upto_in_array (bitmask, upto);
|
||||
else if (upto >= COGL_BITMASK_MAX_DIRECT_BITS)
|
||||
return _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask));
|
||||
else
|
||||
return _cogl_util_popcountl (_cogl_bitmask_to_bits (bitmask) &
|
||||
((1UL << upto) - 1));
|
||||
}
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_BITMASK_H */
|
1003
cogl/cogl/cogl-blend-string.c
Normal file
1003
cogl/cogl/cogl-blend-string.c
Normal file
File diff suppressed because it is too large
Load Diff
144
cogl/cogl/cogl-blend-string.h
Normal file
144
cogl/cogl/cogl-blend-string.h
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef COGL_BLEND_STRING_H
|
||||
#define COGL_BLEND_STRING_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
|
||||
typedef enum _CoglBlendStringContext
|
||||
{
|
||||
COGL_BLEND_STRING_CONTEXT_BLENDING,
|
||||
COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE
|
||||
} CoglBlendStringContext;
|
||||
|
||||
/* NB: debug stringify code will get upset if these
|
||||
* are re-ordered */
|
||||
typedef enum _CoglBlendStringChannelMask
|
||||
{
|
||||
COGL_BLEND_STRING_CHANNEL_MASK_RGB,
|
||||
COGL_BLEND_STRING_CHANNEL_MASK_ALPHA,
|
||||
COGL_BLEND_STRING_CHANNEL_MASK_RGBA
|
||||
} CoglBlendStringChannelMask;
|
||||
|
||||
typedef enum _CoglBlendStringColorSourceType
|
||||
{
|
||||
/* blending */
|
||||
COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR,
|
||||
COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR,
|
||||
|
||||
/* shared */
|
||||
COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT,
|
||||
|
||||
/* texture combining */
|
||||
COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE,
|
||||
COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N,
|
||||
COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY,
|
||||
COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS
|
||||
} CoglBlendStringColorSourceType;
|
||||
|
||||
typedef struct _CoglBlendStringColorSourceInfo
|
||||
{
|
||||
CoglBlendStringColorSourceType type;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
} CoglBlendStringColorSourceInfo;
|
||||
|
||||
typedef struct _CoglBlendStringColorSource
|
||||
{
|
||||
CoglBool is_zero;
|
||||
const CoglBlendStringColorSourceInfo *info;
|
||||
int texture; /* for the TEXTURE_N color source */
|
||||
CoglBool one_minus;
|
||||
CoglBlendStringChannelMask mask;
|
||||
} CoglBlendStringColorSource;
|
||||
|
||||
typedef struct _CoglBlendStringFactor
|
||||
{
|
||||
CoglBool is_one;
|
||||
CoglBool is_src_alpha_saturate;
|
||||
CoglBool is_color;
|
||||
CoglBlendStringColorSource source;
|
||||
} CoglBlendStringFactor;
|
||||
|
||||
typedef struct _CoglBlendStringArgument
|
||||
{
|
||||
CoglBlendStringColorSource source;
|
||||
CoglBlendStringFactor factor;
|
||||
} CoglBlendStringArgument;
|
||||
|
||||
typedef enum _CoglBlendStringFunctionType
|
||||
{
|
||||
/* shared */
|
||||
COGL_BLEND_STRING_FUNCTION_ADD,
|
||||
|
||||
/* texture combine only */
|
||||
COGL_BLEND_STRING_FUNCTION_REPLACE,
|
||||
COGL_BLEND_STRING_FUNCTION_MODULATE,
|
||||
COGL_BLEND_STRING_FUNCTION_ADD_SIGNED,
|
||||
COGL_BLEND_STRING_FUNCTION_INTERPOLATE,
|
||||
COGL_BLEND_STRING_FUNCTION_SUBTRACT,
|
||||
COGL_BLEND_STRING_FUNCTION_DOT3_RGB,
|
||||
COGL_BLEND_STRING_FUNCTION_DOT3_RGBA
|
||||
} CoglBlendStringFunctionType;
|
||||
|
||||
typedef struct _CoglBlendStringFunctionInfo
|
||||
{
|
||||
enum _CoglBlendStringFunctionType type;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
int argc;
|
||||
} CoglBlendStringFunctionInfo;
|
||||
|
||||
typedef struct _CoglBlendStringStatement
|
||||
{
|
||||
CoglBlendStringChannelMask mask;
|
||||
const CoglBlendStringFunctionInfo *function;
|
||||
CoglBlendStringArgument args[3];
|
||||
} CoglBlendStringStatement;
|
||||
|
||||
|
||||
CoglBool
|
||||
_cogl_blend_string_compile (const char *string,
|
||||
CoglBlendStringContext context,
|
||||
CoglBlendStringStatement *statements,
|
||||
CoglError **error);
|
||||
|
||||
void
|
||||
_cogl_blend_string_split_rgba_statement (CoglBlendStringStatement *statement,
|
||||
CoglBlendStringStatement *rgb,
|
||||
CoglBlendStringStatement *a);
|
||||
|
||||
#endif /* COGL_BLEND_STRING_H */
|
||||
|
438
cogl/cogl/cogl-blit.c
Normal file
438
cogl/cogl/cogl-blit.c
Normal file
@ -0,0 +1,438 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-blit.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-texture-private.h"
|
||||
#include "cogl-texture-2d-private.h"
|
||||
#include "cogl-private.h"
|
||||
#include "cogl1-context.h"
|
||||
|
||||
static const CoglBlitMode *_cogl_blit_default_mode = NULL;
|
||||
|
||||
static CoglBool
|
||||
_cogl_blit_texture_render_begin (CoglBlitData *data)
|
||||
{
|
||||
CoglContext *ctx = data->src_tex->context;
|
||||
CoglOffscreen *offscreen;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipeline *pipeline;
|
||||
unsigned int dst_width, dst_height;
|
||||
CoglError *ignore_error = NULL;
|
||||
|
||||
offscreen = _cogl_offscreen_new_with_texture_full
|
||||
(data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */);
|
||||
|
||||
fb = COGL_FRAMEBUFFER (offscreen);
|
||||
if (!cogl_framebuffer_allocate (fb, &ignore_error))
|
||||
{
|
||||
cogl_error_free (ignore_error);
|
||||
cogl_object_unref (fb);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data->dest_fb = fb;
|
||||
|
||||
dst_width = cogl_texture_get_width (data->dst_tex);
|
||||
dst_height = cogl_texture_get_height (data->dst_tex);
|
||||
|
||||
/* Set up an orthographic projection so we can use pixel
|
||||
coordinates to render to the texture */
|
||||
cogl_framebuffer_orthographic (fb,
|
||||
0, 0, dst_width, dst_height,
|
||||
-1 /* near */, 1 /* far */);
|
||||
|
||||
/* We cache a pipeline used for migrating on to the context so
|
||||
that it doesn't have to continuously regenerate a shader
|
||||
program */
|
||||
if (ctx->blit_texture_pipeline == NULL)
|
||||
{
|
||||
ctx->blit_texture_pipeline = cogl_pipeline_new (ctx);
|
||||
|
||||
cogl_pipeline_set_layer_filters (ctx->blit_texture_pipeline, 0,
|
||||
COGL_PIPELINE_FILTER_NEAREST,
|
||||
COGL_PIPELINE_FILTER_NEAREST);
|
||||
|
||||
/* Disable blending by just directly taking the contents of the
|
||||
source texture */
|
||||
cogl_pipeline_set_blend (ctx->blit_texture_pipeline,
|
||||
"RGBA = ADD(SRC_COLOR, 0)",
|
||||
NULL);
|
||||
}
|
||||
|
||||
pipeline = ctx->blit_texture_pipeline;
|
||||
|
||||
cogl_pipeline_set_layer_texture (pipeline, 0, data->src_tex);
|
||||
|
||||
data->pipeline = pipeline;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_texture_render_blit (CoglBlitData *data,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cogl_framebuffer_draw_textured_rectangle (data->dest_fb,
|
||||
data->pipeline,
|
||||
dst_x, dst_y,
|
||||
dst_x + width,
|
||||
dst_y + height,
|
||||
src_x / (float) data->src_width,
|
||||
src_y / (float) data->src_height,
|
||||
(src_x + width) /
|
||||
(float) data->src_width,
|
||||
(src_y + height) /
|
||||
(float) data->src_height);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_texture_render_end (CoglBlitData *data)
|
||||
{
|
||||
CoglContext *ctx = data->src_tex->context;
|
||||
|
||||
/* Attach the target texture to the texture render pipeline so that
|
||||
we don't keep a reference to the source texture forever. This is
|
||||
assuming that the destination texture will live for a long time
|
||||
which is currently the case when cogl_blit_* is used from the
|
||||
atlas code. It may be better in future to keep around a set of
|
||||
dummy 1x1 textures for each texture target that we could bind
|
||||
instead. This would also be useful when using a pipeline as a
|
||||
hash table key such as for the ARBfp program cache. */
|
||||
cogl_pipeline_set_layer_texture (ctx->blit_texture_pipeline, 0,
|
||||
data->dst_tex);
|
||||
|
||||
cogl_object_unref (data->dest_fb);
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
_cogl_blit_framebuffer_begin (CoglBlitData *data)
|
||||
{
|
||||
CoglContext *ctx = data->src_tex->context;
|
||||
CoglOffscreen *dst_offscreen = NULL, *src_offscreen = NULL;
|
||||
CoglFramebuffer *dst_fb, *src_fb;
|
||||
CoglError *ignore_error = NULL;
|
||||
|
||||
/* We can only blit between FBOs if both textures are the same
|
||||
format and the blit framebuffer extension is supported */
|
||||
if ((_cogl_texture_get_format (data->src_tex) & ~COGL_A_BIT) !=
|
||||
(_cogl_texture_get_format (data->dst_tex) & ~COGL_A_BIT) ||
|
||||
!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT))
|
||||
return FALSE;
|
||||
|
||||
dst_offscreen = _cogl_offscreen_new_with_texture_full
|
||||
(data->dst_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */);
|
||||
|
||||
dst_fb = COGL_FRAMEBUFFER (dst_offscreen);
|
||||
if (!cogl_framebuffer_allocate (dst_fb, &ignore_error))
|
||||
{
|
||||
cogl_error_free (ignore_error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
src_offscreen= _cogl_offscreen_new_with_texture_full
|
||||
(data->src_tex,
|
||||
COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
|
||||
0 /* level */);
|
||||
|
||||
src_fb = COGL_FRAMEBUFFER (src_offscreen);
|
||||
if (!cogl_framebuffer_allocate (src_fb, &ignore_error))
|
||||
{
|
||||
cogl_error_free (ignore_error);
|
||||
goto error;
|
||||
}
|
||||
|
||||
data->src_fb = src_fb;
|
||||
data->dest_fb = dst_fb;
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
|
||||
if (dst_offscreen)
|
||||
cogl_object_unref (dst_offscreen);
|
||||
if (src_offscreen)
|
||||
cogl_object_unref (src_offscreen);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_framebuffer_blit (CoglBlitData *data,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
_cogl_blit_framebuffer (data->src_fb,
|
||||
data->dest_fb,
|
||||
src_x, src_y,
|
||||
dst_x, dst_y,
|
||||
width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_framebuffer_end (CoglBlitData *data)
|
||||
{
|
||||
cogl_object_unref (data->src_fb);
|
||||
cogl_object_unref (data->dest_fb);
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
_cogl_blit_copy_tex_sub_image_begin (CoglBlitData *data)
|
||||
{
|
||||
CoglOffscreen *offscreen;
|
||||
CoglFramebuffer *fb;
|
||||
CoglError *ignore_error = NULL;
|
||||
|
||||
/* This will only work if the target texture is a CoglTexture2D */
|
||||
if (!cogl_is_texture_2d (data->dst_tex))
|
||||
return FALSE;
|
||||
|
||||
offscreen = _cogl_offscreen_new_with_texture_full
|
||||
(data->src_tex, COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL, 0 /* level */);
|
||||
|
||||
fb = COGL_FRAMEBUFFER (offscreen);
|
||||
if (!cogl_framebuffer_allocate (fb, &ignore_error))
|
||||
{
|
||||
cogl_error_free (ignore_error);
|
||||
cogl_object_unref (fb);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data->src_fb = fb;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_copy_tex_sub_image_blit (CoglBlitData *data,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
_cogl_texture_2d_copy_from_framebuffer (COGL_TEXTURE_2D (data->dst_tex),
|
||||
src_x, src_y,
|
||||
width, height,
|
||||
data->src_fb,
|
||||
dst_x, dst_y,
|
||||
0); /* level */
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_copy_tex_sub_image_end (CoglBlitData *data)
|
||||
{
|
||||
cogl_object_unref (data->src_fb);
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
_cogl_blit_get_tex_data_begin (CoglBlitData *data)
|
||||
{
|
||||
data->format = _cogl_texture_get_format (data->src_tex);
|
||||
data->bpp = _cogl_pixel_format_get_bytes_per_pixel (data->format);
|
||||
|
||||
data->image_data = g_malloc (data->bpp * data->src_width *
|
||||
data->src_height);
|
||||
cogl_texture_get_data (data->src_tex, data->format,
|
||||
data->src_width * data->bpp, data->image_data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_get_tex_data_blit (CoglBlitData *data,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
CoglError *ignore = NULL;
|
||||
int rowstride = data->src_width * data->bpp;
|
||||
int offset = rowstride * src_y + src_x * data->bpp;
|
||||
|
||||
_cogl_texture_set_region (data->dst_tex,
|
||||
width, height,
|
||||
data->format,
|
||||
rowstride,
|
||||
data->image_data + offset,
|
||||
dst_x, dst_y,
|
||||
0, /* level */
|
||||
&ignore);
|
||||
/* TODO: support chaining up errors during the blit */
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_blit_get_tex_data_end (CoglBlitData *data)
|
||||
{
|
||||
g_free (data->image_data);
|
||||
}
|
||||
|
||||
/* These should be specified in order of preference */
|
||||
static const CoglBlitMode
|
||||
_cogl_blit_modes[] =
|
||||
{
|
||||
{
|
||||
"texture-render",
|
||||
_cogl_blit_texture_render_begin,
|
||||
_cogl_blit_texture_render_blit,
|
||||
_cogl_blit_texture_render_end
|
||||
},
|
||||
{
|
||||
"framebuffer",
|
||||
_cogl_blit_framebuffer_begin,
|
||||
_cogl_blit_framebuffer_blit,
|
||||
_cogl_blit_framebuffer_end
|
||||
},
|
||||
{
|
||||
"copy-tex-sub-image",
|
||||
_cogl_blit_copy_tex_sub_image_begin,
|
||||
_cogl_blit_copy_tex_sub_image_blit,
|
||||
_cogl_blit_copy_tex_sub_image_end
|
||||
},
|
||||
{
|
||||
"get-tex-data",
|
||||
_cogl_blit_get_tex_data_begin,
|
||||
_cogl_blit_get_tex_data_blit,
|
||||
_cogl_blit_get_tex_data_end
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
_cogl_blit_begin (CoglBlitData *data,
|
||||
CoglTexture *dst_tex,
|
||||
CoglTexture *src_tex)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (_cogl_blit_default_mode == NULL)
|
||||
{
|
||||
const char *default_mode_string;
|
||||
|
||||
/* Allow the default to be specified with an environment
|
||||
variable. For the time being these functions are only used
|
||||
when blitting between atlas textures so the environment
|
||||
variable is named to be specific to the atlas code. If we
|
||||
want to use the code in other places we should create another
|
||||
environment variable for each specific use case */
|
||||
if ((default_mode_string = g_getenv ("COGL_ATLAS_DEFAULT_BLIT_MODE")))
|
||||
{
|
||||
for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++)
|
||||
if (!strcmp (_cogl_blit_modes[i].name, default_mode_string))
|
||||
{
|
||||
_cogl_blit_default_mode = _cogl_blit_modes + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= G_N_ELEMENTS (_cogl_blit_modes))
|
||||
{
|
||||
g_warning ("Unknown blit mode %s", default_mode_string);
|
||||
_cogl_blit_default_mode = _cogl_blit_modes;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Default to the first blit mode */
|
||||
_cogl_blit_default_mode = _cogl_blit_modes;
|
||||
}
|
||||
|
||||
memset (data, 0, sizeof (CoglBlitData));
|
||||
|
||||
data->dst_tex = dst_tex;
|
||||
data->src_tex = src_tex;
|
||||
|
||||
data->src_width = cogl_texture_get_width (src_tex);
|
||||
data->src_height = cogl_texture_get_height (src_tex);
|
||||
|
||||
/* Try the default blit mode first */
|
||||
if (!_cogl_blit_default_mode->begin_func (data))
|
||||
{
|
||||
COGL_NOTE (ATLAS, "Failed to set up blit mode %s",
|
||||
_cogl_blit_default_mode->name);
|
||||
|
||||
/* Try all of the other modes in order */
|
||||
for (i = 0; i < G_N_ELEMENTS (_cogl_blit_modes); i++)
|
||||
if (_cogl_blit_modes + i != _cogl_blit_default_mode &&
|
||||
_cogl_blit_modes[i].begin_func (data))
|
||||
{
|
||||
/* Use this mode as the default from now on */
|
||||
_cogl_blit_default_mode = _cogl_blit_modes + i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
COGL_NOTE (ATLAS,
|
||||
"Failed to set up blit mode %s",
|
||||
_cogl_blit_modes[i].name);
|
||||
|
||||
/* The last blit mode can't fail so this should never happen */
|
||||
_COGL_RETURN_IF_FAIL (i < G_N_ELEMENTS (_cogl_blit_modes));
|
||||
}
|
||||
|
||||
data->blit_mode = _cogl_blit_default_mode;
|
||||
|
||||
COGL_NOTE (ATLAS, "Setup blit using %s", _cogl_blit_default_mode->name);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_blit (CoglBlitData *data,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
data->blit_mode->blit_func (data, src_x, src_y, dst_x, dst_y, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_blit_end (CoglBlitData *data)
|
||||
{
|
||||
data->blit_mode->end_func (data);
|
||||
}
|
101
cogl/cogl/cogl-blit.h
Normal file
101
cogl/cogl/cogl-blit.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __COGL_BLIT_H
|
||||
#define __COGL_BLIT_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-texture.h"
|
||||
#include "cogl-framebuffer.h"
|
||||
|
||||
/* This structures and functions are used when a series of blits needs
|
||||
to be performed between two textures. In this case there are
|
||||
multiple methods we can use, most of which involve transferring
|
||||
between an FBO bound to the texture. */
|
||||
|
||||
typedef struct _CoglBlitData CoglBlitData;
|
||||
|
||||
typedef CoglBool (* CoglBlitBeginFunc) (CoglBlitData *data);
|
||||
typedef void (* CoglBlitEndFunc) (CoglBlitData *data);
|
||||
|
||||
typedef void (* CoglBlitFunc) (CoglBlitData *data,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
CoglBlitBeginFunc begin_func;
|
||||
CoglBlitFunc blit_func;
|
||||
CoglBlitEndFunc end_func;
|
||||
} CoglBlitMode;
|
||||
|
||||
struct _CoglBlitData
|
||||
{
|
||||
CoglTexture *src_tex, *dst_tex;
|
||||
|
||||
unsigned int src_width;
|
||||
unsigned int src_height;
|
||||
|
||||
const CoglBlitMode *blit_mode;
|
||||
|
||||
/* If we're not using an FBO then we g_malloc a buffer and copy the
|
||||
complete texture data in */
|
||||
unsigned char *image_data;
|
||||
CoglPixelFormat format;
|
||||
|
||||
int bpp;
|
||||
|
||||
CoglFramebuffer *src_fb;
|
||||
CoglFramebuffer *dest_fb;
|
||||
CoglPipeline *pipeline;
|
||||
};
|
||||
|
||||
void
|
||||
_cogl_blit_begin (CoglBlitData *data,
|
||||
CoglTexture *dst_tex,
|
||||
CoglTexture *src_tex);
|
||||
|
||||
void
|
||||
_cogl_blit (CoglBlitData *data,
|
||||
int src_x,
|
||||
int src_y,
|
||||
int dst_x,
|
||||
int dst_y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void
|
||||
_cogl_blit_end (CoglBlitData *data);
|
||||
|
||||
#endif /* __COGL_BLIT_H */
|
377
cogl/cogl/cogl-boxed-value.c
Normal file
377
cogl/cogl/cogl-boxed-value.c
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "cogl-boxed-value.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-util-gl-private.h"
|
||||
|
||||
CoglBool
|
||||
_cogl_boxed_value_equal (const CoglBoxedValue *bva,
|
||||
const CoglBoxedValue *bvb)
|
||||
{
|
||||
const void *pa, *pb;
|
||||
|
||||
if (bva->type != bvb->type)
|
||||
return FALSE;
|
||||
|
||||
switch (bva->type)
|
||||
{
|
||||
case COGL_BOXED_NONE:
|
||||
return TRUE;
|
||||
|
||||
case COGL_BOXED_INT:
|
||||
if (bva->size != bvb->size || bva->count != bvb->count)
|
||||
return FALSE;
|
||||
|
||||
if (bva->count == 1)
|
||||
{
|
||||
pa = bva->v.int_value;
|
||||
pb = bvb->v.int_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
pa = bva->v.int_array;
|
||||
pb = bvb->v.int_array;
|
||||
}
|
||||
|
||||
return !memcmp (pa, pb, sizeof (int) * bva->size * bva->count);
|
||||
|
||||
case COGL_BOXED_FLOAT:
|
||||
if (bva->size != bvb->size || bva->count != bvb->count)
|
||||
return FALSE;
|
||||
|
||||
if (bva->count == 1)
|
||||
{
|
||||
pa = bva->v.float_value;
|
||||
pb = bvb->v.float_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
pa = bva->v.float_array;
|
||||
pb = bvb->v.float_array;
|
||||
}
|
||||
|
||||
return !memcmp (pa, pb, sizeof (float) * bva->size * bva->count);
|
||||
|
||||
case COGL_BOXED_MATRIX:
|
||||
if (bva->size != bvb->size ||
|
||||
bva->count != bvb->count)
|
||||
return FALSE;
|
||||
|
||||
if (bva->count == 1)
|
||||
{
|
||||
pa = bva->v.matrix;
|
||||
pb = bvb->v.matrix;
|
||||
}
|
||||
else
|
||||
{
|
||||
pa = bva->v.array;
|
||||
pb = bvb->v.array;
|
||||
}
|
||||
|
||||
return !memcmp (pa, pb,
|
||||
sizeof (float) * bva->size * bva->size * bva->count);
|
||||
}
|
||||
|
||||
g_warn_if_reached ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_boxed_value_tranpose (float *dst,
|
||||
int size,
|
||||
const float *src)
|
||||
{
|
||||
int y, x;
|
||||
|
||||
/* If the value is transposed we'll just transpose it now as it
|
||||
* is copied into the boxed value instead of passing TRUE to
|
||||
* glUniformMatrix because that is not supported on GLES and it
|
||||
* doesn't seem like the GL driver would be able to do anything
|
||||
* much smarter than this anyway */
|
||||
|
||||
for (y = 0; y < size; y++)
|
||||
for (x = 0; x < size; x++)
|
||||
*(dst++) = src[y + x * size];
|
||||
}
|
||||
|
||||
static void
|
||||
_cogl_boxed_value_set_x (CoglBoxedValue *bv,
|
||||
int size,
|
||||
int count,
|
||||
CoglBoxedType type,
|
||||
size_t value_size,
|
||||
const void *value,
|
||||
CoglBool transpose)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
if (bv->count > 1)
|
||||
g_free (bv->v.array);
|
||||
|
||||
if (transpose)
|
||||
_cogl_boxed_value_tranpose (bv->v.float_value,
|
||||
size,
|
||||
value);
|
||||
else
|
||||
memcpy (bv->v.float_value, value, value_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bv->count > 1)
|
||||
{
|
||||
if (bv->count != count ||
|
||||
bv->size != size ||
|
||||
bv->type != type)
|
||||
{
|
||||
g_free (bv->v.array);
|
||||
bv->v.array = g_malloc (count * value_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
bv->v.array = g_malloc (count * value_size);
|
||||
|
||||
if (transpose)
|
||||
{
|
||||
int value_num;
|
||||
|
||||
for (value_num = 0; value_num < count; value_num++)
|
||||
_cogl_boxed_value_tranpose (bv->v.float_array +
|
||||
value_num * size * size,
|
||||
size,
|
||||
(const float *) value +
|
||||
value_num * size * size);
|
||||
}
|
||||
else
|
||||
memcpy (bv->v.array, value, count * value_size);
|
||||
}
|
||||
|
||||
bv->type = type;
|
||||
bv->size = size;
|
||||
bv->count = count;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_1f (CoglBoxedValue *bv,
|
||||
float value)
|
||||
{
|
||||
_cogl_boxed_value_set_x (bv,
|
||||
1, 1, COGL_BOXED_FLOAT,
|
||||
sizeof (float), &value, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_1i (CoglBoxedValue *bv,
|
||||
int value)
|
||||
{
|
||||
_cogl_boxed_value_set_x (bv,
|
||||
1, 1, COGL_BOXED_INT,
|
||||
sizeof (int), &value, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_float (CoglBoxedValue *bv,
|
||||
int n_components,
|
||||
int count,
|
||||
const float *value)
|
||||
{
|
||||
_cogl_boxed_value_set_x (bv,
|
||||
n_components, count,
|
||||
COGL_BOXED_FLOAT,
|
||||
sizeof (float) * n_components, value, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_int (CoglBoxedValue *bv,
|
||||
int n_components,
|
||||
int count,
|
||||
const int *value)
|
||||
{
|
||||
_cogl_boxed_value_set_x (bv,
|
||||
n_components, count,
|
||||
COGL_BOXED_INT,
|
||||
sizeof (int) * n_components, value, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_matrix (CoglBoxedValue *bv,
|
||||
int dimensions,
|
||||
int count,
|
||||
CoglBool transpose,
|
||||
const float *value)
|
||||
{
|
||||
_cogl_boxed_value_set_x (bv,
|
||||
dimensions, count,
|
||||
COGL_BOXED_MATRIX,
|
||||
sizeof (float) * dimensions * dimensions,
|
||||
value,
|
||||
transpose);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_copy (CoglBoxedValue *dst,
|
||||
const CoglBoxedValue *src)
|
||||
{
|
||||
*dst = *src;
|
||||
|
||||
if (src->count > 1)
|
||||
{
|
||||
switch (src->type)
|
||||
{
|
||||
case COGL_BOXED_NONE:
|
||||
break;
|
||||
|
||||
case COGL_BOXED_INT:
|
||||
dst->v.int_array = g_memdup (src->v.int_array,
|
||||
src->size * src->count * sizeof (int));
|
||||
break;
|
||||
|
||||
case COGL_BOXED_FLOAT:
|
||||
dst->v.float_array = g_memdup (src->v.float_array,
|
||||
src->size *
|
||||
src->count *
|
||||
sizeof (float));
|
||||
break;
|
||||
|
||||
case COGL_BOXED_MATRIX:
|
||||
dst->v.float_array = g_memdup (src->v.float_array,
|
||||
src->size * src->size *
|
||||
src->count * sizeof (float));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_destroy (CoglBoxedValue *bv)
|
||||
{
|
||||
if (bv->count > 1)
|
||||
g_free (bv->v.array);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_uniform (CoglContext *ctx,
|
||||
GLint location,
|
||||
const CoglBoxedValue *value)
|
||||
{
|
||||
switch (value->type)
|
||||
{
|
||||
case COGL_BOXED_NONE:
|
||||
break;
|
||||
|
||||
case COGL_BOXED_INT:
|
||||
{
|
||||
const int *ptr;
|
||||
|
||||
if (value->count == 1)
|
||||
ptr = value->v.int_value;
|
||||
else
|
||||
ptr = value->v.int_array;
|
||||
|
||||
switch (value->size)
|
||||
{
|
||||
case 1:
|
||||
GE( ctx, glUniform1iv (location, value->count, ptr) );
|
||||
break;
|
||||
case 2:
|
||||
GE( ctx, glUniform2iv (location, value->count, ptr) );
|
||||
break;
|
||||
case 3:
|
||||
GE( ctx, glUniform3iv (location, value->count, ptr) );
|
||||
break;
|
||||
case 4:
|
||||
GE( ctx, glUniform4iv (location, value->count, ptr) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case COGL_BOXED_FLOAT:
|
||||
{
|
||||
const float *ptr;
|
||||
|
||||
if (value->count == 1)
|
||||
ptr = value->v.float_value;
|
||||
else
|
||||
ptr = value->v.float_array;
|
||||
|
||||
switch (value->size)
|
||||
{
|
||||
case 1:
|
||||
GE( ctx, glUniform1fv (location, value->count, ptr) );
|
||||
break;
|
||||
case 2:
|
||||
GE( ctx, glUniform2fv (location, value->count, ptr) );
|
||||
break;
|
||||
case 3:
|
||||
GE( ctx, glUniform3fv (location, value->count, ptr) );
|
||||
break;
|
||||
case 4:
|
||||
GE( ctx, glUniform4fv (location, value->count, ptr) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case COGL_BOXED_MATRIX:
|
||||
{
|
||||
const float *ptr;
|
||||
|
||||
if (value->count == 1)
|
||||
ptr = value->v.matrix;
|
||||
else
|
||||
ptr = value->v.float_array;
|
||||
|
||||
switch (value->size)
|
||||
{
|
||||
case 2:
|
||||
GE( ctx, glUniformMatrix2fv (location, value->count,
|
||||
FALSE, ptr) );
|
||||
break;
|
||||
case 3:
|
||||
GE( ctx, glUniformMatrix3fv (location, value->count,
|
||||
FALSE, ptr) );
|
||||
break;
|
||||
case 4:
|
||||
GE( ctx, glUniformMatrix4fv (location, value->count,
|
||||
FALSE, ptr) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
117
cogl/cogl/cogl-boxed-value.h
Normal file
117
cogl/cogl/cogl-boxed-value.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __COGL_BOXED_VALUE_H
|
||||
#define __COGL_BOXED_VALUE_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "cogl-context.h"
|
||||
|
||||
typedef enum {
|
||||
COGL_BOXED_NONE,
|
||||
COGL_BOXED_INT,
|
||||
COGL_BOXED_FLOAT,
|
||||
COGL_BOXED_MATRIX
|
||||
} CoglBoxedType;
|
||||
|
||||
typedef struct _CoglBoxedValue
|
||||
{
|
||||
CoglBoxedType type;
|
||||
int size, count;
|
||||
|
||||
union {
|
||||
float float_value[4];
|
||||
int int_value[4];
|
||||
float matrix[16];
|
||||
float *float_array;
|
||||
int *int_array;
|
||||
void *array;
|
||||
} v;
|
||||
} CoglBoxedValue;
|
||||
|
||||
#define _cogl_boxed_value_init(bv) \
|
||||
G_STMT_START { \
|
||||
CoglBoxedValue *_bv = (bv); \
|
||||
_bv->type = COGL_BOXED_NONE; \
|
||||
_bv->count = 1; \
|
||||
} G_STMT_END
|
||||
|
||||
CoglBool
|
||||
_cogl_boxed_value_equal (const CoglBoxedValue *bva,
|
||||
const CoglBoxedValue *bvb);
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_1f (CoglBoxedValue *bv,
|
||||
float value);
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_1i (CoglBoxedValue *bv,
|
||||
int value);
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_float (CoglBoxedValue *bv,
|
||||
int n_components,
|
||||
int count,
|
||||
const float *value);
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_int (CoglBoxedValue *bv,
|
||||
int n_components,
|
||||
int count,
|
||||
const int *value);
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_matrix (CoglBoxedValue *bv,
|
||||
int dimensions,
|
||||
int count,
|
||||
CoglBool transpose,
|
||||
const float *value);
|
||||
|
||||
/*
|
||||
* _cogl_boxed_value_copy:
|
||||
* @dst: The destination boxed value
|
||||
* @src: The source boxed value
|
||||
*
|
||||
* This copies @src to @dst. It is assumed that @dst is initialised.
|
||||
*/
|
||||
void
|
||||
_cogl_boxed_value_copy (CoglBoxedValue *dst,
|
||||
const CoglBoxedValue *src);
|
||||
|
||||
void
|
||||
_cogl_boxed_value_destroy (CoglBoxedValue *bv);
|
||||
|
||||
void
|
||||
_cogl_boxed_value_set_uniform (CoglContext *ctx,
|
||||
int location,
|
||||
const CoglBoxedValue *value);
|
||||
|
||||
#endif /* __COGL_BOXED_VALUE_H */
|
180
cogl/cogl/cogl-buffer-private.h
Normal file
180
cogl/cogl/cogl-buffer-private.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Damien Lespiau <damien.lespiau@intel.com>
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __COGL_BUFFER_PRIVATE_H__
|
||||
#define __COGL_BUFFER_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-buffer.h"
|
||||
#include "cogl-context.h"
|
||||
#include "cogl-gl-header.h"
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
typedef struct _CoglBufferVtable CoglBufferVtable;
|
||||
|
||||
struct _CoglBufferVtable
|
||||
{
|
||||
void * (* map_range) (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error);
|
||||
|
||||
void (* unmap) (CoglBuffer *buffer);
|
||||
|
||||
CoglBool (* set_data) (CoglBuffer *buffer,
|
||||
unsigned int offset,
|
||||
const void *data,
|
||||
unsigned int size,
|
||||
CoglError **error);
|
||||
};
|
||||
|
||||
typedef enum _CoglBufferFlags
|
||||
{
|
||||
COGL_BUFFER_FLAG_NONE = 0,
|
||||
COGL_BUFFER_FLAG_BUFFER_OBJECT = 1UL << 0, /* real openGL buffer object */
|
||||
COGL_BUFFER_FLAG_MAPPED = 1UL << 1,
|
||||
COGL_BUFFER_FLAG_MAPPED_FALLBACK = 1UL << 2
|
||||
} CoglBufferFlags;
|
||||
|
||||
typedef enum {
|
||||
COGL_BUFFER_USAGE_HINT_TEXTURE,
|
||||
COGL_BUFFER_USAGE_HINT_ATTRIBUTE_BUFFER,
|
||||
COGL_BUFFER_USAGE_HINT_INDEX_BUFFER
|
||||
} CoglBufferUsageHint;
|
||||
|
||||
typedef enum {
|
||||
COGL_BUFFER_BIND_TARGET_PIXEL_PACK,
|
||||
COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK,
|
||||
COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER,
|
||||
COGL_BUFFER_BIND_TARGET_INDEX_BUFFER,
|
||||
|
||||
COGL_BUFFER_BIND_TARGET_COUNT
|
||||
} CoglBufferBindTarget;
|
||||
|
||||
struct _CoglBuffer
|
||||
{
|
||||
CoglObject _parent;
|
||||
|
||||
CoglContext *context;
|
||||
|
||||
CoglBufferVtable vtable;
|
||||
|
||||
CoglBufferBindTarget last_target;
|
||||
|
||||
CoglBufferFlags flags;
|
||||
|
||||
GLuint gl_handle; /* OpenGL handle */
|
||||
unsigned int size; /* size of the buffer, in bytes */
|
||||
CoglBufferUsageHint usage_hint;
|
||||
CoglBufferUpdateHint update_hint;
|
||||
|
||||
/* points to the mapped memory when the CoglBuffer is a VBO, PBO,
|
||||
* ... or points to allocated memory in the fallback paths */
|
||||
uint8_t *data;
|
||||
|
||||
int immutable_ref;
|
||||
|
||||
unsigned int store_created:1;
|
||||
};
|
||||
|
||||
/* This is used to register a type to the list of handle types that
|
||||
will be considered a texture in cogl_is_texture() */
|
||||
void
|
||||
_cogl_buffer_register_buffer_type (const CoglObjectClass *klass);
|
||||
|
||||
#define COGL_BUFFER_DEFINE(TypeName, type_name) \
|
||||
COGL_OBJECT_DEFINE_WITH_CODE \
|
||||
(TypeName, type_name, \
|
||||
_cogl_buffer_register_buffer_type (&_cogl_##type_name##_class))
|
||||
|
||||
void
|
||||
_cogl_buffer_initialize (CoglBuffer *buffer,
|
||||
CoglContext *context,
|
||||
size_t size,
|
||||
CoglBufferBindTarget default_target,
|
||||
CoglBufferUsageHint usage_hint,
|
||||
CoglBufferUpdateHint update_hint);
|
||||
|
||||
void
|
||||
_cogl_buffer_fini (CoglBuffer *buffer);
|
||||
|
||||
CoglBufferUsageHint
|
||||
_cogl_buffer_get_usage_hint (CoglBuffer *buffer);
|
||||
|
||||
GLenum
|
||||
_cogl_buffer_access_to_gl_enum (CoglBufferAccess access);
|
||||
|
||||
CoglBuffer *
|
||||
_cogl_buffer_immutable_ref (CoglBuffer *buffer);
|
||||
|
||||
void
|
||||
_cogl_buffer_immutable_unref (CoglBuffer *buffer);
|
||||
|
||||
CoglBool
|
||||
_cogl_buffer_set_data (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
const void *data,
|
||||
size_t size,
|
||||
CoglError **error);
|
||||
|
||||
void *
|
||||
_cogl_buffer_map (CoglBuffer *buffer,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error);
|
||||
|
||||
/* This is a wrapper around cogl_buffer_map_range for internal use
|
||||
when we want to map the buffer for write only to replace the entire
|
||||
contents. If the map fails then it will fallback to writing to a
|
||||
temporary buffer. When _cogl_buffer_unmap_for_fill_or_fallback is
|
||||
called the temporary buffer will be copied into the array. Note
|
||||
that these calls share a global array so they can not be nested. */
|
||||
void *
|
||||
_cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size);
|
||||
void *
|
||||
_cogl_buffer_map_for_fill_or_fallback (CoglBuffer *buffer);
|
||||
|
||||
void
|
||||
_cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_BUFFER_PRIVATE_H__ */
|
411
cogl/cogl/cogl-buffer.c
Normal file
411
cogl/cogl/cogl-buffer.c
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Damien Lespiau <damien.lespiau@intel.com>
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
/* For an overview of the functionality implemented here, please see
|
||||
* cogl-buffer.h, which contains the gtk-doc section overview for the
|
||||
* Pixel Buffers API.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-object-private.h"
|
||||
#include "cogl-pixel-buffer-private.h"
|
||||
|
||||
/* XXX:
|
||||
* The CoglObject macros don't support any form of inheritance, so for
|
||||
* now we implement the CoglObject support for the CoglBuffer
|
||||
* abstract class manually.
|
||||
*/
|
||||
|
||||
static GSList *_cogl_buffer_types;
|
||||
|
||||
void
|
||||
_cogl_buffer_register_buffer_type (const CoglObjectClass *klass)
|
||||
{
|
||||
_cogl_buffer_types = g_slist_prepend (_cogl_buffer_types, (void *) klass);
|
||||
}
|
||||
|
||||
CoglBool
|
||||
cogl_is_buffer (void *object)
|
||||
{
|
||||
const CoglObject *obj = object;
|
||||
GSList *l;
|
||||
|
||||
if (object == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (l = _cogl_buffer_types; l; l = l->next)
|
||||
if (l->data == obj->klass)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fallback path, buffer->data points to a malloc'ed buffer.
|
||||
*/
|
||||
|
||||
static void *
|
||||
malloc_map_range (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error)
|
||||
{
|
||||
buffer->flags |= COGL_BUFFER_FLAG_MAPPED;
|
||||
return buffer->data + offset;
|
||||
}
|
||||
|
||||
static void
|
||||
malloc_unmap (CoglBuffer *buffer)
|
||||
{
|
||||
buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED;
|
||||
}
|
||||
|
||||
static CoglBool
|
||||
malloc_set_data (CoglBuffer *buffer,
|
||||
unsigned int offset,
|
||||
const void *data,
|
||||
unsigned int size,
|
||||
CoglError **error)
|
||||
{
|
||||
memcpy (buffer->data + offset, data, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_buffer_initialize (CoglBuffer *buffer,
|
||||
CoglContext *ctx,
|
||||
size_t size,
|
||||
CoglBufferBindTarget default_target,
|
||||
CoglBufferUsageHint usage_hint,
|
||||
CoglBufferUpdateHint update_hint)
|
||||
{
|
||||
CoglBool use_malloc = FALSE;
|
||||
|
||||
buffer->context = ctx;
|
||||
buffer->flags = COGL_BUFFER_FLAG_NONE;
|
||||
buffer->store_created = FALSE;
|
||||
buffer->size = size;
|
||||
buffer->last_target = default_target;
|
||||
buffer->usage_hint = usage_hint;
|
||||
buffer->update_hint = update_hint;
|
||||
buffer->data = NULL;
|
||||
buffer->immutable_ref = 0;
|
||||
|
||||
if (default_target == COGL_BUFFER_BIND_TARGET_PIXEL_PACK ||
|
||||
default_target == COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK)
|
||||
{
|
||||
if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_PBOS))
|
||||
use_malloc = TRUE;
|
||||
}
|
||||
else if (default_target == COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER ||
|
||||
default_target == COGL_BUFFER_BIND_TARGET_INDEX_BUFFER)
|
||||
{
|
||||
if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_VBOS))
|
||||
use_malloc = TRUE;
|
||||
}
|
||||
|
||||
if (use_malloc)
|
||||
{
|
||||
buffer->vtable.map_range = malloc_map_range;
|
||||
buffer->vtable.unmap = malloc_unmap;
|
||||
buffer->vtable.set_data = malloc_set_data;
|
||||
|
||||
buffer->data = g_malloc (size);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->vtable.map_range = ctx->driver_vtable->buffer_map_range;
|
||||
buffer->vtable.unmap = ctx->driver_vtable->buffer_unmap;
|
||||
buffer->vtable.set_data = ctx->driver_vtable->buffer_set_data;
|
||||
|
||||
ctx->driver_vtable->buffer_create (buffer);
|
||||
|
||||
buffer->flags |= COGL_BUFFER_FLAG_BUFFER_OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_buffer_fini (CoglBuffer *buffer)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (!(buffer->flags & COGL_BUFFER_FLAG_MAPPED));
|
||||
_COGL_RETURN_IF_FAIL (buffer->immutable_ref == 0);
|
||||
|
||||
if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT)
|
||||
buffer->context->driver_vtable->buffer_destroy (buffer);
|
||||
else
|
||||
g_free (buffer->data);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cogl_buffer_get_size (CoglBuffer *buffer)
|
||||
{
|
||||
if (!cogl_is_buffer (buffer))
|
||||
return 0;
|
||||
|
||||
return COGL_BUFFER (buffer)->size;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_buffer_set_update_hint (CoglBuffer *buffer,
|
||||
CoglBufferUpdateHint hint)
|
||||
{
|
||||
if (!cogl_is_buffer (buffer))
|
||||
return;
|
||||
|
||||
if (G_UNLIKELY (hint > COGL_BUFFER_UPDATE_HINT_STREAM))
|
||||
hint = COGL_BUFFER_UPDATE_HINT_STATIC;
|
||||
|
||||
buffer->update_hint = hint;
|
||||
}
|
||||
|
||||
CoglBufferUpdateHint
|
||||
cogl_buffer_get_update_hint (CoglBuffer *buffer)
|
||||
{
|
||||
if (!cogl_is_buffer (buffer))
|
||||
return FALSE;
|
||||
|
||||
return buffer->update_hint;
|
||||
}
|
||||
|
||||
static void
|
||||
warn_about_midscene_changes (void)
|
||||
{
|
||||
static CoglBool seen = FALSE;
|
||||
if (!seen)
|
||||
{
|
||||
g_warning ("Mid-scene modification of buffers has "
|
||||
"undefined results\n");
|
||||
seen = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
_cogl_buffer_map (CoglBuffer *buffer,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error)
|
||||
{
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL);
|
||||
|
||||
return cogl_buffer_map_range (buffer, 0, buffer->size, access, hints, error);
|
||||
}
|
||||
|
||||
void *
|
||||
cogl_buffer_map (CoglBuffer *buffer,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints)
|
||||
{
|
||||
CoglError *ignore_error = NULL;
|
||||
void *ptr =
|
||||
cogl_buffer_map_range (buffer, 0, buffer->size, access, hints,
|
||||
&ignore_error);
|
||||
if (!ptr)
|
||||
cogl_error_free (ignore_error);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
cogl_buffer_map_range (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error)
|
||||
{
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL);
|
||||
_COGL_RETURN_VAL_IF_FAIL (!(buffer->flags & COGL_BUFFER_FLAG_MAPPED), NULL);
|
||||
|
||||
if (G_UNLIKELY (buffer->immutable_ref))
|
||||
warn_about_midscene_changes ();
|
||||
|
||||
buffer->data = buffer->vtable.map_range (buffer,
|
||||
offset,
|
||||
size,
|
||||
access,
|
||||
hints,
|
||||
error);
|
||||
|
||||
return buffer->data;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_buffer_unmap (CoglBuffer *buffer)
|
||||
{
|
||||
if (!cogl_is_buffer (buffer))
|
||||
return;
|
||||
|
||||
if (!(buffer->flags & COGL_BUFFER_FLAG_MAPPED))
|
||||
return;
|
||||
|
||||
buffer->vtable.unmap (buffer);
|
||||
}
|
||||
|
||||
void *
|
||||
_cogl_buffer_map_for_fill_or_fallback (CoglBuffer *buffer)
|
||||
{
|
||||
return _cogl_buffer_map_range_for_fill_or_fallback (buffer, 0, buffer->size);
|
||||
}
|
||||
|
||||
void *
|
||||
_cogl_buffer_map_range_for_fill_or_fallback (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size)
|
||||
{
|
||||
CoglContext *ctx = buffer->context;
|
||||
void *ret;
|
||||
CoglError *ignore_error = NULL;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (!ctx->buffer_map_fallback_in_use, NULL);
|
||||
|
||||
ctx->buffer_map_fallback_in_use = TRUE;
|
||||
|
||||
ret = cogl_buffer_map_range (buffer,
|
||||
offset,
|
||||
size,
|
||||
COGL_BUFFER_ACCESS_WRITE,
|
||||
COGL_BUFFER_MAP_HINT_DISCARD,
|
||||
&ignore_error);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cogl_error_free (ignore_error);
|
||||
|
||||
/* If the map fails then we'll use a temporary buffer to fill
|
||||
the data and then upload it using cogl_buffer_set_data when
|
||||
the buffer is unmapped. The temporary buffer is shared to
|
||||
avoid reallocating it every time */
|
||||
g_byte_array_set_size (ctx->buffer_map_fallback_array, size);
|
||||
ctx->buffer_map_fallback_offset = offset;
|
||||
|
||||
buffer->flags |= COGL_BUFFER_FLAG_MAPPED_FALLBACK;
|
||||
|
||||
return ctx->buffer_map_fallback_array->data;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer)
|
||||
{
|
||||
CoglContext *ctx = buffer->context;
|
||||
|
||||
_COGL_RETURN_IF_FAIL (ctx->buffer_map_fallback_in_use);
|
||||
|
||||
ctx->buffer_map_fallback_in_use = FALSE;
|
||||
|
||||
if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK))
|
||||
{
|
||||
/* Note: don't try to catch OOM errors here since the use cases
|
||||
* we currently have for this api (the journal and path stroke
|
||||
* tesselator) don't have anything particularly sensible they
|
||||
* can do in response to a failure anyway so it seems better to
|
||||
* simply abort instead.
|
||||
*
|
||||
* If we find this is a problem for real world applications
|
||||
* then in the path tesselation case we could potentially add an
|
||||
* explicit cogl_path_tesselate_stroke() api that can throw an
|
||||
* error for the app to cache. For the journal we could
|
||||
* potentially flush the journal in smaller batches so we use
|
||||
* smaller buffers, though that would probably not help for
|
||||
* deferred renderers.
|
||||
*/
|
||||
_cogl_buffer_set_data (buffer,
|
||||
ctx->buffer_map_fallback_offset,
|
||||
ctx->buffer_map_fallback_array->data,
|
||||
ctx->buffer_map_fallback_array->len,
|
||||
NULL);
|
||||
buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK;
|
||||
}
|
||||
else
|
||||
cogl_buffer_unmap (buffer);
|
||||
}
|
||||
|
||||
CoglBool
|
||||
_cogl_buffer_set_data (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
const void *data,
|
||||
size_t size,
|
||||
CoglError **error)
|
||||
{
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), FALSE);
|
||||
_COGL_RETURN_VAL_IF_FAIL ((offset + size) <= buffer->size, FALSE);
|
||||
|
||||
if (G_UNLIKELY (buffer->immutable_ref))
|
||||
warn_about_midscene_changes ();
|
||||
|
||||
return buffer->vtable.set_data (buffer, offset, data, size, error);
|
||||
}
|
||||
|
||||
CoglBool
|
||||
cogl_buffer_set_data (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
const void *data,
|
||||
size_t size)
|
||||
{
|
||||
CoglError *ignore_error = NULL;
|
||||
CoglBool status =
|
||||
_cogl_buffer_set_data (buffer, offset, data, size, &ignore_error);
|
||||
if (!status)
|
||||
cogl_error_free (ignore_error);
|
||||
return status;
|
||||
}
|
||||
|
||||
CoglBuffer *
|
||||
_cogl_buffer_immutable_ref (CoglBuffer *buffer)
|
||||
{
|
||||
_COGL_RETURN_VAL_IF_FAIL (cogl_is_buffer (buffer), NULL);
|
||||
|
||||
buffer->immutable_ref++;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_buffer_immutable_unref (CoglBuffer *buffer)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (cogl_is_buffer (buffer));
|
||||
_COGL_RETURN_IF_FAIL (buffer->immutable_ref > 0);
|
||||
|
||||
buffer->immutable_ref--;
|
||||
}
|
||||
|
324
cogl/cogl/cogl-buffer.h
Normal file
324
cogl/cogl/cogl-buffer.h
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Damien Lespiau <damien.lespiau@intel.com>
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_BUFFER_H__
|
||||
#define __COGL_BUFFER_H__
|
||||
|
||||
#include <cogl/cogl-types.h>
|
||||
#include <cogl/cogl-error.h>
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* SECTION:cogl-buffer
|
||||
* @short_description: Common buffer functions, including data upload APIs
|
||||
* @stability: unstable
|
||||
*
|
||||
* The CoglBuffer API provides a common interface to manipulate
|
||||
* buffers that have been allocated either via cogl_pixel_buffer_new()
|
||||
* or cogl_attribute_buffer_new(). The API allows you to upload data
|
||||
* to these buffers and define usage hints that help Cogl manage your
|
||||
* buffer optimally.
|
||||
*
|
||||
* Data can either be uploaded by supplying a pointer and size so Cogl
|
||||
* can copy your data, or you can mmap() a CoglBuffer and then you can
|
||||
* copy data to the buffer directly.
|
||||
*
|
||||
* One of the most common uses for CoglBuffers is to upload texture
|
||||
* data asynchronously since the ability to mmap the buffers into
|
||||
* the CPU makes it possible for another thread to handle the IO
|
||||
* of loading an image file and unpacking it into the mapped buffer
|
||||
* without blocking other Cogl operations.
|
||||
*/
|
||||
|
||||
#ifdef __COGL_H_INSIDE__
|
||||
/* For the public C api we typedef interface types as void to avoid needing
|
||||
* lots of casting in code and instead we will rely on runtime type checking
|
||||
* for these objects. */
|
||||
typedef void CoglBuffer;
|
||||
#else
|
||||
typedef struct _CoglBuffer CoglBuffer;
|
||||
#define COGL_BUFFER(buffer) ((CoglBuffer *)(buffer))
|
||||
#endif
|
||||
|
||||
#define COGL_BUFFER_ERROR (_cogl_buffer_error_domain ())
|
||||
|
||||
/**
|
||||
* CoglBufferError:
|
||||
* @COGL_BUFFER_ERROR_MAP: A buffer could not be mapped either
|
||||
* because the feature isn't supported or because a system
|
||||
* limitation was hit.
|
||||
*
|
||||
* Error enumeration for #CoglBuffer
|
||||
*
|
||||
* Stability: unstable
|
||||
*/
|
||||
typedef enum { /*< prefix=COGL_BUFFER_ERROR >*/
|
||||
COGL_BUFFER_ERROR_MAP
|
||||
} CoglBufferError;
|
||||
|
||||
uint32_t
|
||||
_cogl_buffer_error_domain (void);
|
||||
|
||||
/**
|
||||
* cogl_is_buffer:
|
||||
* @object: a buffer object
|
||||
*
|
||||
* Checks whether @buffer is a buffer object.
|
||||
*
|
||||
* Return value: %TRUE if the handle is a CoglBuffer, and %FALSE otherwise
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglBool
|
||||
cogl_is_buffer (void *object);
|
||||
|
||||
/**
|
||||
* cogl_buffer_get_size:
|
||||
* @buffer: a buffer object
|
||||
*
|
||||
* Retrieves the size of buffer
|
||||
*
|
||||
* Return value: the size of the buffer in bytes
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
unsigned int
|
||||
cogl_buffer_get_size (CoglBuffer *buffer);
|
||||
|
||||
/**
|
||||
* CoglBufferUpdateHint:
|
||||
* @COGL_BUFFER_UPDATE_HINT_STATIC: the buffer will not change over time
|
||||
* @COGL_BUFFER_UPDATE_HINT_DYNAMIC: the buffer will change from time to time
|
||||
* @COGL_BUFFER_UPDATE_HINT_STREAM: the buffer will be used once or a couple of
|
||||
* times
|
||||
*
|
||||
* The update hint on a buffer allows the user to give some detail on how often
|
||||
* the buffer data is going to be updated.
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
typedef enum { /*< prefix=COGL_BUFFER_UPDATE_HINT >*/
|
||||
COGL_BUFFER_UPDATE_HINT_STATIC,
|
||||
COGL_BUFFER_UPDATE_HINT_DYNAMIC,
|
||||
COGL_BUFFER_UPDATE_HINT_STREAM
|
||||
} CoglBufferUpdateHint;
|
||||
|
||||
/**
|
||||
* cogl_buffer_set_update_hint:
|
||||
* @buffer: a buffer object
|
||||
* @hint: the new hint
|
||||
*
|
||||
* Sets the update hint on a buffer. See #CoglBufferUpdateHint for a description
|
||||
* of the available hints.
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
void
|
||||
cogl_buffer_set_update_hint (CoglBuffer *buffer,
|
||||
CoglBufferUpdateHint hint);
|
||||
|
||||
/**
|
||||
* cogl_buffer_get_update_hint:
|
||||
* @buffer: a buffer object
|
||||
*
|
||||
* Retrieves the update hints set using cogl_buffer_set_update_hint()
|
||||
*
|
||||
* Return value: the #CoglBufferUpdateHint currently used by the buffer
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglBufferUpdateHint
|
||||
cogl_buffer_get_update_hint (CoglBuffer *buffer);
|
||||
|
||||
/**
|
||||
* CoglBufferAccess:
|
||||
* @COGL_BUFFER_ACCESS_READ: the buffer will be read
|
||||
* @COGL_BUFFER_ACCESS_WRITE: the buffer will written to
|
||||
* @COGL_BUFFER_ACCESS_READ_WRITE: the buffer will be used for both reading and
|
||||
* writing
|
||||
*
|
||||
* The access hints for cogl_buffer_set_update_hint()
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
typedef enum { /*< prefix=COGL_BUFFER_ACCESS >*/
|
||||
COGL_BUFFER_ACCESS_READ = 1 << 0,
|
||||
COGL_BUFFER_ACCESS_WRITE = 1 << 1,
|
||||
COGL_BUFFER_ACCESS_READ_WRITE = COGL_BUFFER_ACCESS_READ | COGL_BUFFER_ACCESS_WRITE
|
||||
} CoglBufferAccess;
|
||||
|
||||
|
||||
/**
|
||||
* CoglBufferMapHint:
|
||||
* @COGL_BUFFER_MAP_HINT_DISCARD: Tells Cogl that you plan to replace
|
||||
* all the buffer's contents. When this flag is used to map a
|
||||
* buffer, the entire contents of the buffer become undefined, even
|
||||
* if only a subregion of the buffer is mapped.
|
||||
* @COGL_BUFFER_MAP_HINT_DISCARD_RANGE: Tells Cogl that you plan to
|
||||
* replace all the contents of the mapped region. The contents of
|
||||
* the region specified are undefined after this flag is used to
|
||||
* map a buffer.
|
||||
*
|
||||
* Hints to Cogl about how you are planning to modify the data once it
|
||||
* is mapped.
|
||||
*
|
||||
* Since: 1.4
|
||||
* Stability: unstable
|
||||
*/
|
||||
typedef enum { /*< prefix=COGL_BUFFER_MAP_HINT >*/
|
||||
COGL_BUFFER_MAP_HINT_DISCARD = 1 << 0,
|
||||
COGL_BUFFER_MAP_HINT_DISCARD_RANGE = 1 << 1
|
||||
} CoglBufferMapHint;
|
||||
|
||||
/**
|
||||
* cogl_buffer_map:
|
||||
* @buffer: a buffer object
|
||||
* @access: how the mapped buffer will be used by the application
|
||||
* @hints: A mask of #CoglBufferMapHint<!-- -->s that tell Cogl how
|
||||
* the data will be modified once mapped.
|
||||
*
|
||||
* Maps the buffer into the application address space for direct
|
||||
* access. This is equivalent to calling cogl_buffer_map_range() with
|
||||
* zero as the offset and the size of the entire buffer as the size.
|
||||
*
|
||||
* It is strongly recommended that you pass
|
||||
* %COGL_BUFFER_MAP_HINT_DISCARD as a hint if you are going to replace
|
||||
* all the buffer's data. This way if the buffer is currently being
|
||||
* used by the GPU then the driver won't have to stall the CPU and
|
||||
* wait for the hardware to finish because it can instead allocate a
|
||||
* new buffer to map.
|
||||
*
|
||||
* The behaviour is undefined if you access the buffer in a way
|
||||
* conflicting with the @access mask you pass. It is also an error to
|
||||
* release your last reference while the buffer is mapped.
|
||||
*
|
||||
* Return value: (transfer none): A pointer to the mapped memory or
|
||||
* %NULL is the call fails
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
void *
|
||||
cogl_buffer_map (CoglBuffer *buffer,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints);
|
||||
|
||||
/**
|
||||
* cogl_buffer_map_range:
|
||||
* @buffer: a buffer object
|
||||
* @offset: Offset within the buffer to start the mapping
|
||||
* @size: The size of data to map
|
||||
* @access: how the mapped buffer will be used by the application
|
||||
* @hints: A mask of #CoglBufferMapHint<!-- -->s that tell Cogl how
|
||||
* the data will be modified once mapped.
|
||||
* @error: A #CoglError for catching exceptional errors
|
||||
*
|
||||
* Maps a sub-region of the buffer into the application's address space
|
||||
* for direct access.
|
||||
*
|
||||
* It is strongly recommended that you pass
|
||||
* %COGL_BUFFER_MAP_HINT_DISCARD as a hint if you are going to replace
|
||||
* all the buffer's data. This way if the buffer is currently being
|
||||
* used by the GPU then the driver won't have to stall the CPU and
|
||||
* wait for the hardware to finish because it can instead allocate a
|
||||
* new buffer to map. You can pass
|
||||
* %COGL_BUFFER_MAP_HINT_DISCARD_RANGE instead if you want the
|
||||
* regions outside of the mapping to be retained.
|
||||
*
|
||||
* The behaviour is undefined if you access the buffer in a way
|
||||
* conflicting with the @access mask you pass. It is also an error to
|
||||
* release your last reference while the buffer is mapped.
|
||||
*
|
||||
* Return value: (transfer none): A pointer to the mapped memory or
|
||||
* %NULL is the call fails
|
||||
*
|
||||
* Since: 2.0
|
||||
* Stability: unstable
|
||||
*/
|
||||
void *
|
||||
cogl_buffer_map_range (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t size,
|
||||
CoglBufferAccess access,
|
||||
CoglBufferMapHint hints,
|
||||
CoglError **error);
|
||||
|
||||
/**
|
||||
* cogl_buffer_unmap:
|
||||
* @buffer: a buffer object
|
||||
*
|
||||
* Unmaps a buffer previously mapped by cogl_buffer_map().
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
void
|
||||
cogl_buffer_unmap (CoglBuffer *buffer);
|
||||
|
||||
/**
|
||||
* cogl_buffer_set_data:
|
||||
* @buffer: a buffer object
|
||||
* @offset: destination offset (in bytes) in the buffer
|
||||
* @data: a pointer to the data to be copied into the buffer
|
||||
* @size: number of bytes to copy
|
||||
*
|
||||
* Updates part of the buffer with new data from @data. Where to put this new
|
||||
* data is controlled by @offset and @offset + @data should be less than the
|
||||
* buffer size.
|
||||
*
|
||||
* Return value: %TRUE is the operation succeeded, %FALSE otherwise
|
||||
*
|
||||
* Since: 1.2
|
||||
* Stability: unstable
|
||||
*/
|
||||
CoglBool
|
||||
cogl_buffer_set_data (CoglBuffer *buffer,
|
||||
size_t offset,
|
||||
const void *data,
|
||||
size_t size);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_BUFFER_H__ */
|
412
cogl/cogl/cogl-clip-stack.c
Normal file
412
cogl/cogl/cogl-clip-stack.c
Normal file
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2007,2008,2009,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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "cogl-clip-stack.h"
|
||||
#include "cogl-primitives.h"
|
||||
#include "cogl-context-private.h"
|
||||
#include "cogl-framebuffer-private.h"
|
||||
#include "cogl-journal-private.h"
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-matrix-private.h"
|
||||
#include "cogl-primitives-private.h"
|
||||
#include "cogl-private.h"
|
||||
#include "cogl-pipeline-opengl-private.h"
|
||||
#include "cogl-attribute-private.h"
|
||||
#include "cogl-primitive-private.h"
|
||||
#include "cogl1-context.h"
|
||||
#include "cogl-offscreen.h"
|
||||
#include "cogl-matrix-stack.h"
|
||||
|
||||
|
||||
|
||||
static void *
|
||||
_cogl_clip_stack_push_entry (CoglClipStack *clip_stack,
|
||||
size_t size,
|
||||
CoglClipStackType type)
|
||||
{
|
||||
CoglClipStack *entry = g_slice_alloc (size);
|
||||
|
||||
/* The new entry starts with a ref count of 1 because the stack
|
||||
holds a reference to it as it is the top entry */
|
||||
entry->ref_count = 1;
|
||||
entry->type = type;
|
||||
entry->parent = clip_stack;
|
||||
|
||||
/* We don't need to take a reference to the parent from the entry
|
||||
because the we are stealing the ref in the new stack top */
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void
|
||||
get_transformed_corners (float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2,
|
||||
CoglMatrix *modelview,
|
||||
CoglMatrix *projection,
|
||||
const float *viewport,
|
||||
float *transformed_corners)
|
||||
{
|
||||
int i;
|
||||
|
||||
transformed_corners[0] = x_1;
|
||||
transformed_corners[1] = y_1;
|
||||
transformed_corners[2] = x_2;
|
||||
transformed_corners[3] = y_1;
|
||||
transformed_corners[4] = x_2;
|
||||
transformed_corners[5] = y_2;
|
||||
transformed_corners[6] = x_1;
|
||||
transformed_corners[7] = y_2;
|
||||
|
||||
|
||||
/* Project the coordinates to window space coordinates */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
float *v = transformed_corners + i * 2;
|
||||
_cogl_transform_point (modelview, projection, viewport, v, v + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sets the window-space bounds of the entry based on the projected
|
||||
coordinates of the given rectangle */
|
||||
static void
|
||||
_cogl_clip_stack_entry_set_bounds (CoglClipStack *entry,
|
||||
float *transformed_corners)
|
||||
{
|
||||
float min_x = G_MAXFLOAT, min_y = G_MAXFLOAT;
|
||||
float max_x = -G_MAXFLOAT, max_y = -G_MAXFLOAT;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
float *v = transformed_corners + i * 2;
|
||||
|
||||
if (v[0] > max_x)
|
||||
max_x = v[0];
|
||||
if (v[0] < min_x)
|
||||
min_x = v[0];
|
||||
if (v[1] > max_y)
|
||||
max_y = v[1];
|
||||
if (v[1] < min_y)
|
||||
min_y = v[1];
|
||||
}
|
||||
|
||||
entry->bounds_x0 = floorf (min_x);
|
||||
entry->bounds_x1 = ceilf (max_x);
|
||||
entry->bounds_y0 = floorf (min_y);
|
||||
entry->bounds_y1 = ceilf (max_y);
|
||||
}
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
|
||||
int x_offset,
|
||||
int y_offset,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
CoglClipStack *entry;
|
||||
|
||||
entry = _cogl_clip_stack_push_entry (stack,
|
||||
sizeof (CoglClipStackWindowRect),
|
||||
COGL_CLIP_STACK_WINDOW_RECT);
|
||||
|
||||
entry->bounds_x0 = x_offset;
|
||||
entry->bounds_x1 = x_offset + width;
|
||||
entry->bounds_y0 = y_offset;
|
||||
entry->bounds_y1 = y_offset + height;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_push_rectangle (CoglClipStack *stack,
|
||||
float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2,
|
||||
CoglMatrixEntry *modelview_entry,
|
||||
CoglMatrixEntry *projection_entry,
|
||||
const float *viewport)
|
||||
{
|
||||
CoglClipStackRect *entry;
|
||||
CoglMatrix modelview;
|
||||
CoglMatrix projection;
|
||||
CoglMatrix modelview_projection;
|
||||
|
||||
/* Corners of the given rectangle in an clockwise order:
|
||||
* (0, 1) (2, 3)
|
||||
*
|
||||
*
|
||||
*
|
||||
* (6, 7) (4, 5)
|
||||
*/
|
||||
float rect[] = {
|
||||
x_1, y_1,
|
||||
x_2, y_1,
|
||||
x_2, y_2,
|
||||
x_1, y_2
|
||||
};
|
||||
|
||||
/* Make a new entry */
|
||||
entry = _cogl_clip_stack_push_entry (stack,
|
||||
sizeof (CoglClipStackRect),
|
||||
COGL_CLIP_STACK_RECT);
|
||||
|
||||
entry->x0 = x_1;
|
||||
entry->y0 = y_1;
|
||||
entry->x1 = x_2;
|
||||
entry->y1 = y_2;
|
||||
|
||||
entry->matrix_entry = cogl_matrix_entry_ref (modelview_entry);
|
||||
|
||||
cogl_matrix_entry_get (modelview_entry, &modelview);
|
||||
cogl_matrix_entry_get (projection_entry, &projection);
|
||||
|
||||
cogl_matrix_multiply (&modelview_projection,
|
||||
&projection,
|
||||
&modelview);
|
||||
|
||||
/* Technically we could avoid the viewport transform at this point
|
||||
* if we want to make this a bit faster. */
|
||||
_cogl_transform_point (&modelview, &projection, viewport, &rect[0], &rect[1]);
|
||||
_cogl_transform_point (&modelview, &projection, viewport, &rect[2], &rect[3]);
|
||||
_cogl_transform_point (&modelview, &projection, viewport, &rect[4], &rect[5]);
|
||||
_cogl_transform_point (&modelview, &projection, viewport, &rect[6], &rect[7]);
|
||||
|
||||
/* If the fully transformed rectangle isn't still axis aligned we
|
||||
* can't handle it using a scissor.
|
||||
*
|
||||
* We don't use an epsilon here since we only really aim to catch
|
||||
* simple cases where the transform doesn't leave the rectangle screen
|
||||
* aligned and don't mind some false positives.
|
||||
*/
|
||||
if (rect[0] != rect[6] ||
|
||||
rect[1] != rect[3] ||
|
||||
rect[2] != rect[4] ||
|
||||
rect[7] != rect[5])
|
||||
{
|
||||
entry->can_be_scissor = FALSE;
|
||||
|
||||
_cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
|
||||
rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
CoglClipStack *base_entry = (CoglClipStack *) entry;
|
||||
x_1 = rect[0];
|
||||
y_1 = rect[1];
|
||||
x_2 = rect[4];
|
||||
y_2 = rect[5];
|
||||
|
||||
/* Consider that the modelview matrix may flip the rectangle
|
||||
* along the x or y axis... */
|
||||
#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0)
|
||||
if (x_1 > x_2)
|
||||
SWAP (x_1, x_2);
|
||||
if (y_1 > y_2)
|
||||
SWAP (y_1, y_2);
|
||||
#undef SWAP
|
||||
|
||||
base_entry->bounds_x0 = COGL_UTIL_NEARBYINT (x_1);
|
||||
base_entry->bounds_y0 = COGL_UTIL_NEARBYINT (y_1);
|
||||
base_entry->bounds_x1 = COGL_UTIL_NEARBYINT (x_2);
|
||||
base_entry->bounds_y1 = COGL_UTIL_NEARBYINT (y_2);
|
||||
entry->can_be_scissor = TRUE;
|
||||
}
|
||||
|
||||
return (CoglClipStack *) entry;
|
||||
}
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_push_primitive (CoglClipStack *stack,
|
||||
CoglPrimitive *primitive,
|
||||
float bounds_x1,
|
||||
float bounds_y1,
|
||||
float bounds_x2,
|
||||
float bounds_y2,
|
||||
CoglMatrixEntry *modelview_entry,
|
||||
CoglMatrixEntry *projection_entry,
|
||||
const float *viewport)
|
||||
{
|
||||
CoglClipStackPrimitive *entry;
|
||||
CoglMatrix modelview;
|
||||
CoglMatrix projection;
|
||||
float transformed_corners[8];
|
||||
|
||||
entry = _cogl_clip_stack_push_entry (stack,
|
||||
sizeof (CoglClipStackPrimitive),
|
||||
COGL_CLIP_STACK_PRIMITIVE);
|
||||
|
||||
entry->primitive = cogl_object_ref (primitive);
|
||||
|
||||
entry->matrix_entry = cogl_matrix_entry_ref (modelview_entry);
|
||||
|
||||
entry->bounds_x1 = bounds_x1;
|
||||
entry->bounds_y1 = bounds_y1;
|
||||
entry->bounds_x2 = bounds_x2;
|
||||
entry->bounds_y2 = bounds_y2;
|
||||
|
||||
cogl_matrix_entry_get (modelview_entry, &modelview);
|
||||
cogl_matrix_entry_get (projection_entry, &projection);
|
||||
|
||||
get_transformed_corners (bounds_x1, bounds_y1, bounds_x2, bounds_y2,
|
||||
&modelview,
|
||||
&projection,
|
||||
viewport,
|
||||
transformed_corners);
|
||||
|
||||
/* NB: this is referring to the bounds in window coordinates as opposed
|
||||
* to the bounds above in primitive local coordinates. */
|
||||
_cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
|
||||
transformed_corners);
|
||||
|
||||
return (CoglClipStack *) entry;
|
||||
}
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_ref (CoglClipStack *entry)
|
||||
{
|
||||
/* A NULL pointer is considered a valid stack so we should accept
|
||||
that as an argument */
|
||||
if (entry)
|
||||
entry->ref_count++;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_unref (CoglClipStack *entry)
|
||||
{
|
||||
/* Unref all of the entries until we hit the root of the list or the
|
||||
entry still has a remaining reference */
|
||||
while (entry && --entry->ref_count <= 0)
|
||||
{
|
||||
CoglClipStack *parent = entry->parent;
|
||||
|
||||
switch (entry->type)
|
||||
{
|
||||
case COGL_CLIP_STACK_RECT:
|
||||
{
|
||||
CoglClipStackRect *rect = (CoglClipStackRect *) entry;
|
||||
cogl_matrix_entry_unref (rect->matrix_entry);
|
||||
g_slice_free1 (sizeof (CoglClipStackRect), entry);
|
||||
break;
|
||||
}
|
||||
case COGL_CLIP_STACK_WINDOW_RECT:
|
||||
g_slice_free1 (sizeof (CoglClipStackWindowRect), entry);
|
||||
break;
|
||||
case COGL_CLIP_STACK_PRIMITIVE:
|
||||
{
|
||||
CoglClipStackPrimitive *primitive_entry =
|
||||
(CoglClipStackPrimitive *) entry;
|
||||
cogl_matrix_entry_unref (primitive_entry->matrix_entry);
|
||||
cogl_object_unref (primitive_entry->primitive);
|
||||
g_slice_free1 (sizeof (CoglClipStackPrimitive), entry);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
entry = parent;
|
||||
}
|
||||
}
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_pop (CoglClipStack *stack)
|
||||
{
|
||||
CoglClipStack *new_top;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (stack != NULL, NULL);
|
||||
|
||||
/* To pop we are moving the top of the stack to the old top's parent
|
||||
node. The stack always needs to have a reference to the top entry
|
||||
so we must take a reference to the new top. The stack would have
|
||||
previously had a reference to the old top so we need to decrease
|
||||
the ref count on that. We need to ref the new head first in case
|
||||
this stack was the only thing referencing the old top. In that
|
||||
case the call to _cogl_clip_stack_entry_unref will unref the
|
||||
parent. */
|
||||
new_top = stack->parent;
|
||||
|
||||
_cogl_clip_stack_ref (new_top);
|
||||
|
||||
_cogl_clip_stack_unref (stack);
|
||||
|
||||
return new_top;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_get_bounds (CoglClipStack *stack,
|
||||
int *scissor_x0,
|
||||
int *scissor_y0,
|
||||
int *scissor_x1,
|
||||
int *scissor_y1)
|
||||
{
|
||||
CoglClipStack *entry;
|
||||
|
||||
*scissor_x0 = 0;
|
||||
*scissor_y0 = 0;
|
||||
*scissor_x1 = G_MAXINT;
|
||||
*scissor_y1 = G_MAXINT;
|
||||
|
||||
for (entry = stack; entry; entry = entry->parent)
|
||||
{
|
||||
/* Get the intersection of the current scissor and the bounding
|
||||
box of this clip */
|
||||
_cogl_util_scissor_intersect (entry->bounds_x0,
|
||||
entry->bounds_y0,
|
||||
entry->bounds_x1,
|
||||
entry->bounds_y1,
|
||||
scissor_x0,
|
||||
scissor_y0,
|
||||
scissor_x1,
|
||||
scissor_y1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_flush (CoglClipStack *stack,
|
||||
CoglFramebuffer *framebuffer)
|
||||
{
|
||||
CoglContext *ctx = framebuffer->context;
|
||||
|
||||
ctx->driver_vtable->clip_stack_flush (stack, framebuffer);
|
||||
}
|
213
cogl/cogl/cogl-clip-stack.h
Normal file
213
cogl/cogl/cogl-clip-stack.h
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2007,2008,2009,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_CLIP_STACK_H
|
||||
#define __COGL_CLIP_STACK_H
|
||||
|
||||
#include "cogl-matrix.h"
|
||||
#include "cogl-primitive.h"
|
||||
#include "cogl-framebuffer.h"
|
||||
#include "cogl-matrix-stack.h"
|
||||
|
||||
/* The clip stack works like a GSList where only a pointer to the top
|
||||
of the stack is stored. The empty clip stack is represented simply
|
||||
by the NULL pointer. When an entry is added to or removed from the
|
||||
stack the new top of the stack is returned. When an entry is pushed
|
||||
a new clip stack entry is created which effectively takes ownership
|
||||
of the reference on the old entry. Therefore unrefing the top entry
|
||||
effectively loses ownership of all entries in the stack */
|
||||
|
||||
typedef struct _CoglClipStack CoglClipStack;
|
||||
typedef struct _CoglClipStackRect CoglClipStackRect;
|
||||
typedef struct _CoglClipStackWindowRect CoglClipStackWindowRect;
|
||||
typedef struct _CoglClipStackPrimitive CoglClipStackPrimitive;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COGL_CLIP_STACK_RECT,
|
||||
COGL_CLIP_STACK_WINDOW_RECT,
|
||||
COGL_CLIP_STACK_PRIMITIVE
|
||||
} CoglClipStackType;
|
||||
|
||||
/* A clip stack consists a list of entries. Each entry has a reference
|
||||
* count and a link to its parent node. The child takes a reference on
|
||||
* the parent and the CoglClipStack holds a reference to the top of
|
||||
* the stack. There are no links back from the parent to the
|
||||
* children. This allows stacks that have common ancestry to share the
|
||||
* entries.
|
||||
*
|
||||
* For example, the following sequence of operations would generate
|
||||
* the tree below:
|
||||
*
|
||||
* CoglClipStack *stack_a = NULL;
|
||||
* stack_a = _cogl_clip_stack_push_rectangle (stack_a, ...);
|
||||
* stack_a = _cogl_clip_stack_push_rectangle (stack_a, ...);
|
||||
* stack_a = _cogl_clip_stack_push_primitive (stack_a, ...);
|
||||
* CoglClipStack *stack_b = NULL;
|
||||
* stack_b = cogl_clip_stack_push_window_rectangle (stack_b, ...);
|
||||
*
|
||||
* stack_a
|
||||
* \ holds a ref to
|
||||
* +-----------+
|
||||
* | prim node |
|
||||
* |ref count 1|
|
||||
* +-----------+
|
||||
* \
|
||||
* +-----------+ +-----------+
|
||||
* both tops hold | rect node | | rect node |
|
||||
* a ref to the |ref count 2|--|ref count 1|
|
||||
* same rect node +-----------+ +-----------+
|
||||
* /
|
||||
* +-----------+
|
||||
* | win. rect |
|
||||
* |ref count 1|
|
||||
* +-----------+
|
||||
* / holds a ref to
|
||||
* stack_b
|
||||
*
|
||||
*/
|
||||
|
||||
struct _CoglClipStack
|
||||
{
|
||||
/* This will be null if there is no parent. If it is not null then
|
||||
this node must be holding a reference to the parent */
|
||||
CoglClipStack *parent;
|
||||
|
||||
CoglClipStackType type;
|
||||
|
||||
/* All clip entries have a window-space bounding box which we can
|
||||
use to calculate a scissor. The scissor limits the clip so that
|
||||
we don't need to do a full stencil clear if the stencil buffer is
|
||||
needed. This is stored in Cogl's coordinate space (ie, 0,0 is the
|
||||
top left) */
|
||||
int bounds_x0;
|
||||
int bounds_y0;
|
||||
int bounds_x1;
|
||||
int bounds_y1;
|
||||
|
||||
unsigned int ref_count;
|
||||
};
|
||||
|
||||
struct _CoglClipStackRect
|
||||
{
|
||||
CoglClipStack _parent_data;
|
||||
|
||||
/* The rectangle for this clip */
|
||||
float x0;
|
||||
float y0;
|
||||
float x1;
|
||||
float y1;
|
||||
|
||||
/* The matrix that was current when the clip was set */
|
||||
CoglMatrixEntry *matrix_entry;
|
||||
|
||||
/* If this is true then the clip for this rectangle is entirely
|
||||
described by the scissor bounds. This implies that the rectangle
|
||||
is screen aligned and we don't need to use the stencil buffer to
|
||||
set the clip. We keep the entry as a rect entry rather than a
|
||||
window rect entry so that it will be easier to detect if the
|
||||
modelview matrix is that same as when a rectangle is added to the
|
||||
journal. In that case we can use the original clip coordinates
|
||||
and modify the rectangle instead. */
|
||||
CoglBool can_be_scissor;
|
||||
};
|
||||
|
||||
struct _CoglClipStackWindowRect
|
||||
{
|
||||
CoglClipStack _parent_data;
|
||||
|
||||
/* The window rect clip doesn't need any specific data because it
|
||||
just adds to the scissor clip */
|
||||
};
|
||||
|
||||
struct _CoglClipStackPrimitive
|
||||
{
|
||||
CoglClipStack _parent_data;
|
||||
|
||||
/* The matrix that was current when the clip was set */
|
||||
CoglMatrixEntry *matrix_entry;
|
||||
|
||||
CoglPrimitive *primitive;
|
||||
|
||||
float bounds_x1;
|
||||
float bounds_y1;
|
||||
float bounds_x2;
|
||||
float bounds_y2;
|
||||
};
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_push_window_rectangle (CoglClipStack *stack,
|
||||
int x_offset,
|
||||
int y_offset,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_push_rectangle (CoglClipStack *stack,
|
||||
float x_1,
|
||||
float y_1,
|
||||
float x_2,
|
||||
float y_2,
|
||||
CoglMatrixEntry *modelview_entry,
|
||||
CoglMatrixEntry *projection_entry,
|
||||
const float *viewport);
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_push_primitive (CoglClipStack *stack,
|
||||
CoglPrimitive *primitive,
|
||||
float bounds_x1,
|
||||
float bounds_y1,
|
||||
float bounds_x2,
|
||||
float bounds_y2,
|
||||
CoglMatrixEntry *modelview_entry,
|
||||
CoglMatrixEntry *projection_entry,
|
||||
const float *viewport);
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_pop (CoglClipStack *stack);
|
||||
|
||||
void
|
||||
_cogl_clip_stack_get_bounds (CoglClipStack *stack,
|
||||
int *scissor_x0,
|
||||
int *scissor_y0,
|
||||
int *scissor_x1,
|
||||
int *scissor_y1);
|
||||
|
||||
void
|
||||
_cogl_clip_stack_flush (CoglClipStack *stack,
|
||||
CoglFramebuffer *framebuffer);
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_ref (CoglClipStack *stack);
|
||||
|
||||
void
|
||||
_cogl_clip_stack_unref (CoglClipStack *stack);
|
||||
|
||||
#endif /* __COGL_CLIP_STACK_H */
|
118
cogl/cogl/cogl-closure-list-private.h
Normal file
118
cogl/cogl/cogl-closure-list-private.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2012,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_CLOSURE_LIST_PRIVATE_H_
|
||||
#define _COGL_CLOSURE_LIST_PRIVATE_H_
|
||||
|
||||
#include "cogl-object.h"
|
||||
#include "cogl-list.h"
|
||||
|
||||
/*
|
||||
* This implements a list of callbacks that can be used a bit like
|
||||
* signals in GObject, but that don't have any marshalling overhead.
|
||||
*
|
||||
* The idea is that any Cogl code that wants to provide a callback
|
||||
* point will provide api to add a callback for that particular point.
|
||||
* The function can take a function pointer with the correct
|
||||
* signature. Internally the Cogl code can use _cogl_closure_list_add,
|
||||
* _cogl_closure_disconnect and _cogl_closure_list_disconnect_all
|
||||
*
|
||||
* In the future we could consider exposing the CoglClosure type which
|
||||
* would allow applications to use _cogl_closure_disconnect() directly
|
||||
* so we don't need to expose new disconnect apis for each callback
|
||||
* point.
|
||||
*/
|
||||
|
||||
typedef struct _CoglClosure
|
||||
{
|
||||
CoglList link;
|
||||
|
||||
void *function;
|
||||
void *user_data;
|
||||
CoglUserDataDestroyCallback destroy_cb;
|
||||
} CoglClosure;
|
||||
|
||||
/*
|
||||
* _cogl_closure_disconnect:
|
||||
* @closure: A closure connected to a Cogl closure list
|
||||
*
|
||||
* Removes the given closure from the callback list it is connected to
|
||||
* and destroys it. If the closure was created with a destroy function
|
||||
* then it will be invoked. */
|
||||
void
|
||||
_cogl_closure_disconnect (CoglClosure *closure);
|
||||
|
||||
void
|
||||
_cogl_closure_list_disconnect_all (CoglList *list);
|
||||
|
||||
CoglClosure *
|
||||
_cogl_closure_list_add (CoglList *list,
|
||||
void *function,
|
||||
void *user_data,
|
||||
CoglUserDataDestroyCallback destroy_cb);
|
||||
|
||||
/*
|
||||
* _cogl_closure_list_invoke:
|
||||
* @list: A pointer to a CoglList containing CoglClosures
|
||||
* @cb_type: The name of a typedef for the closure callback function signature
|
||||
* @...: The the arguments to pass to the callback
|
||||
*
|
||||
* A convenience macro to invoke a closure list with a variable number
|
||||
* of arguments that will be passed to the closure callback functions.
|
||||
*
|
||||
* Note that the arguments will be evaluated multiple times so it is
|
||||
* not safe to pass expressions that have side-effects.
|
||||
*
|
||||
* Note also that this function ignores the return value from the
|
||||
* callbacks. If you want to handle the return value you should
|
||||
* manually iterate the list and invoke the callbacks yourself.
|
||||
*/
|
||||
#define _cogl_closure_list_invoke(list, cb_type, ...) \
|
||||
G_STMT_START { \
|
||||
CoglClosure *_c, *_tmp; \
|
||||
\
|
||||
_cogl_list_for_each_safe (_c, _tmp, (list), link) \
|
||||
{ \
|
||||
cb_type _cb = _c->function; \
|
||||
_cb (__VA_ARGS__, _c->user_data); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define _cogl_closure_list_invoke_no_args(list) \
|
||||
G_STMT_START { \
|
||||
CoglClosure *_c, *_tmp; \
|
||||
\
|
||||
_cogl_list_for_each_safe (_c, _tmp, (list), link) \
|
||||
{ \
|
||||
void (*_cb)(void *) = _c->function; \
|
||||
_cb (_c->user_data); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#endif /* _COGL_CLOSURE_LIST_PRIVATE_H_ */
|
71
cogl/cogl/cogl-closure-list.c
Normal file
71
cogl/cogl/cogl-closure-list.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2012,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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "cogl-closure-list-private.h"
|
||||
|
||||
void
|
||||
_cogl_closure_disconnect (CoglClosure *closure)
|
||||
{
|
||||
_cogl_list_remove (&closure->link);
|
||||
|
||||
if (closure->destroy_cb)
|
||||
closure->destroy_cb (closure->user_data);
|
||||
|
||||
g_slice_free (CoglClosure, closure);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_closure_list_disconnect_all (CoglList *list)
|
||||
{
|
||||
CoglClosure *closure, *next;
|
||||
|
||||
_cogl_list_for_each_safe (closure, next, list, link)
|
||||
_cogl_closure_disconnect (closure);
|
||||
}
|
||||
|
||||
CoglClosure *
|
||||
_cogl_closure_list_add (CoglList *list,
|
||||
void *function,
|
||||
void *user_data,
|
||||
CoglUserDataDestroyCallback destroy_cb)
|
||||
{
|
||||
CoglClosure *closure = g_slice_new (CoglClosure);
|
||||
|
||||
closure->function = function;
|
||||
closure->user_data = user_data;
|
||||
closure->destroy_cb = destroy_cb;
|
||||
|
||||
_cogl_list_insert (list, &closure->link);
|
||||
|
||||
return closure;
|
||||
}
|
51
cogl/cogl/cogl-color-private.h
Normal file
51
cogl/cogl/cogl-color-private.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __COGL_COLOR_PRIVATE_PRIVATE_H
|
||||
#define __COGL_COLOR_PRIVATE_PRIVATE_H
|
||||
|
||||
#include "cogl-color.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/* cogl-pipeline.c wants to be able to hash CoglColor data so it needs
|
||||
* the exact data size to be able to avoid reading the padding bytes.
|
||||
*/
|
||||
#define _COGL_COLOR_DATA_SIZE 4
|
||||
|
||||
void
|
||||
_cogl_color_get_rgba_4ubv (const CoglColor *color,
|
||||
uint8_t *dest);
|
||||
|
||||
#endif /* __COGL_COLOR_PRIVATE_PRIVATE_H */
|
||||
|
449
cogl/cogl/cogl-color.c
Normal file
449
cogl/cogl/cogl-color.c
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2008,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 <string.h>
|
||||
|
||||
#include "cogl-util.h"
|
||||
#include "cogl-color.h"
|
||||
#include "cogl-fixed.h"
|
||||
#include "cogl-color-private.h"
|
||||
#include "cogl-gtype-private.h"
|
||||
|
||||
COGL_GTYPE_DEFINE_BOXED (Color, color, cogl_color_copy, cogl_color_free);
|
||||
|
||||
CoglColor *
|
||||
cogl_color_new (void)
|
||||
{
|
||||
return g_slice_new (CoglColor);
|
||||
}
|
||||
|
||||
CoglColor *
|
||||
cogl_color_copy (const CoglColor *color)
|
||||
{
|
||||
if (G_LIKELY (color))
|
||||
return g_slice_dup (CoglColor, color);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_free (CoglColor *color)
|
||||
{
|
||||
if (G_LIKELY (color))
|
||||
g_slice_free (CoglColor, color);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_init_from_4ub (CoglColor *color,
|
||||
uint8_t red,
|
||||
uint8_t green,
|
||||
uint8_t blue,
|
||||
uint8_t alpha)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (color != NULL);
|
||||
|
||||
color->red = red;
|
||||
color->green = green;
|
||||
color->blue = blue;
|
||||
color->alpha = alpha;
|
||||
}
|
||||
|
||||
/* XXX: deprecated, use cogl_color_init_from_4ub */
|
||||
void
|
||||
cogl_color_set_from_4ub (CoglColor *dest,
|
||||
uint8_t red,
|
||||
uint8_t green,
|
||||
uint8_t blue,
|
||||
uint8_t alpha)
|
||||
{
|
||||
cogl_color_init_from_4ub (dest, red, green, blue, alpha);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_init_from_4f (CoglColor *color,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (color != NULL);
|
||||
|
||||
color->red = (red * 255);
|
||||
color->green = (green * 255);
|
||||
color->blue = (blue * 255);
|
||||
color->alpha = (alpha * 255);
|
||||
}
|
||||
|
||||
/* XXX: deprecated, use cogl_color_init_from_4f */
|
||||
void
|
||||
cogl_color_set_from_4f (CoglColor *color,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha)
|
||||
{
|
||||
cogl_color_init_from_4f (color, red, green, blue, alpha);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_init_from_4fv (CoglColor *color,
|
||||
const float *color_array)
|
||||
{
|
||||
_COGL_RETURN_IF_FAIL (color != NULL);
|
||||
|
||||
color->red = (color_array[0] * 255);
|
||||
color->green = (color_array[1] * 255);
|
||||
color->blue = (color_array[2] * 255);
|
||||
color->alpha = (color_array[3] * 255);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
cogl_color_get_red_byte (const CoglColor *color)
|
||||
{
|
||||
return color->red;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_red_float (const CoglColor *color)
|
||||
{
|
||||
return (float) color->red / 255.0;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_red (const CoglColor *color)
|
||||
{
|
||||
return ((float) color->red / 255.0);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
cogl_color_get_green_byte (const CoglColor *color)
|
||||
{
|
||||
return color->green;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_green_float (const CoglColor *color)
|
||||
{
|
||||
return (float) color->green / 255.0;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_green (const CoglColor *color)
|
||||
{
|
||||
return ((float) color->green / 255.0);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
cogl_color_get_blue_byte (const CoglColor *color)
|
||||
{
|
||||
return color->blue;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_blue_float (const CoglColor *color)
|
||||
{
|
||||
return (float) color->blue / 255.0;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_blue (const CoglColor *color)
|
||||
{
|
||||
return ((float) color->blue / 255.0);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
cogl_color_get_alpha_byte (const CoglColor *color)
|
||||
{
|
||||
return color->alpha;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_alpha_float (const CoglColor *color)
|
||||
{
|
||||
return (float) color->alpha / 255.0;
|
||||
}
|
||||
|
||||
float
|
||||
cogl_color_get_alpha (const CoglColor *color)
|
||||
{
|
||||
return ((float) color->alpha / 255.0);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_red_byte (CoglColor *color,
|
||||
unsigned char red)
|
||||
{
|
||||
color->red = red;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_red_float (CoglColor *color,
|
||||
float red)
|
||||
{
|
||||
color->red = red * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_red (CoglColor *color,
|
||||
float red)
|
||||
{
|
||||
color->red = red * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_green_byte (CoglColor *color,
|
||||
unsigned char green)
|
||||
{
|
||||
color->green = green;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_green_float (CoglColor *color,
|
||||
float green)
|
||||
{
|
||||
color->green = green * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_green (CoglColor *color,
|
||||
float green)
|
||||
{
|
||||
color->green = green * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_blue_byte (CoglColor *color,
|
||||
unsigned char blue)
|
||||
{
|
||||
color->blue = blue;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_blue_float (CoglColor *color,
|
||||
float blue)
|
||||
{
|
||||
color->blue = blue * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_blue (CoglColor *color,
|
||||
float blue)
|
||||
{
|
||||
color->blue = blue * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_alpha_byte (CoglColor *color,
|
||||
unsigned char alpha)
|
||||
{
|
||||
color->alpha = alpha;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_alpha_float (CoglColor *color,
|
||||
float alpha)
|
||||
{
|
||||
color->alpha = alpha * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_set_alpha (CoglColor *color,
|
||||
float alpha)
|
||||
{
|
||||
color->alpha = alpha * 255.0;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_premultiply (CoglColor *color)
|
||||
{
|
||||
color->red = (color->red * color->alpha + 128) / 255;
|
||||
color->green = (color->green * color->alpha + 128) / 255;
|
||||
color->blue = (color->blue * color->alpha + 128) / 255;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_unpremultiply (CoglColor *color)
|
||||
{
|
||||
if (color->alpha != 0)
|
||||
{
|
||||
color->red = (color->red * 255) / color->alpha;
|
||||
color->green = (color->green * 255) / color->alpha;
|
||||
color->blue = (color->blue * 255) / color->alpha;
|
||||
}
|
||||
}
|
||||
|
||||
CoglBool
|
||||
cogl_color_equal (const void *v1, const void *v2)
|
||||
{
|
||||
const uint32_t *c1 = v1, *c2 = v2;
|
||||
|
||||
_COGL_RETURN_VAL_IF_FAIL (v1 != NULL, FALSE);
|
||||
_COGL_RETURN_VAL_IF_FAIL (v2 != NULL, FALSE);
|
||||
|
||||
/* XXX: We don't compare the padding */
|
||||
return *c1 == *c2 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_color_get_rgba_4ubv (const CoglColor *color,
|
||||
uint8_t *dest)
|
||||
{
|
||||
memcpy (dest, color, 4);
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_to_hsl (const CoglColor *color,
|
||||
float *hue,
|
||||
float *saturation,
|
||||
float *luminance)
|
||||
{
|
||||
float red, green, blue;
|
||||
float min, max, delta;
|
||||
float h, l, s;
|
||||
|
||||
red = color->red / 255.0;
|
||||
green = color->green / 255.0;
|
||||
blue = color->blue / 255.0;
|
||||
|
||||
if (red > green)
|
||||
{
|
||||
if (red > blue)
|
||||
max = red;
|
||||
else
|
||||
max = blue;
|
||||
|
||||
if (green < blue)
|
||||
min = green;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (green > blue)
|
||||
max = green;
|
||||
else
|
||||
max = blue;
|
||||
|
||||
if (red < blue)
|
||||
min = red;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
|
||||
l = (max + min) / 2;
|
||||
s = 0;
|
||||
h = 0;
|
||||
|
||||
if (max != min)
|
||||
{
|
||||
if (l <= 0.5)
|
||||
s = (max - min) / (max + min);
|
||||
else
|
||||
s = (max - min) / (2.0 - max - min);
|
||||
|
||||
delta = max - min;
|
||||
|
||||
if (red == max)
|
||||
h = (green - blue) / delta;
|
||||
else if (green == max)
|
||||
h = 2.0 + (blue - red) / delta;
|
||||
else if (blue == max)
|
||||
h = 4.0 + (red - green) / delta;
|
||||
|
||||
h *= 60;
|
||||
|
||||
if (h < 0)
|
||||
h += 360.0;
|
||||
}
|
||||
|
||||
if (hue)
|
||||
*hue = h;
|
||||
|
||||
if (luminance)
|
||||
*luminance = l;
|
||||
|
||||
if (saturation)
|
||||
*saturation = s;
|
||||
}
|
||||
|
||||
void
|
||||
cogl_color_init_from_hsl (CoglColor *color,
|
||||
float hue,
|
||||
float saturation,
|
||||
float luminance)
|
||||
{
|
||||
float tmp1, tmp2;
|
||||
float tmp3[3];
|
||||
float clr[3];
|
||||
int i;
|
||||
|
||||
hue /= 360.0;
|
||||
|
||||
if (saturation == 0)
|
||||
{
|
||||
cogl_color_init_from_4f (color, luminance, luminance, luminance, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (luminance <= 0.5)
|
||||
tmp2 = luminance * (1.0 + saturation);
|
||||
else
|
||||
tmp2 = luminance + saturation - (luminance * saturation);
|
||||
|
||||
tmp1 = 2.0 * luminance - tmp2;
|
||||
|
||||
tmp3[0] = hue + 1.0 / 3.0;
|
||||
tmp3[1] = hue;
|
||||
tmp3[2] = hue - 1.0 / 3.0;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (tmp3[i] < 0)
|
||||
tmp3[i] += 1.0;
|
||||
|
||||
if (tmp3[i] > 1)
|
||||
tmp3[i] -= 1.0;
|
||||
|
||||
if (6.0 * tmp3[i] < 1.0)
|
||||
clr[i] = tmp1 + (tmp2 - tmp1) * tmp3[i] * 6.0;
|
||||
else if (2.0 * tmp3[i] < 1.0)
|
||||
clr[i] = tmp2;
|
||||
else if (3.0 * tmp3[i] < 2.0)
|
||||
clr[i] = (tmp1 + (tmp2 - tmp1) * ((2.0 / 3.0) - tmp3[i]) * 6.0);
|
||||
else
|
||||
clr[i] = tmp1;
|
||||
}
|
||||
|
||||
cogl_color_init_from_4f (color, clr[0], clr[1], clr[2], 1.0f);
|
||||
}
|
604
cogl/cogl/cogl-color.h
Normal file
604
cogl/cogl/cogl-color.h
Normal file
@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Cogl
|
||||
*
|
||||
* A Low Level GPU Graphics and Utilities API
|
||||
*
|
||||
* Copyright (C) 2008,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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
|
||||
#error "Only <cogl/cogl.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __COGL_COLOR_H__
|
||||
#define __COGL_COLOR_H__
|
||||
|
||||
/**
|
||||
* SECTION:cogl-color
|
||||
* @short_description: A generic color definition
|
||||
*
|
||||
* #CoglColor is a simple structure holding the definition of a color such
|
||||
* that it can be efficiently used by GL
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
|
||||
#include <cogl/cogl-types.h>
|
||||
#include <cogl/cogl-macros.h>
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
#include <glib-object.h>
|
||||
#endif
|
||||
|
||||
COGL_BEGIN_DECLS
|
||||
|
||||
#ifdef COGL_HAS_GTYPE_SUPPORT
|
||||
/**
|
||||
* cogl_color_get_gtype:
|
||||
*
|
||||
* Returns: a #GType that can be used with the GLib type system.
|
||||
*/
|
||||
GType cogl_color_get_gtype (void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cogl_color_new:
|
||||
*
|
||||
* Creates a new (empty) color
|
||||
*
|
||||
* Return value: a newly-allocated #CoglColor. Use cogl_color_free()
|
||||
* to free the allocated resources
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
CoglColor *
|
||||
cogl_color_new (void);
|
||||
|
||||
/**
|
||||
* cogl_color_copy:
|
||||
* @color: the color to copy
|
||||
*
|
||||
* Creates a copy of @color
|
||||
*
|
||||
* Return value: a newly-allocated #CoglColor. Use cogl_color_free()
|
||||
* to free the allocate resources
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
CoglColor *
|
||||
cogl_color_copy (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_free:
|
||||
* @color: the color to free
|
||||
*
|
||||
* Frees the resources allocated by cogl_color_new() and cogl_color_copy()
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void
|
||||
cogl_color_free (CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_init_from_4ub:
|
||||
* @color: A pointer to a #CoglColor to initialize
|
||||
* @red: value of the red channel, between 0 and 255
|
||||
* @green: value of the green channel, between 0 and 255
|
||||
* @blue: value of the blue channel, between 0 and 255
|
||||
* @alpha: value of the alpha channel, between 0 and 255
|
||||
*
|
||||
* Sets the values of the passed channels into a #CoglColor.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_init_from_4ub (CoglColor *color,
|
||||
uint8_t red,
|
||||
uint8_t green,
|
||||
uint8_t blue,
|
||||
uint8_t alpha);
|
||||
|
||||
/**
|
||||
* cogl_color_set_from_4ub:
|
||||
* @color: A pointer to a #CoglColor to initialize
|
||||
* @red: value of the red channel, between 0 and 255
|
||||
* @green: value of the green channel, between 0 and 255
|
||||
* @blue: value of the blue channel, between 0 and 255
|
||||
* @alpha: value of the alpha channel, between 0 and 255
|
||||
*
|
||||
* Sets the values of the passed channels into a #CoglColor.
|
||||
*
|
||||
* Since: 1.0
|
||||
* Deprecated: 1.4: Use cogl_color_init_from_4ub instead.
|
||||
*/
|
||||
COGL_DEPRECATED_IN_1_4_FOR (cogl_color_init_from_4ub)
|
||||
void
|
||||
cogl_color_set_from_4ub (CoglColor *color,
|
||||
uint8_t red,
|
||||
uint8_t green,
|
||||
uint8_t blue,
|
||||
uint8_t alpha);
|
||||
|
||||
/**
|
||||
* cogl_color_init_from_4f:
|
||||
* @color: A pointer to a #CoglColor to initialize
|
||||
* @red: value of the red channel, between 0 and 1.0
|
||||
* @green: value of the green channel, between 0 and 1.0
|
||||
* @blue: value of the blue channel, between 0 and 1.0
|
||||
* @alpha: value of the alpha channel, between 0 and 1.0
|
||||
*
|
||||
* Sets the values of the passed channels into a #CoglColor
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_init_from_4f (CoglColor *color,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha);
|
||||
|
||||
/**
|
||||
* cogl_color_set_from_4f:
|
||||
* @color: A pointer to a #CoglColor to initialize
|
||||
* @red: value of the red channel, between 0 and %1.0
|
||||
* @green: value of the green channel, between 0 and %1.0
|
||||
* @blue: value of the blue channel, between 0 and %1.0
|
||||
* @alpha: value of the alpha channel, between 0 and %1.0
|
||||
*
|
||||
* Sets the values of the passed channels into a #CoglColor
|
||||
*
|
||||
* Since: 1.0
|
||||
* Deprecated: 1.4: Use cogl_color_init_from_4f instead.
|
||||
*/
|
||||
COGL_DEPRECATED_IN_1_4_FOR (cogl_color_init_from_4f)
|
||||
void
|
||||
cogl_color_set_from_4f (CoglColor *color,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha);
|
||||
|
||||
/**
|
||||
* cogl_color_init_from_4fv:
|
||||
* @color: A pointer to a #CoglColor to initialize
|
||||
* @color_array: a pointer to an array of 4 float color components
|
||||
*
|
||||
* Sets the values of the passed channels into a #CoglColor
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_init_from_4fv (CoglColor *color,
|
||||
const float *color_array);
|
||||
|
||||
/**
|
||||
* cogl_color_get_red_byte:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the red channel of @color as a byte value
|
||||
* between 0 and 255
|
||||
*
|
||||
* Return value: the red channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
unsigned char
|
||||
cogl_color_get_red_byte (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_green_byte:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the green channel of @color as a byte value
|
||||
* between 0 and 255
|
||||
*
|
||||
* Return value: the green channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
unsigned char
|
||||
cogl_color_get_green_byte (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_blue_byte:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the blue channel of @color as a byte value
|
||||
* between 0 and 255
|
||||
*
|
||||
* Return value: the blue channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
unsigned char
|
||||
cogl_color_get_blue_byte (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_alpha_byte:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the alpha channel of @color as a byte value
|
||||
* between 0 and 255
|
||||
*
|
||||
* Return value: the alpha channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
unsigned char
|
||||
cogl_color_get_alpha_byte (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_red_float:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the red channel of @color as a floating point
|
||||
* value between 0.0 and 1.0
|
||||
*
|
||||
* Return value: the red channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_red_float (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_green_float:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the green channel of @color as a floating point
|
||||
* value between 0.0 and 1.0
|
||||
*
|
||||
* Return value: the green channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_green_float (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_blue_float:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the blue channel of @color as a floating point
|
||||
* value between 0.0 and 1.0
|
||||
*
|
||||
* Return value: the blue channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_blue_float (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_alpha_float:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the alpha channel of @color as a floating point
|
||||
* value between 0.0 and 1.0
|
||||
*
|
||||
* Return value: the alpha channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_alpha_float (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_red:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the red channel of @color as a fixed point
|
||||
* value between 0 and 1.0.
|
||||
*
|
||||
* Return value: the red channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_red (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_green:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the green channel of @color as a fixed point
|
||||
* value between 0 and 1.0.
|
||||
*
|
||||
* Return value: the green channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_green (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_blue:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the blue channel of @color as a fixed point
|
||||
* value between 0 and 1.0.
|
||||
*
|
||||
* Return value: the blue channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_blue (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_get_alpha:
|
||||
* @color: a #CoglColor
|
||||
*
|
||||
* Retrieves the alpha channel of @color as a fixed point
|
||||
* value between 0 and 1.0.
|
||||
*
|
||||
* Return value: the alpha channel of the passed color
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
float
|
||||
cogl_color_get_alpha (const CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_set_red_byte:
|
||||
* @color: a #CoglColor
|
||||
* @red: a byte value between 0 and 255
|
||||
*
|
||||
* Sets the red channel of @color to @red.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_red_byte (CoglColor *color,
|
||||
unsigned char red);
|
||||
|
||||
/**
|
||||
* cogl_color_set_green_byte:
|
||||
* @color: a #CoglColor
|
||||
* @green: a byte value between 0 and 255
|
||||
*
|
||||
* Sets the green channel of @color to @green.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_green_byte (CoglColor *color,
|
||||
unsigned char green);
|
||||
|
||||
/**
|
||||
* cogl_color_set_blue_byte:
|
||||
* @color: a #CoglColor
|
||||
* @blue: a byte value between 0 and 255
|
||||
*
|
||||
* Sets the blue channel of @color to @blue.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_blue_byte (CoglColor *color,
|
||||
unsigned char blue);
|
||||
|
||||
/**
|
||||
* cogl_color_set_alpha_byte:
|
||||
* @color: a #CoglColor
|
||||
* @alpha: a byte value between 0 and 255
|
||||
*
|
||||
* Sets the alpha channel of @color to @alpha.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_alpha_byte (CoglColor *color,
|
||||
unsigned char alpha);
|
||||
|
||||
/**
|
||||
* cogl_color_set_red_float:
|
||||
* @color: a #CoglColor
|
||||
* @red: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the red channel of @color to @red.
|
||||
*
|
||||
* since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_red_float (CoglColor *color,
|
||||
float red);
|
||||
|
||||
/**
|
||||
* cogl_color_set_green_float:
|
||||
* @color: a #CoglColor
|
||||
* @green: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the green channel of @color to @green.
|
||||
*
|
||||
* since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_green_float (CoglColor *color,
|
||||
float green);
|
||||
|
||||
/**
|
||||
* cogl_color_set_blue_float:
|
||||
* @color: a #CoglColor
|
||||
* @blue: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the blue channel of @color to @blue.
|
||||
*
|
||||
* since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_blue_float (CoglColor *color,
|
||||
float blue);
|
||||
|
||||
/**
|
||||
* cogl_color_set_alpha_float:
|
||||
* @color: a #CoglColor
|
||||
* @alpha: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the alpha channel of @color to @alpha.
|
||||
*
|
||||
* since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_alpha_float (CoglColor *color,
|
||||
float alpha);
|
||||
|
||||
/**
|
||||
* cogl_color_set_red:
|
||||
* @color: a #CoglColor
|
||||
* @red: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the red channel of @color to @red.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_red (CoglColor *color,
|
||||
float red);
|
||||
|
||||
/**
|
||||
* cogl_color_set_green:
|
||||
* @color: a #CoglColor
|
||||
* @green: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the green channel of @color to @green.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_green (CoglColor *color,
|
||||
float green);
|
||||
|
||||
/**
|
||||
* cogl_color_set_blue:
|
||||
* @color: a #CoglColor
|
||||
* @blue: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the blue channel of @color to @blue.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_blue (CoglColor *color,
|
||||
float blue);
|
||||
|
||||
/**
|
||||
* cogl_color_set_alpha:
|
||||
* @color: a #CoglColor
|
||||
* @alpha: a float value between 0.0f and 1.0f
|
||||
*
|
||||
* Sets the alpha channel of @color to @alpha.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_set_alpha (CoglColor *color,
|
||||
float alpha);
|
||||
|
||||
/**
|
||||
* cogl_color_premultiply:
|
||||
* @color: the color to premultiply
|
||||
*
|
||||
* Converts a non-premultiplied color to a pre-multiplied color. For
|
||||
* example, semi-transparent red is (1.0, 0, 0, 0.5) when non-premultiplied
|
||||
* and (0.5, 0, 0, 0.5) when premultiplied.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void
|
||||
cogl_color_premultiply (CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_unpremultiply:
|
||||
* @color: the color to unpremultiply
|
||||
*
|
||||
* Converts a pre-multiplied color to a non-premultiplied color. For
|
||||
* example, semi-transparent red is (0.5, 0, 0, 0.5) when premultiplied
|
||||
* and (1.0, 0, 0, 0.5) when non-premultiplied.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void
|
||||
cogl_color_unpremultiply (CoglColor *color);
|
||||
|
||||
/**
|
||||
* cogl_color_equal:
|
||||
* @v1: a #CoglColor
|
||||
* @v2: a #CoglColor
|
||||
*
|
||||
* Compares two #CoglColor<!-- -->s and checks if they are the same.
|
||||
*
|
||||
* This function can be passed to g_hash_table_new() as the @key_equal_func
|
||||
* parameter, when using #CoglColor<!-- -->s as keys in a #GHashTable.
|
||||
*
|
||||
* Return value: %TRUE if the two colors are the same.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
CoglBool
|
||||
cogl_color_equal (const void *v1, const void *v2);
|
||||
|
||||
/**
|
||||
* cogl_color_to_hsl:
|
||||
* @color: a #CoglColor
|
||||
* @hue: (out): return location for the hue value or %NULL
|
||||
* @saturation: (out): return location for the saturation value or %NULL
|
||||
* @luminance: (out): return location for the luminance value or %NULL
|
||||
*
|
||||
* Converts @color to the HLS format.
|
||||
*
|
||||
* The @hue value is in the 0 .. 360 range. The @luminance and
|
||||
* @saturation values are in the 0 .. 1 range.
|
||||
*
|
||||
* Since: 1.16
|
||||
*/
|
||||
void
|
||||
cogl_color_to_hsl (const CoglColor *color,
|
||||
float *hue,
|
||||
float *saturation,
|
||||
float *luminance);
|
||||
|
||||
/**
|
||||
* cogl_color_init_from_hsl:
|
||||
* @color: (out): return location for a #CoglColor
|
||||
* @hue: hue value, in the 0 .. 360 range
|
||||
* @saturation: saturation value, in the 0 .. 1 range
|
||||
* @luminance: luminance value, in the 0 .. 1 range
|
||||
*
|
||||
* Converts a color expressed in HLS (hue, luminance and saturation)
|
||||
* values into a #CoglColor.
|
||||
*
|
||||
* Since: 1.16
|
||||
*/
|
||||
void
|
||||
cogl_color_init_from_hsl (CoglColor *color,
|
||||
float hue,
|
||||
float saturation,
|
||||
float luminance);
|
||||
|
||||
COGL_END_DECLS
|
||||
|
||||
#endif /* __COGL_COLOR_H__ */
|
45
cogl/cogl/cogl-config-private.h
Normal file
45
cogl/cogl/cogl-config-private.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __COGL_CONFIG_PRIVATE_H
|
||||
#define __COGL_CONFIG_PRIVATE_H
|
||||
|
||||
void
|
||||
_cogl_config_read (void);
|
||||
|
||||
extern char *_cogl_config_driver;
|
||||
extern char *_cogl_config_renderer;
|
||||
extern char *_cogl_config_disable_gl_extensions;
|
||||
extern char *_cogl_config_override_gl_version;
|
||||
|
||||
#endif /* __COGL_CONFIG_PRIVATE_H */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user