diff options
Diffstat (limited to 'app/gegl')
31 files changed, 8990 insertions, 0 deletions
diff --git a/app/gegl/Makefile.am b/app/gegl/Makefile.am new file mode 100644 index 0000000..e402056 --- /dev/null +++ b/app/gegl/Makefile.am @@ -0,0 +1,99 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-GEGL\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libappgegl-generic.a \ + libappgegl-sse2.a \ + libappgegl.a + +libappgegl_generic_a_sources = \ + gimp-gegl-enums.h \ + gimp-gegl-types.h \ + gimp-babl.c \ + gimp-babl.h \ + gimp-babl-compat.c \ + gimp-babl-compat.h \ + gimp-gegl.c \ + gimp-gegl.h \ + gimp-gegl-apply-operation.c \ + gimp-gegl-apply-operation.h \ + gimp-gegl-loops.cc \ + gimp-gegl-loops.h \ + gimp-gegl-mask.c \ + gimp-gegl-mask.h \ + gimp-gegl-mask-combine.cc \ + gimp-gegl-mask-combine.h \ + gimp-gegl-nodes.c \ + gimp-gegl-nodes.h \ + gimp-gegl-tile-compat.c \ + gimp-gegl-tile-compat.h \ + gimp-gegl-utils.c \ + gimp-gegl-utils.h \ + gimpapplicator.c \ + gimpapplicator.h \ + gimptilehandlervalidate.c \ + gimptilehandlervalidate.h + +libappgegl_generic_a_built_sources = gimp-gegl-enums.c + +libappgegl_sse2_a_sources = \ + gimp-gegl-loops-sse2.c \ + gimp-gegl-loops-sse2.h + +libappgegl_generic_a_SOURCES = $(libappgegl_generic_a_built_sources) $(libappgegl_generic_a_sources) + +libappgegl_sse2_a_SOURCES = $(libappgegl_sse2_a_sources) + +libappgegl_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS) + +libappgegl_a_SOURCES = + + +libappgegl.a: libappgegl-generic.a \ + libappgegl-sse2.a + $(AR) $(ARFLAGS) libappgegl.a \ + $(libappgegl_generic_a_OBJECTS) \ + $(libappgegl_sse2_a_OBJECTS) + $(RANLIB) libappgegl.a + + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-ggec +CLEANFILES = $(gen_sources) + +xgen-ggec: $(srcdir)/gimp-gegl-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"core/core-enums.h\"\n#include \"gimp-gegl-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/gimp-gegl-enums.c: xgen-ggec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi diff --git a/app/gegl/Makefile.in b/app/gegl/Makefile.in new file mode 100644 index 0000000..1e9d24b --- /dev/null +++ b/app/gegl/Makefile.in @@ -0,0 +1,1116 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = app/gegl +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/m4macros/alsa.m4 \ + $(top_srcdir)/m4macros/ax_compare_version.m4 \ + $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \ + $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \ + $(top_srcdir)/m4macros/detectcflags.m4 \ + $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libappgegl_generic_a_AR = $(AR) $(ARFLAGS) +libappgegl_generic_a_LIBADD = +am__objects_1 = gimp-gegl-enums.$(OBJEXT) +am__objects_2 = gimp-babl.$(OBJEXT) gimp-babl-compat.$(OBJEXT) \ + gimp-gegl.$(OBJEXT) gimp-gegl-apply-operation.$(OBJEXT) \ + gimp-gegl-loops.$(OBJEXT) gimp-gegl-mask.$(OBJEXT) \ + gimp-gegl-mask-combine.$(OBJEXT) gimp-gegl-nodes.$(OBJEXT) \ + gimp-gegl-tile-compat.$(OBJEXT) gimp-gegl-utils.$(OBJEXT) \ + gimpapplicator.$(OBJEXT) gimptilehandlervalidate.$(OBJEXT) +am_libappgegl_generic_a_OBJECTS = $(am__objects_1) $(am__objects_2) +libappgegl_generic_a_OBJECTS = $(am_libappgegl_generic_a_OBJECTS) +libappgegl_sse2_a_AR = $(AR) $(ARFLAGS) +libappgegl_sse2_a_LIBADD = +am__objects_3 = libappgegl_sse2_a-gimp-gegl-loops-sse2.$(OBJEXT) +am_libappgegl_sse2_a_OBJECTS = $(am__objects_3) +libappgegl_sse2_a_OBJECTS = $(am_libappgegl_sse2_a_OBJECTS) +libappgegl_a_AR = $(AR) $(ARFLAGS) +libappgegl_a_LIBADD = +am_libappgegl_a_OBJECTS = +libappgegl_a_OBJECTS = $(am_libappgegl_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/gimp-babl-compat.Po \ + ./$(DEPDIR)/gimp-babl.Po \ + ./$(DEPDIR)/gimp-gegl-apply-operation.Po \ + ./$(DEPDIR)/gimp-gegl-enums.Po ./$(DEPDIR)/gimp-gegl-loops.Po \ + ./$(DEPDIR)/gimp-gegl-mask-combine.Po \ + ./$(DEPDIR)/gimp-gegl-mask.Po ./$(DEPDIR)/gimp-gegl-nodes.Po \ + ./$(DEPDIR)/gimp-gegl-tile-compat.Po \ + ./$(DEPDIR)/gimp-gegl-utils.Po ./$(DEPDIR)/gimp-gegl.Po \ + ./$(DEPDIR)/gimpapplicator.Po \ + ./$(DEPDIR)/gimptilehandlervalidate.Po \ + ./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po +am__mv = mv -f +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(libappgegl_generic_a_SOURCES) $(libappgegl_sse2_a_SOURCES) \ + $(libappgegl_a_SOURCES) +DIST_SOURCES = $(libappgegl_generic_a_SOURCES) \ + $(libappgegl_sse2_a_SOURCES) $(libappgegl_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +AA_LIBS = @AA_LIBS@ +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +ALL_LINGUAS = @ALL_LINGUAS@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPSTREAM_UTIL = @APPSTREAM_UTIL@ +AR = @AR@ +AS = @AS@ +ATK_CFLAGS = @ATK_CFLAGS@ +ATK_LIBS = @ATK_LIBS@ +ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BABL_CFLAGS = @BABL_CFLAGS@ +BABL_LIBS = @BABL_LIBS@ +BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@ +BUG_REPORT_URL = @BUG_REPORT_URL@ +BUILD_EXEEXT = @BUILD_EXEEXT@ +BUILD_OBJEXT = @BUILD_OBJEXT@ +BZIP2_LIBS = @BZIP2_LIBS@ +CAIRO_CFLAGS = @CAIRO_CFLAGS@ +CAIRO_LIBS = @CAIRO_LIBS@ +CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@ +CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@ +CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@ +CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CC_VERSION = @CC_VERSION@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CPP_FOR_BUILD = @CPP_FOR_BUILD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DESKTOP_DATADIR = @DESKTOP_DATADIR@ +DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@ +DLLTOOL = @DLLTOOL@ +DOC_SHOOTER = @DOC_SHOOTER@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILE_AA = @FILE_AA@ +FILE_EXR = @FILE_EXR@ +FILE_HEIF = @FILE_HEIF@ +FILE_JP2_LOAD = @FILE_JP2_LOAD@ +FILE_JPEGXL = @FILE_JPEGXL@ +FILE_MNG = @FILE_MNG@ +FILE_PDF_SAVE = @FILE_PDF_SAVE@ +FILE_PS = @FILE_PS@ +FILE_WMF = @FILE_WMF@ +FILE_XMC = @FILE_XMC@ +FILE_XPM = @FILE_XPM@ +FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ +FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ +FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@ +FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +GDBUS_CODEGEN = @GDBUS_CODEGEN@ +GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@ +GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@ +GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@ +GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@ +GEGL = @GEGL@ +GEGL_CFLAGS = @GEGL_CFLAGS@ +GEGL_LIBS = @GEGL_LIBS@ +GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@ +GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GEXIV2_CFLAGS = @GEXIV2_CFLAGS@ +GEXIV2_LIBS = @GEXIV2_LIBS@ +GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@ +GIMP_API_VERSION = @GIMP_API_VERSION@ +GIMP_APP_VERSION = @GIMP_APP_VERSION@ +GIMP_BINARY_AGE = @GIMP_BINARY_AGE@ +GIMP_COMMAND = @GIMP_COMMAND@ +GIMP_DATA_VERSION = @GIMP_DATA_VERSION@ +GIMP_FULL_NAME = @GIMP_FULL_NAME@ +GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@ +GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@ +GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@ +GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@ +GIMP_MKENUMS = @GIMP_MKENUMS@ +GIMP_MODULES = @GIMP_MODULES@ +GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@ +GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@ +GIMP_PLUGINS = @GIMP_PLUGINS@ +GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@ +GIMP_REAL_VERSION = @GIMP_REAL_VERSION@ +GIMP_RELEASE = @GIMP_RELEASE@ +GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@ +GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@ +GIMP_UNSTABLE = @GIMP_UNSTABLE@ +GIMP_USER_VERSION = @GIMP_USER_VERSION@ +GIMP_VERSION = @GIMP_VERSION@ +GIO_CFLAGS = @GIO_CFLAGS@ +GIO_LIBS = @GIO_LIBS@ +GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@ +GIO_UNIX_LIBS = @GIO_UNIX_LIBS@ +GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@ +GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@ +GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@ +GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GREP = @GREP@ +GS_LIBS = @GS_LIBS@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@ +GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@ +GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@ +GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@ +GUDEV_CFLAGS = @GUDEV_CFLAGS@ +GUDEV_LIBS = @GUDEV_LIBS@ +HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@ +HARFBUZZ_LIBS = @HARFBUZZ_LIBS@ +HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@ +HAVE_CXX14 = @HAVE_CXX14@ +HAVE_FINITE = @HAVE_FINITE@ +HAVE_ISFINITE = @HAVE_ISFINITE@ +HAVE_VFORK = @HAVE_VFORK@ +HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ +INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ +INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ +INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@ +ISO_CODES_LOCATION = @ISO_CODES_LOCATION@ +JPEG_LIBS = @JPEG_LIBS@ +JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@ +JSON_GLIB_LIBS = @JSON_GLIB_LIBS@ +JXL_CFLAGS = @JXL_CFLAGS@ +JXL_LIBS = @JXL_LIBS@ +JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@ +JXL_THREADS_LIBS = @JXL_THREADS_LIBS@ +LCMS_CFLAGS = @LCMS_CFLAGS@ +LCMS_LIBS = @LCMS_LIBS@ +LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@ +LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@ +LIBHEIF_LIBS = @LIBHEIF_LIBS@ +LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@ +LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@ +LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@ +LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@ +LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@ +LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@ +LIBUNWIND_LIBS = @LIBUNWIND_LIBS@ +LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +LZMA_CFLAGS = @LZMA_CFLAGS@ +LZMA_LIBS = @LZMA_LIBS@ +MAIL = @MAIL@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@ +MIME_INFO_LIBS = @MIME_INFO_LIBS@ +MIME_TYPES = @MIME_TYPES@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@ +MNG_CFLAGS = @MNG_CFLAGS@ +MNG_LIBS = @MNG_LIBS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@ +MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@ +NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@ +NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENEXR_CFLAGS = @OPENEXR_CFLAGS@ +OPENEXR_LIBS = @OPENEXR_LIBS@ +OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@ +OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@ +OPENJPEG_LIBS = @OPENJPEG_LIBS@ +OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@ +PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@ +PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@ +PATHSEP = @PATHSEP@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@ +PERL_VERSION = @PERL_VERSION@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PNG_CFLAGS = @PNG_CFLAGS@ +PNG_LIBS = @PNG_LIBS@ +POFILES = @POFILES@ +POPPLER_CFLAGS = @POPPLER_CFLAGS@ +POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@ +POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@ +POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@ +POPPLER_LIBS = @POPPLER_LIBS@ +POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYBIN_PATH = @PYBIN_PATH@ +PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ +PYCAIRO_LIBS = @PYCAIRO_LIBS@ +PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@ +PYGTK_CFLAGS = @PYGTK_CFLAGS@ +PYGTK_CODEGEN = @PYGTK_CODEGEN@ +PYGTK_DEFSDIR = @PYGTK_DEFSDIR@ +PYGTK_LIBS = @PYGTK_LIBS@ +PYLINK_LIBS = @PYLINK_LIBS@ +PYTHON = @PYTHON@ +PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@ +RT_LIBS = @RT_LIBS@ +SCREENSHOT_LIBS = @SCREENSHOT_LIBS@ +SED = @SED@ +SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKET_LIBS = @SOCKET_LIBS@ +SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@ +SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@ +SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@ +STRIP = @STRIP@ +SVG_CFLAGS = @SVG_CFLAGS@ +SVG_LIBS = @SVG_LIBS@ +SYMPREFIX = @SYMPREFIX@ +TIFF_LIBS = @TIFF_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WEBKIT_CFLAGS = @WEBKIT_CFLAGS@ +WEBKIT_LIBS = @WEBKIT_LIBS@ +WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@ +WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@ +WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@ +WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@ +WEBPMUX_LIBS = @WEBPMUX_LIBS@ +WEBP_CFLAGS = @WEBP_CFLAGS@ +WEBP_LIBS = @WEBP_LIBS@ +WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@ +WEB_PAGE = @WEB_PAGE@ +WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@ +WINDRES = @WINDRES@ +WMF_CFLAGS = @WMF_CFLAGS@ +WMF_CONFIG = @WMF_CONFIG@ +WMF_LIBS = @WMF_LIBS@ +WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@ +XDG_EMAIL = @XDG_EMAIL@ +XFIXES_CFLAGS = @XFIXES_CFLAGS@ +XFIXES_LIBS = @XFIXES_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@ +XMC_CFLAGS = @XMC_CFLAGS@ +XMC_LIBS = @XMC_LIBS@ +XMKMF = @XMKMF@ +XMLLINT = @XMLLINT@ +XMU_LIBS = @XMU_LIBS@ +XPM_LIBS = @XPM_LIBS@ +XSLTPROC = @XSLTPROC@ +XVFB_RUN = @XVFB_RUN@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +Z_LIBS = @Z_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gimpdatadir = @gimpdatadir@ +gimpdir = @gimpdir@ +gimplocaledir = @gimplocaledir@ +gimpplugindir = @gimpplugindir@ +gimpsysconfdir = @gimpsysconfdir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +intltool__v_merge_options_ = @intltool__v_merge_options_@ +intltool__v_merge_options_0 = @intltool__v_merge_options_0@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +manpage_gimpdir = @manpage_gimpdir@ +mkdir_p = @mkdir_p@ +ms_librarian = @ms_librarian@ +mypaint_brushes_dir = @mypaint_brushes_dir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-GEGL\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libappgegl-generic.a \ + libappgegl-sse2.a \ + libappgegl.a + +libappgegl_generic_a_sources = \ + gimp-gegl-enums.h \ + gimp-gegl-types.h \ + gimp-babl.c \ + gimp-babl.h \ + gimp-babl-compat.c \ + gimp-babl-compat.h \ + gimp-gegl.c \ + gimp-gegl.h \ + gimp-gegl-apply-operation.c \ + gimp-gegl-apply-operation.h \ + gimp-gegl-loops.cc \ + gimp-gegl-loops.h \ + gimp-gegl-mask.c \ + gimp-gegl-mask.h \ + gimp-gegl-mask-combine.cc \ + gimp-gegl-mask-combine.h \ + gimp-gegl-nodes.c \ + gimp-gegl-nodes.h \ + gimp-gegl-tile-compat.c \ + gimp-gegl-tile-compat.h \ + gimp-gegl-utils.c \ + gimp-gegl-utils.h \ + gimpapplicator.c \ + gimpapplicator.h \ + gimptilehandlervalidate.c \ + gimptilehandlervalidate.h + +libappgegl_generic_a_built_sources = gimp-gegl-enums.c +libappgegl_sse2_a_sources = \ + gimp-gegl-loops-sse2.c \ + gimp-gegl-loops-sse2.h + +libappgegl_generic_a_SOURCES = $(libappgegl_generic_a_built_sources) $(libappgegl_generic_a_sources) +libappgegl_sse2_a_SOURCES = $(libappgegl_sse2_a_sources) +libappgegl_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS) +libappgegl_a_SOURCES = + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-ggec +CLEANFILES = $(gen_sources) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .cc .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu app/gegl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu app/gegl/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libappgegl-generic.a: $(libappgegl_generic_a_OBJECTS) $(libappgegl_generic_a_DEPENDENCIES) $(EXTRA_libappgegl_generic_a_DEPENDENCIES) + $(AM_V_at)-rm -f libappgegl-generic.a + $(AM_V_AR)$(libappgegl_generic_a_AR) libappgegl-generic.a $(libappgegl_generic_a_OBJECTS) $(libappgegl_generic_a_LIBADD) + $(AM_V_at)$(RANLIB) libappgegl-generic.a + +libappgegl-sse2.a: $(libappgegl_sse2_a_OBJECTS) $(libappgegl_sse2_a_DEPENDENCIES) $(EXTRA_libappgegl_sse2_a_DEPENDENCIES) + $(AM_V_at)-rm -f libappgegl-sse2.a + $(AM_V_AR)$(libappgegl_sse2_a_AR) libappgegl-sse2.a $(libappgegl_sse2_a_OBJECTS) $(libappgegl_sse2_a_LIBADD) + $(AM_V_at)$(RANLIB) libappgegl-sse2.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-babl-compat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-babl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-apply-operation.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-enums.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-loops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-mask-combine.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-mask.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-nodes.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-tile-compat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-gegl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpapplicator.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptilehandlervalidate.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libappgegl_sse2_a-gimp-gegl-loops-sse2.o: gimp-gegl-loops-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -MT libappgegl_sse2_a-gimp-gegl-loops-sse2.o -MD -MP -MF $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.o `test -f 'gimp-gegl-loops-sse2.c' || echo '$(srcdir)/'`gimp-gegl-loops-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimp-gegl-loops-sse2.c' object='libappgegl_sse2_a-gimp-gegl-loops-sse2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.o `test -f 'gimp-gegl-loops-sse2.c' || echo '$(srcdir)/'`gimp-gegl-loops-sse2.c + +libappgegl_sse2_a-gimp-gegl-loops-sse2.obj: gimp-gegl-loops-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -MT libappgegl_sse2_a-gimp-gegl-loops-sse2.obj -MD -MP -MF $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.obj `if test -f 'gimp-gegl-loops-sse2.c'; then $(CYGPATH_W) 'gimp-gegl-loops-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimp-gegl-loops-sse2.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Tpo $(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimp-gegl-loops-sse2.c' object='libappgegl_sse2_a-gimp-gegl-loops-sse2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libappgegl_sse2_a_CFLAGS) $(CFLAGS) -c -o libappgegl_sse2_a-gimp-gegl-loops-sse2.obj `if test -f 'gimp-gegl-loops-sse2.c'; then $(CYGPATH_W) 'gimp-gegl-loops-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimp-gegl-loops-sse2.c'; fi` + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gimp-babl-compat.Po + -rm -f ./$(DEPDIR)/gimp-babl.Po + -rm -f ./$(DEPDIR)/gimp-gegl-apply-operation.Po + -rm -f ./$(DEPDIR)/gimp-gegl-enums.Po + -rm -f ./$(DEPDIR)/gimp-gegl-loops.Po + -rm -f ./$(DEPDIR)/gimp-gegl-mask-combine.Po + -rm -f ./$(DEPDIR)/gimp-gegl-mask.Po + -rm -f ./$(DEPDIR)/gimp-gegl-nodes.Po + -rm -f ./$(DEPDIR)/gimp-gegl-tile-compat.Po + -rm -f ./$(DEPDIR)/gimp-gegl-utils.Po + -rm -f ./$(DEPDIR)/gimp-gegl.Po + -rm -f ./$(DEPDIR)/gimpapplicator.Po + -rm -f ./$(DEPDIR)/gimptilehandlervalidate.Po + -rm -f ./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/gimp-babl-compat.Po + -rm -f ./$(DEPDIR)/gimp-babl.Po + -rm -f ./$(DEPDIR)/gimp-gegl-apply-operation.Po + -rm -f ./$(DEPDIR)/gimp-gegl-enums.Po + -rm -f ./$(DEPDIR)/gimp-gegl-loops.Po + -rm -f ./$(DEPDIR)/gimp-gegl-mask-combine.Po + -rm -f ./$(DEPDIR)/gimp-gegl-mask.Po + -rm -f ./$(DEPDIR)/gimp-gegl-nodes.Po + -rm -f ./$(DEPDIR)/gimp-gegl-tile-compat.Po + -rm -f ./$(DEPDIR)/gimp-gegl-utils.Po + -rm -f ./$(DEPDIR)/gimp-gegl.Po + -rm -f ./$(DEPDIR)/gimpapplicator.Po + -rm -f ./$(DEPDIR)/gimptilehandlervalidate.Po + -rm -f ./$(DEPDIR)/libappgegl_sse2_a-gimp-gegl-loops-sse2.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +libappgegl.a: libappgegl-generic.a \ + libappgegl-sse2.a + $(AR) $(ARFLAGS) libappgegl.a \ + $(libappgegl_generic_a_OBJECTS) \ + $(libappgegl_sse2_a_OBJECTS) + $(RANLIB) libappgegl.a + +xgen-ggec: $(srcdir)/gimp-gegl-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"core/core-enums.h\"\n#include \"gimp-gegl-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/gimp-gegl-enums.c: xgen-ggec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/app/gegl/gimp-babl-compat.c b/app/gegl/gimp-babl-compat.c new file mode 100644 index 0000000..b077f86 --- /dev/null +++ b/app/gegl/gimp-babl-compat.c @@ -0,0 +1,93 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-babl-compat.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "gimp-babl.h" +#include "gimp-babl-compat.h" + + +GimpImageType +gimp_babl_format_get_image_type (const Babl *format) +{ + const Babl *model; + + g_return_val_if_fail (format != NULL, -1); + + model = babl_format_get_model (format); + + if (model == babl_model ("Y") || + model == babl_model ("Y'")) + { + return GIMP_GRAY_IMAGE; + } + else if (model == babl_model ("YA") || + model == babl_model ("Y'A")) + { + return GIMP_GRAYA_IMAGE; + } + else if (model == babl_model ("RGB") || + model == babl_model ("R'G'B'")) + { + return GIMP_RGB_IMAGE; + } + else if (model == babl_model ("RGBA") || + model == babl_model ("R'G'B'A")) + { + return GIMP_RGBA_IMAGE; + } + else if (babl_format_is_palette (format)) + { + if (babl_format_has_alpha (format)) + return GIMP_INDEXEDA_IMAGE; + else + return GIMP_INDEXED_IMAGE; + } + + g_return_val_if_reached (-1); +} + +const Babl * +gimp_babl_compat_u8_format (const Babl *format) +{ + g_return_val_if_fail (format != NULL, NULL); + + /* indexed images only exist in u8, return the same format */ + if (babl_format_is_palette (format)) + return format; + + return gimp_babl_format (gimp_babl_format_get_base_type (format), + GIMP_PRECISION_U8_GAMMA, + babl_format_has_alpha (format)); +} + +const Babl * +gimp_babl_compat_u8_mask_format (const Babl *format) +{ + g_return_val_if_fail (format != NULL, NULL); + + return gimp_babl_format (gimp_babl_format_get_base_type (format), + GIMP_PRECISION_U8_LINEAR, + FALSE); +} diff --git a/app/gegl/gimp-babl-compat.h b/app/gegl/gimp-babl-compat.h new file mode 100644 index 0000000..778bf3e --- /dev/null +++ b/app/gegl/gimp-babl-compat.h @@ -0,0 +1,31 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-babl-compat.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_BABL_COMPAT_H__ +#define __GIMP_BABL_COMPAT_H__ + + +GimpImageType gimp_babl_format_get_image_type (const Babl *format); + +const Babl * gimp_babl_compat_u8_format (const Babl *format); +const Babl * gimp_babl_compat_u8_mask_format (const Babl *format); + + +#endif /* __GIMP_BABL_COMPAT_H__ */ diff --git a/app/gegl/gimp-babl.c b/app/gegl/gimp-babl.c new file mode 100644 index 0000000..b2dc20a --- /dev/null +++ b/app/gegl/gimp-babl.c @@ -0,0 +1,1415 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-babl.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpcolor/gimpcolor.h" + +#include "gimp-gegl-types.h" + +#include "gimp-babl.h" + +#include "gimp-intl.h" + + +void +gimp_babl_init (void) +{ + babl_format_new ("name", "R u8", + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("R"), + NULL); + babl_format_new ("name", "R' u8", + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + NULL); + babl_format_new ("name", "G u8", + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("G"), + NULL); + babl_format_new ("name", "G' u8", + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("G'"), + NULL); + babl_format_new ("name", "B u8", + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("B"), + NULL); + babl_format_new ("name", "B' u8", + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("B'"), + NULL); + babl_format_new ("name", "A u8", + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("A"), + NULL); + + babl_format_new ("name", "R u16", + babl_model ("RGBA"), + babl_type ("u16"), + babl_component ("R"), + NULL); + babl_format_new ("name", "R' u16", + babl_model ("R'G'B'A"), + babl_type ("u16"), + babl_component ("R'"), + NULL); + babl_format_new ("name", "G u16", + babl_model ("RGBA"), + babl_type ("u16"), + babl_component ("G"), + NULL); + babl_format_new ("name", "G' u16", + babl_model ("R'G'B'A"), + babl_type ("u16"), + babl_component ("G'"), + NULL); + babl_format_new ("name", "B u16", + babl_model ("RGBA"), + babl_type ("u16"), + babl_component ("B"), + NULL); + babl_format_new ("name", "B' u16", + babl_model ("R'G'B'A"), + babl_type ("u16"), + babl_component ("B'"), + NULL); + babl_format_new ("name", "A u16", + babl_model ("RGBA"), + babl_type ("u16"), + babl_component ("A"), + NULL); + + babl_format_new ("name", "R u32", + babl_model ("RGBA"), + babl_type ("u32"), + babl_component ("R"), + NULL); + babl_format_new ("name", "R' u32", + babl_model ("R'G'B'A"), + babl_type ("u32"), + babl_component ("R'"), + NULL); + babl_format_new ("name", "G u32", + babl_model ("RGBA"), + babl_type ("u32"), + babl_component ("G"), + NULL); + babl_format_new ("name", "G' u32", + babl_model ("R'G'B'A"), + babl_type ("u32"), + babl_component ("G'"), + NULL); + babl_format_new ("name", "B u32", + babl_model ("RGBA"), + babl_type ("u32"), + babl_component ("B"), + NULL); + babl_format_new ("name", "B' u32", + babl_model ("R'G'B'A"), + babl_type ("u32"), + babl_component ("B'"), + NULL); + babl_format_new ("name", "A u32", + babl_model ("RGBA"), + babl_type ("u32"), + babl_component ("A"), + NULL); + + babl_format_new ("name", "R half", + babl_model ("RGBA"), + babl_type ("half"), + babl_component ("R"), + NULL); + babl_format_new ("name", "R' half", + babl_model ("R'G'B'A"), + babl_type ("half"), + babl_component ("R'"), + NULL); + babl_format_new ("name", "G half", + babl_model ("RGBA"), + babl_type ("half"), + babl_component ("G"), + NULL); + babl_format_new ("name", "G' half", + babl_model ("R'G'B'A"), + babl_type ("half"), + babl_component ("G'"), + NULL); + babl_format_new ("name", "B half", + babl_model ("RGBA"), + babl_type ("half"), + babl_component ("B"), + NULL); + babl_format_new ("name", "B' half", + babl_model ("R'G'B'A"), + babl_type ("half"), + babl_component ("B'"), + NULL); + babl_format_new ("name", "A half", + babl_model ("RGBA"), + babl_type ("half"), + babl_component ("A"), + NULL); + + babl_format_new ("name", "R float", + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + NULL); + babl_format_new ("name", "R' float", + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + NULL); + babl_format_new ("name", "G float", + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("G"), + NULL); + babl_format_new ("name", "G' float", + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("G'"), + NULL); + babl_format_new ("name", "B float", + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("B"), + NULL); + babl_format_new ("name", "B' float", + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("B'"), + NULL); + babl_format_new ("name", "A float", + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("A"), + NULL); + + babl_format_new ("name", "R double", + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + NULL); + babl_format_new ("name", "R' double", + babl_model ("R'G'B'A"), + babl_type ("double"), + babl_component ("R'"), + NULL); + babl_format_new ("name", "G double", + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("G"), + NULL); + babl_format_new ("name", "G' double", + babl_model ("R'G'B'A"), + babl_type ("double"), + babl_component ("G'"), + NULL); + babl_format_new ("name", "B double", + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("B"), + NULL); + babl_format_new ("name", "B' double", + babl_model ("R'G'B'A"), + babl_type ("double"), + babl_component ("B'"), + NULL); + babl_format_new ("name", "A double", + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("A"), + NULL); +} + +void +gimp_babl_init_fishes (GimpInitStatusFunc status_callback) +{ + /* create a bunch of fishes - to decrease the initial lazy + * initialization cost for some interactions + */ + static const struct + { + const gchar *from_format; + const gchar *to_format; + } + fishes[] = + { + { "Y' u8", "RaGaBaA float" }, + { "Y u8", "RaGaBaA float" }, + { "R'G'B'A u8", "RaGaBaA float" }, + { "R'G'B'A float", "R'G'B'A u8" }, + { "R'G'B'A float", "R'G'B' u8" }, + { "R'G'B'A u8", "RGBA float" }, + { "RGBA float", "R'G'B'A u8" }, + { "RGBA float", "R'G'B'A u8" }, + { "RGBA float", "R'G'B'A float" }, + { "Y' u8", "R'G'B' u8" }, + { "Y u8", "Y float" }, + { "R'G'B' u8", "cairo-RGB24" }, + { "R'G'B' u8", "R'G'B'A float" }, + { "R'G'B' u8", "R'G'B'A u8" }, + { "R'G'B'A u8", "R'G'B'A float" }, + { "R'G'B'A u8", "cairo-ARGB32" }, + { "R'G'B'A double", "RGBA float" }, + { "R'G'B'A float", "RGBA double" }, + { "R'G'B' u8", "RGB float" }, + { "RGB float", "R'G'B'A float" }, + { "R'G'B' u8", "RGBA float" }, + { "RaGaBaA float", "R'G'B'A float" }, + { "RaGaBaA float", "RGBA float" }, + { "RGBA float", "RaGaBaA float" }, + { "R'G'B' u8", "RaGaBaA float" }, + { "cairo-ARGB32", "R'G'B'A u8" } + }; + + gint i; + + for (i = 0; i < G_N_ELEMENTS (fishes); i++) + { + status_callback (NULL, NULL, + (gdouble) (i + 1) / + (gdouble) G_N_ELEMENTS (fishes) * 0.8); + + babl_fish (babl_format (fishes[i].from_format), + babl_format (fishes[i].to_format)); + } +} + +static const struct +{ + const gchar *name; + const gchar *description; +} +babl_descriptions[] = +{ + { "RGB u8", N_("RGB") }, + { "R'G'B' u8", N_("RGB") }, + { "RGB u16", N_("RGB") }, + { "R'G'B' u16", N_("RGB") }, + { "RGB u32", N_("RGB") }, + { "R'G'B' u32", N_("RGB") }, + { "RGB half", N_("RGB") }, + { "R'G'B' half", N_("RGB") }, + { "RGB float", N_("RGB") }, + { "R'G'B' float", N_("RGB") }, + { "RGB double", N_("RGB") }, + { "R'G'B' double", N_("RGB") }, + + { "RGBA u8", N_("RGB-alpha") }, + { "R'G'B'A u8", N_("RGB-alpha") }, + { "RGBA u16", N_("RGB-alpha") }, + { "R'G'B'A u16", N_("RGB-alpha") }, + { "RGBA u32", N_("RGB-alpha") }, + { "R'G'B'A u32", N_("RGB-alpha") }, + { "RGBA half", N_("RGB-alpha") }, + { "R'G'B'A half", N_("RGB-alpha") }, + { "RGBA float", N_("RGB-alpha") }, + { "R'G'B'A float", N_("RGB-alpha") }, + { "RGBA double", N_("RGB-alpha") }, + { "R'G'B'A double", N_("RGB-alpha") }, + + { "Y u8", N_("Grayscale") }, + { "Y' u8", N_("Grayscale") }, + { "Y u16", N_("Grayscale") }, + { "Y' u16", N_("Grayscale") }, + { "Y u32", N_("Grayscale") }, + { "Y' u32", N_("Grayscale") }, + { "Y half", N_("Grayscale") }, + { "Y' half", N_("Grayscale") }, + { "Y float", N_("Grayscale") }, + { "Y' float", N_("Grayscale") }, + { "Y double", N_("Grayscale") }, + { "Y' double", N_("Grayscale") }, + + { "YA u8", N_("Grayscale-alpha") }, + { "Y'A u8", N_("Grayscale-alpha") }, + { "YA u16", N_("Grayscale-alpha") }, + { "Y'A u16", N_("Grayscale-alpha") }, + { "YA u32", N_("Grayscale-alpha") }, + { "Y'A u32", N_("Grayscale-alpha") }, + { "YA half", N_("Grayscale-alpha") }, + { "Y'A half", N_("Grayscale-alpha") }, + { "YA float", N_("Grayscale-alpha") }, + { "Y'A float", N_("Grayscale-alpha") }, + { "YA double", N_("Grayscale-alpha") }, + { "Y'A double", N_("Grayscale-alpha") }, + + { "R u8", N_("Red component") }, + { "R' u8", N_("Red component") }, + { "R u16", N_("Red component") }, + { "R' u16", N_("Red component") }, + { "R u32", N_("Red component") }, + { "R' u32", N_("Red component") }, + { "R half", N_("Red component") }, + { "R' half", N_("Red component") }, + { "R float", N_("Red component") }, + { "R' float", N_("Red component") }, + { "R double", N_("Red component") }, + { "R' double", N_("Red component") }, + + { "G u8", N_("Green component") }, + { "G' u8", N_("Green component") }, + { "G u16", N_("Green component") }, + { "G' u16", N_("Green component") }, + { "G u32", N_("Green component") }, + { "G' u32", N_("Green component") }, + { "G half", N_("Green component") }, + { "G' half", N_("Green component") }, + { "G float", N_("Green component") }, + { "G' float", N_("Green component") }, + { "G double", N_("Green component") }, + { "G' double", N_("Green component") }, + + { "B u8", N_("Blue component") }, + { "B' u8", N_("Blue component") }, + { "B u16", N_("Blue component") }, + { "B' u16", N_("Blue component") }, + { "B u32", N_("Blue component") }, + { "B' u32", N_("Blue component") }, + { "B half", N_("Blue component") }, + { "B' half", N_("Blue component") }, + { "B float", N_("Blue component") }, + { "B' float", N_("Blue component") }, + { "B double", N_("Blue component") }, + { "B' double", N_("Blue component") }, + + { "A u8", N_("Alpha component") }, + { "A u16", N_("Alpha component") }, + { "A u32", N_("Alpha component") }, + { "A half", N_("Alpha component") }, + { "A float", N_("Alpha component") }, + { "A double", N_("Alpha component") } +}; + +static GHashTable *babl_description_hash = NULL; + +const gchar * +gimp_babl_format_get_description (const Babl *babl) +{ + const gchar *description; + + g_return_val_if_fail (babl != NULL, NULL); + + if (G_UNLIKELY (! babl_description_hash)) + { + gint i; + + babl_description_hash = g_hash_table_new (g_str_hash, + g_str_equal); + + for (i = 0; i < G_N_ELEMENTS (babl_descriptions); i++) + g_hash_table_insert (babl_description_hash, + (gpointer) babl_descriptions[i].name, + gettext (babl_descriptions[i].description)); + } + + if (babl_format_is_palette (babl)) + { + if (babl_format_has_alpha (babl)) + return _("Indexed-alpha"); + else + return _("Indexed"); + } + + description = g_hash_table_lookup (babl_description_hash, + babl_get_name (babl)); + + if (description) + return description; + + return g_strconcat ("ERROR: unknown Babl format ", + babl_get_name (babl), NULL); +} + +GimpColorProfile * +gimp_babl_format_get_color_profile (const Babl *format) +{ + static GimpColorProfile *srgb_profile = NULL; + static GimpColorProfile *linear_rgb_profile = NULL; + static GimpColorProfile *gray_profile = NULL; + static GimpColorProfile *linear_gray_profile = NULL; + + g_return_val_if_fail (format != NULL, NULL); + + if (gimp_babl_format_get_base_type (format) == GIMP_GRAY) + { + if (gimp_babl_format_get_linear (format)) + { + if (! linear_gray_profile) + { + linear_gray_profile = gimp_color_profile_new_d65_gray_linear (); + g_object_add_weak_pointer (G_OBJECT (linear_gray_profile), + (gpointer) &linear_gray_profile); + } + + return linear_gray_profile; + } + else + { + if (! gray_profile) + { + gray_profile = gimp_color_profile_new_d65_gray_srgb_trc (); + g_object_add_weak_pointer (G_OBJECT (gray_profile), + (gpointer) &gray_profile); + } + + return gray_profile; + } + } + else + { + if (gimp_babl_format_get_linear (format)) + { + if (! linear_rgb_profile) + { + linear_rgb_profile = gimp_color_profile_new_rgb_srgb_linear (); + g_object_add_weak_pointer (G_OBJECT (linear_rgb_profile), + (gpointer) &linear_rgb_profile); + } + + return linear_rgb_profile; + } + else + { + if (! srgb_profile) + { + srgb_profile = gimp_color_profile_new_rgb_srgb (); + g_object_add_weak_pointer (G_OBJECT (srgb_profile), + (gpointer) &srgb_profile); + } + + return srgb_profile; + } + } +} + +GimpImageBaseType +gimp_babl_format_get_base_type (const Babl *format) +{ + const Babl *model; + + g_return_val_if_fail (format != NULL, -1); + + model = babl_format_get_model (format); + + if (model == babl_model ("Y") || + model == babl_model ("Y'") || + model == babl_model ("YA") || + model == babl_model ("Y'A")) + { + return GIMP_GRAY; + } + else if (model == babl_model ("RGB") || + model == babl_model ("R'G'B'") || + model == babl_model ("RGBA") || + model == babl_model ("R'G'B'A") || + model == babl_model ("RaGaBaA") || + model == babl_model ("R'aG'aB'aA")) + { + return GIMP_RGB; + } + else if (babl_format_is_palette (format)) + { + return GIMP_INDEXED; + } + + g_return_val_if_reached (-1); +} + +GimpComponentType +gimp_babl_format_get_component_type (const Babl *format) +{ + const Babl *type; + + g_return_val_if_fail (format != NULL, -1); + + type = babl_format_get_type (format, 0); + + if (type == babl_type ("u8")) + return GIMP_COMPONENT_TYPE_U8; + else if (type == babl_type ("u16")) + return GIMP_COMPONENT_TYPE_U16; + else if (type == babl_type ("u32")) + return GIMP_COMPONENT_TYPE_U32; + else if (type == babl_type ("half")) + return GIMP_COMPONENT_TYPE_HALF; + else if (type == babl_type ("float")) + return GIMP_COMPONENT_TYPE_FLOAT; + else if (type == babl_type ("double")) + return GIMP_COMPONENT_TYPE_DOUBLE; + + g_return_val_if_reached (-1); +} + +GimpPrecision +gimp_babl_format_get_precision (const Babl *format) +{ + const Babl *type; + + g_return_val_if_fail (format != NULL, -1); + + type = babl_format_get_type (format, 0); + + if (gimp_babl_format_get_linear (format)) + { + if (type == babl_type ("u8")) + return GIMP_PRECISION_U8_LINEAR; + else if (type == babl_type ("u16")) + return GIMP_PRECISION_U16_LINEAR; + else if (type == babl_type ("u32")) + return GIMP_PRECISION_U32_LINEAR; + else if (type == babl_type ("half")) + return GIMP_PRECISION_HALF_LINEAR; + else if (type == babl_type ("float")) + return GIMP_PRECISION_FLOAT_LINEAR; + else if (type == babl_type ("double")) + return GIMP_PRECISION_DOUBLE_LINEAR; + } + else + { + if (type == babl_type ("u8")) + return GIMP_PRECISION_U8_GAMMA; + else if (type == babl_type ("u16")) + return GIMP_PRECISION_U16_GAMMA; + else if (type == babl_type ("u32")) + return GIMP_PRECISION_U32_GAMMA; + else if (type == babl_type ("half")) + return GIMP_PRECISION_HALF_GAMMA; + else if (type == babl_type ("float")) + return GIMP_PRECISION_FLOAT_GAMMA; + else if (type == babl_type ("double")) + return GIMP_PRECISION_DOUBLE_GAMMA; + } + + g_return_val_if_reached (-1); +} + +gboolean +gimp_babl_format_get_linear (const Babl *format) +{ + const Babl *model; + + g_return_val_if_fail (format != NULL, FALSE); + + model = babl_format_get_model (format); + + if (model == babl_model ("Y") || + model == babl_model ("YA") || + model == babl_model ("RGB") || + model == babl_model ("RGBA") || + model == babl_model ("RaGaBaA")) + { + return TRUE; + } + else if (model == babl_model ("Y'") || + model == babl_model ("Y'A") || + model == babl_model ("R'G'B'") || + model == babl_model ("R'G'B'A") || + model == babl_model ("R'aG'aB'aA")) + { + return FALSE; + } + else if (babl_format_is_palette (format)) + { + return FALSE; + } + + g_return_val_if_reached (FALSE); +} + +GimpComponentType +gimp_babl_component_type (GimpPrecision precision) +{ + switch (precision) + { + case GIMP_PRECISION_U8_LINEAR: + case GIMP_PRECISION_U8_GAMMA: + return GIMP_COMPONENT_TYPE_U8; + + case GIMP_PRECISION_U16_LINEAR: + case GIMP_PRECISION_U16_GAMMA: + return GIMP_COMPONENT_TYPE_U16; + + case GIMP_PRECISION_U32_LINEAR: + case GIMP_PRECISION_U32_GAMMA: + return GIMP_COMPONENT_TYPE_U32; + + case GIMP_PRECISION_HALF_LINEAR: + case GIMP_PRECISION_HALF_GAMMA: + return GIMP_COMPONENT_TYPE_HALF; + + case GIMP_PRECISION_FLOAT_LINEAR: + case GIMP_PRECISION_FLOAT_GAMMA: + return GIMP_COMPONENT_TYPE_FLOAT; + + case GIMP_PRECISION_DOUBLE_LINEAR: + case GIMP_PRECISION_DOUBLE_GAMMA: + return GIMP_COMPONENT_TYPE_DOUBLE; + } + + g_return_val_if_reached (-1); +} + +gboolean +gimp_babl_linear (GimpPrecision precision) +{ + switch (precision) + { + case GIMP_PRECISION_U8_LINEAR: + case GIMP_PRECISION_U16_LINEAR: + case GIMP_PRECISION_U32_LINEAR: + case GIMP_PRECISION_HALF_LINEAR: + case GIMP_PRECISION_FLOAT_LINEAR: + case GIMP_PRECISION_DOUBLE_LINEAR: + return TRUE; + + case GIMP_PRECISION_U8_GAMMA: + case GIMP_PRECISION_U16_GAMMA: + case GIMP_PRECISION_U32_GAMMA: + case GIMP_PRECISION_HALF_GAMMA: + case GIMP_PRECISION_FLOAT_GAMMA: + case GIMP_PRECISION_DOUBLE_GAMMA: + return FALSE; + } + + g_return_val_if_reached (FALSE); +} + +GimpPrecision +gimp_babl_precision (GimpComponentType component, + gboolean linear) +{ + switch (component) + { + case GIMP_COMPONENT_TYPE_U8: + if (linear) + return GIMP_PRECISION_U8_LINEAR; + else + return GIMP_PRECISION_U8_GAMMA; + + case GIMP_COMPONENT_TYPE_U16: + if (linear) + return GIMP_PRECISION_U16_LINEAR; + else + return GIMP_PRECISION_U16_GAMMA; + + case GIMP_COMPONENT_TYPE_U32: + if (linear) + return GIMP_PRECISION_U32_LINEAR; + else + return GIMP_PRECISION_U32_GAMMA; + + case GIMP_COMPONENT_TYPE_HALF: + if (linear) + return GIMP_PRECISION_HALF_LINEAR; + else + return GIMP_PRECISION_HALF_GAMMA; + + case GIMP_COMPONENT_TYPE_FLOAT: + if (linear) + return GIMP_PRECISION_FLOAT_LINEAR; + else + return GIMP_PRECISION_FLOAT_GAMMA; + + case GIMP_COMPONENT_TYPE_DOUBLE: + if (linear) + return GIMP_PRECISION_DOUBLE_LINEAR; + else + return GIMP_PRECISION_DOUBLE_GAMMA; + + default: + break; + } + + g_return_val_if_reached (-1); +} + +gboolean +gimp_babl_is_valid (GimpImageBaseType base_type, + GimpPrecision precision) +{ + switch (base_type) + { + case GIMP_RGB: + case GIMP_GRAY: + return TRUE; + + case GIMP_INDEXED: + switch (precision) + { + case GIMP_PRECISION_U8_GAMMA: + return TRUE; + + default: + return FALSE; + } + } + + g_return_val_if_reached (FALSE); +} + +GimpComponentType +gimp_babl_is_bounded (GimpPrecision precision) +{ + switch (gimp_babl_component_type (precision)) + { + case GIMP_COMPONENT_TYPE_U8: + case GIMP_COMPONENT_TYPE_U16: + case GIMP_COMPONENT_TYPE_U32: + return TRUE; + + case GIMP_COMPONENT_TYPE_HALF: + case GIMP_COMPONENT_TYPE_FLOAT: + case GIMP_COMPONENT_TYPE_DOUBLE: + return FALSE; + } + + g_return_val_if_reached (FALSE); +} + +const Babl * +gimp_babl_format (GimpImageBaseType base_type, + GimpPrecision precision, + gboolean with_alpha) +{ + switch (base_type) + { + case GIMP_RGB: + switch (precision) + { + case GIMP_PRECISION_U8_LINEAR: + if (with_alpha) + return babl_format ("RGBA u8"); + else + return babl_format ("RGB u8"); + + case GIMP_PRECISION_U8_GAMMA: + if (with_alpha) + return babl_format ("R'G'B'A u8"); + else + return babl_format ("R'G'B' u8"); + + case GIMP_PRECISION_U16_LINEAR: + if (with_alpha) + return babl_format ("RGBA u16"); + else + return babl_format ("RGB u16"); + + case GIMP_PRECISION_U16_GAMMA: + if (with_alpha) + return babl_format ("R'G'B'A u16"); + else + return babl_format ("R'G'B' u16"); + + case GIMP_PRECISION_U32_LINEAR: + if (with_alpha) + return babl_format ("RGBA u32"); + else + return babl_format ("RGB u32"); + + case GIMP_PRECISION_U32_GAMMA: + if (with_alpha) + return babl_format ("R'G'B'A u32"); + else + return babl_format ("R'G'B' u32"); + + case GIMP_PRECISION_HALF_LINEAR: + if (with_alpha) + return babl_format ("RGBA half"); + else + return babl_format ("RGB half"); + + case GIMP_PRECISION_HALF_GAMMA: + if (with_alpha) + return babl_format ("R'G'B'A half"); + else + return babl_format ("R'G'B' half"); + + case GIMP_PRECISION_FLOAT_LINEAR: + if (with_alpha) + return babl_format ("RGBA float"); + else + return babl_format ("RGB float"); + + case GIMP_PRECISION_FLOAT_GAMMA: + if (with_alpha) + return babl_format ("R'G'B'A float"); + else + return babl_format ("R'G'B' float"); + + case GIMP_PRECISION_DOUBLE_LINEAR: + if (with_alpha) + return babl_format ("RGBA double"); + else + return babl_format ("RGB double"); + + case GIMP_PRECISION_DOUBLE_GAMMA: + if (with_alpha) + return babl_format ("R'G'B'A double"); + else + return babl_format ("R'G'B' double"); + + default: + break; + } + break; + + case GIMP_GRAY: + switch (precision) + { + case GIMP_PRECISION_U8_LINEAR: + if (with_alpha) + return babl_format ("YA u8"); + else + return babl_format ("Y u8"); + + case GIMP_PRECISION_U8_GAMMA: + if (with_alpha) + return babl_format ("Y'A u8"); + else + return babl_format ("Y' u8"); + + case GIMP_PRECISION_U16_LINEAR: + if (with_alpha) + return babl_format ("YA u16"); + else + return babl_format ("Y u16"); + + case GIMP_PRECISION_U16_GAMMA: + if (with_alpha) + return babl_format ("Y'A u16"); + else + return babl_format ("Y' u16"); + + case GIMP_PRECISION_U32_LINEAR: + if (with_alpha) + return babl_format ("YA u32"); + else + return babl_format ("Y u32"); + + case GIMP_PRECISION_U32_GAMMA: + if (with_alpha) + return babl_format ("Y'A u32"); + else + return babl_format ("Y' u32"); + + case GIMP_PRECISION_HALF_LINEAR: + if (with_alpha) + return babl_format ("YA half"); + else + return babl_format ("Y half"); + + case GIMP_PRECISION_HALF_GAMMA: + if (with_alpha) + return babl_format ("Y'A half"); + else + return babl_format ("Y' half"); + + case GIMP_PRECISION_FLOAT_LINEAR: + if (with_alpha) + return babl_format ("YA float"); + else + return babl_format ("Y float"); + + case GIMP_PRECISION_FLOAT_GAMMA: + if (with_alpha) + return babl_format ("Y'A float"); + else + return babl_format ("Y' float"); + + case GIMP_PRECISION_DOUBLE_LINEAR: + if (with_alpha) + return babl_format ("YA double"); + else + return babl_format ("Y double"); + + case GIMP_PRECISION_DOUBLE_GAMMA: + if (with_alpha) + return babl_format ("Y'A double"); + else + return babl_format ("Y' double"); + + default: + break; + } + break; + + case GIMP_INDEXED: + /* need to use the image's api for this */ + break; + } + + g_return_val_if_reached (NULL); +} + +const Babl * +gimp_babl_mask_format (GimpPrecision precision) +{ + switch (gimp_babl_component_type (precision)) + { + case GIMP_COMPONENT_TYPE_U8: return babl_format ("Y u8"); + case GIMP_COMPONENT_TYPE_U16: return babl_format ("Y u16"); + case GIMP_COMPONENT_TYPE_U32: return babl_format ("Y u32"); + case GIMP_COMPONENT_TYPE_HALF: return babl_format ("Y half"); + case GIMP_COMPONENT_TYPE_FLOAT: return babl_format ("Y float"); + case GIMP_COMPONENT_TYPE_DOUBLE: return babl_format ("Y double"); + } + + g_return_val_if_reached (NULL); +} + +const Babl * +gimp_babl_component_format (GimpImageBaseType base_type, + GimpPrecision precision, + gint index) +{ + switch (base_type) + { + case GIMP_RGB: + switch (precision) + { + case GIMP_PRECISION_U8_LINEAR: + switch (index) + { + case 0: return babl_format ("R u8"); + case 1: return babl_format ("G u8"); + case 2: return babl_format ("B u8"); + case 3: return babl_format ("A u8"); + default: + break; + } + break; + + case GIMP_PRECISION_U8_GAMMA: + switch (index) + { + case 0: return babl_format ("R' u8"); + case 1: return babl_format ("G' u8"); + case 2: return babl_format ("B' u8"); + case 3: return babl_format ("A u8"); + default: + break; + } + break; + + case GIMP_PRECISION_U16_LINEAR: + switch (index) + { + case 0: return babl_format ("R u16"); + case 1: return babl_format ("G u16"); + case 2: return babl_format ("B u16"); + case 3: return babl_format ("A u16"); + default: + break; + } + break; + + case GIMP_PRECISION_U16_GAMMA: + switch (index) + { + case 0: return babl_format ("R' u16"); + case 1: return babl_format ("G' u16"); + case 2: return babl_format ("B' u16"); + case 3: return babl_format ("A u16"); + default: + break; + } + break; + + case GIMP_PRECISION_U32_LINEAR: + switch (index) + { + case 0: return babl_format ("R u32"); + case 1: return babl_format ("G u32"); + case 2: return babl_format ("B u32"); + case 3: return babl_format ("A u32"); + default: + break; + } + break; + + case GIMP_PRECISION_U32_GAMMA: + switch (index) + { + case 0: return babl_format ("R' u32"); + case 1: return babl_format ("G' u32"); + case 2: return babl_format ("B' u32"); + case 3: return babl_format ("A u32"); + default: + break; + } + break; + + case GIMP_PRECISION_HALF_LINEAR: + switch (index) + { + case 0: return babl_format ("R half"); + case 1: return babl_format ("G half"); + case 2: return babl_format ("B half"); + case 3: return babl_format ("A half"); + default: + break; + } + break; + + case GIMP_PRECISION_HALF_GAMMA: + switch (index) + { + case 0: return babl_format ("R' half"); + case 1: return babl_format ("G' half"); + case 2: return babl_format ("B' half"); + case 3: return babl_format ("A half"); + default: + break; + } + break; + + case GIMP_PRECISION_FLOAT_LINEAR: + switch (index) + { + case 0: return babl_format ("R float"); + case 1: return babl_format ("G float"); + case 2: return babl_format ("B float"); + case 3: return babl_format ("A float"); + default: + break; + } + break; + + case GIMP_PRECISION_FLOAT_GAMMA: + switch (index) + { + case 0: return babl_format ("R' float"); + case 1: return babl_format ("G' float"); + case 2: return babl_format ("B' float"); + case 3: return babl_format ("A float"); + default: + break; + } + break; + + case GIMP_PRECISION_DOUBLE_LINEAR: + switch (index) + { + case 0: return babl_format ("R double"); + case 1: return babl_format ("G double"); + case 2: return babl_format ("B double"); + case 3: return babl_format ("A double"); + default: + break; + } + break; + + case GIMP_PRECISION_DOUBLE_GAMMA: + switch (index) + { + case 0: return babl_format ("R' double"); + case 1: return babl_format ("G' double"); + case 2: return babl_format ("B' double"); + case 3: return babl_format ("A double"); + default: + break; + } + break; + + default: + break; + } + break; + + case GIMP_GRAY: + switch (precision) + { + case GIMP_PRECISION_U8_LINEAR: + switch (index) + { + case 0: return babl_format ("Y u8"); + case 1: return babl_format ("A u8"); + default: + break; + } + break; + + case GIMP_PRECISION_U8_GAMMA: + switch (index) + { + case 0: return babl_format ("Y' u8"); + case 1: return babl_format ("A u8"); + default: + break; + } + break; + + case GIMP_PRECISION_U16_LINEAR: + switch (index) + { + case 0: return babl_format ("Y u16"); + case 1: return babl_format ("A u16"); + default: + break; + } + break; + + case GIMP_PRECISION_U16_GAMMA: + switch (index) + { + case 0: return babl_format ("Y' u16"); + case 1: return babl_format ("A u16"); + default: + break; + } + break; + + case GIMP_PRECISION_U32_LINEAR: + switch (index) + { + case 0: return babl_format ("Y u32"); + case 1: return babl_format ("A u32"); + default: + break; + } + break; + + case GIMP_PRECISION_U32_GAMMA: + switch (index) + { + case 0: return babl_format ("Y' u32"); + case 1: return babl_format ("A u32"); + default: + break; + } + break; + + case GIMP_PRECISION_HALF_LINEAR: + switch (index) + { + case 0: return babl_format ("Y half"); + case 1: return babl_format ("A half"); + default: + break; + } + break; + + case GIMP_PRECISION_HALF_GAMMA: + switch (index) + { + case 0: return babl_format ("Y' half"); + case 1: return babl_format ("A half"); + default: + break; + } + break; + + case GIMP_PRECISION_FLOAT_LINEAR: + switch (index) + { + case 0: return babl_format ("Y float"); + case 1: return babl_format ("A float"); + default: + break; + } + break; + + case GIMP_PRECISION_FLOAT_GAMMA: + switch (index) + { + case 0: return babl_format ("Y' float"); + case 1: return babl_format ("A float"); + default: + break; + } + break; + + case GIMP_PRECISION_DOUBLE_LINEAR: + switch (index) + { + case 0: return babl_format ("Y double"); + case 1: return babl_format ("A double"); + default: + break; + } + break; + + case GIMP_PRECISION_DOUBLE_GAMMA: + switch (index) + { + case 0: return babl_format ("Y' double"); + case 1: return babl_format ("A double"); + default: + break; + } + break; + + default: + break; + } + break; + + case GIMP_INDEXED: + /* need to use the image's api for this */ + break; + } + + g_return_val_if_reached (NULL); +} + +const Babl * +gimp_babl_format_change_component_type (const Babl *format, + GimpComponentType component) +{ + g_return_val_if_fail (format != NULL, NULL); + + return gimp_babl_format (gimp_babl_format_get_base_type (format), + gimp_babl_precision ( + component, + gimp_babl_format_get_linear (format)), + babl_format_has_alpha (format)); +} + +const Babl * +gimp_babl_format_change_linear (const Babl *format, + gboolean linear) +{ + g_return_val_if_fail (format != NULL, NULL); + + return gimp_babl_format (gimp_babl_format_get_base_type (format), + gimp_babl_precision ( + gimp_babl_format_get_component_type (format), + linear), + babl_format_has_alpha (format)); +} + +gchar ** +gimp_babl_print_pixel (const Babl *format, + gpointer pixel) +{ + GimpPrecision precision; + gint n_components; + guchar tmp_pixel[32]; + gchar **strings; + + g_return_val_if_fail (format != NULL, NULL); + g_return_val_if_fail (pixel != NULL, NULL); + + precision = gimp_babl_format_get_precision (format); + + if (babl_format_is_palette (format)) + { + const Babl *f = gimp_babl_format (GIMP_RGB, precision, + babl_format_has_alpha (format)); + + babl_process (babl_fish (format, f), pixel, tmp_pixel, 1); + + format = f; + pixel = tmp_pixel; + } + + n_components = babl_format_get_n_components (format); + + strings = g_new0 (gchar *, n_components + 1); + + switch (gimp_babl_format_get_component_type (format)) + { + case GIMP_COMPONENT_TYPE_U8: + { + guchar *color = pixel; + gint i; + + for (i = 0; i < n_components; i++) + strings[i] = g_strdup_printf ("%d", color[i]); + } + break; + + case GIMP_COMPONENT_TYPE_U16: + { + guint16 *color = pixel; + gint i; + + for (i = 0; i < n_components; i++) + strings[i] = g_strdup_printf ("%u", color[i]); + } + break; + + case GIMP_COMPONENT_TYPE_U32: + { + guint32 *color = pixel; + gint i; + + for (i = 0; i < n_components; i++) + strings[i] = g_strdup_printf ("%u", color[i]); + } + break; + + case GIMP_COMPONENT_TYPE_HALF: + { + GimpPrecision p; + const Babl *f; + + p = gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT, + gimp_babl_format_get_linear (format)); + + f = gimp_babl_format (gimp_babl_format_get_base_type (format), + p, + babl_format_has_alpha (format)); + + babl_process (babl_fish (format, f), pixel, tmp_pixel, 1); + + pixel = tmp_pixel; + } + /* fall through */ + + case GIMP_COMPONENT_TYPE_FLOAT: + { + gfloat *color = pixel; + gint i; + + for (i = 0; i < n_components; i++) + strings[i] = g_strdup_printf ("%0.6f", color[i]); + } + break; + + case GIMP_COMPONENT_TYPE_DOUBLE: + { + gdouble *color = pixel; + gint i; + + for (i = 0; i < n_components; i++) + strings[i] = g_strdup_printf ("%0.6f", color[i]); + } + break; + } + + return strings; +} diff --git a/app/gegl/gimp-babl.h b/app/gegl/gimp-babl.h new file mode 100644 index 0000000..3062e02 --- /dev/null +++ b/app/gegl/gimp-babl.h @@ -0,0 +1,62 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-babl.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_BABL_H__ +#define __GIMP_BABL_H__ + + +void gimp_babl_init (void); +void gimp_babl_init_fishes (GimpInitStatusFunc status_callback); + +const gchar * gimp_babl_format_get_description (const Babl *format); +GimpColorProfile * gimp_babl_format_get_color_profile (const Babl *format); + +GimpImageBaseType gimp_babl_format_get_base_type (const Babl *format); +GimpComponentType gimp_babl_format_get_component_type (const Babl *format); +GimpPrecision gimp_babl_format_get_precision (const Babl *format); +gboolean gimp_babl_format_get_linear (const Babl *format); + +GimpComponentType gimp_babl_component_type (GimpPrecision precision); +gboolean gimp_babl_linear (GimpPrecision precision); +GimpPrecision gimp_babl_precision (GimpComponentType component, + gboolean linear); + +gboolean gimp_babl_is_valid (GimpImageBaseType base_type, + GimpPrecision precision); +GimpComponentType gimp_babl_is_bounded (GimpPrecision precision); + +const Babl * gimp_babl_format (GimpImageBaseType base_type, + GimpPrecision precision, + gboolean with_alpha); +const Babl * gimp_babl_mask_format (GimpPrecision precision); +const Babl * gimp_babl_component_format (GimpImageBaseType base_type, + GimpPrecision precision, + gint index); + +const Babl * gimp_babl_format_change_component_type (const Babl *format, + GimpComponentType component); +const Babl * gimp_babl_format_change_linear (const Babl *format, + gboolean linear); + +gchar ** gimp_babl_print_pixel (const Babl *format, + gpointer pixel); + + +#endif /* __GIMP_BABL_H__ */ diff --git a/app/gegl/gimp-gegl-apply-operation.c b/app/gegl/gimp-gegl-apply-operation.c new file mode 100644 index 0000000..d76b3b1 --- /dev/null +++ b/app/gegl/gimp-gegl-apply-operation.c @@ -0,0 +1,827 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-apply-operation.c + * Copyright (C) 2012 Øyvind KolÃ¥s <pippin@gimp.org> + * Sven Neumann <sven@gimp.org> + * Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gio/gio.h> +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "core/gimp-transform-utils.h" +#include "core/gimp-utils.h" +#include "core/gimpchunkiterator.h" +#include "core/gimpprogress.h" + +#include "gimp-gegl-apply-operation.h" +#include "gimp-gegl-loops.h" +#include "gimp-gegl-nodes.h" +#include "gimp-gegl-utils.h" + + +/* iteration interval when applying an operation interactively + * (with progress indication) + */ +#define APPLY_OPERATION_INTERACTIVE_INTERVAL (1.0 / 8.0) /* seconds */ + +/* iteration interval when applying an operation non-interactively + * (without progress indication) + */ +#define APPLY_OPERATION_NON_INTERACTIVE_INTERVAL 1.0 /* seconds */ + + +void +gimp_gegl_apply_operation (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglNode *operation, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gboolean crop_input) +{ + gimp_gegl_apply_cached_operation (src_buffer, + progress, undo_desc, + operation, + src_buffer != NULL, + dest_buffer, + dest_rect, + crop_input, + NULL, NULL, 0, + FALSE); +} + +static void +gimp_gegl_apply_operation_cancel (GimpProgress *progress, + gboolean *cancel) +{ + *cancel = TRUE; +} + +gboolean +gimp_gegl_apply_cached_operation (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglNode *operation, + gboolean connect_src_buffer, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gboolean crop_input, + GeglBuffer *cache, + const GeglRectangle *valid_rects, + gint n_valid_rects, + gboolean cancelable) +{ + GeglNode *gegl; + GeglNode *effect; + GeglNode *dest_node; + GeglNode *underlying_operation; + GeglNode *operation_src_node = NULL; + GeglBuffer *result_buffer; + GimpChunkIterator *iter; + cairo_region_t *region; + gboolean progress_started = FALSE; + gboolean cancel = FALSE; + gint64 all_pixels; + gint64 done_pixels; + + g_return_val_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer), FALSE); + g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE); + g_return_val_if_fail (GEGL_IS_NODE (operation), FALSE); + g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), FALSE); + g_return_val_if_fail (cache == NULL || GEGL_IS_BUFFER (cache), FALSE); + g_return_val_if_fail (valid_rects == NULL || cache != NULL, FALSE); + g_return_val_if_fail (valid_rects == NULL || n_valid_rects != 0, FALSE); + + if (! dest_rect) + dest_rect = gegl_buffer_get_extent (dest_buffer); + + if (progress) + { + if (gimp_progress_is_active (progress)) + { + if (undo_desc) + gimp_progress_set_text_literal (progress, undo_desc); + + progress_started = FALSE; + cancelable = FALSE; + } + else + { + gimp_progress_start (progress, cancelable, "%s", undo_desc); + + if (cancelable) + g_signal_connect (progress, "cancel", + G_CALLBACK (gimp_gegl_apply_operation_cancel), + &cancel); + + progress_started = TRUE; + } + } + else + { + cancelable = FALSE; + } + + gegl_buffer_freeze_changed (dest_buffer); + + underlying_operation = gimp_gegl_node_get_underlying_operation (operation); + + result_buffer = dest_buffer; + + if (result_buffer == src_buffer && + ! (gimp_gegl_node_is_point_operation (underlying_operation) || + gimp_gegl_node_is_source_operation (underlying_operation))) + { + /* Write the result to a temporary buffer, instead of directly to + * dest_buffer, since reading and writing the same buffer doesn't + * generally work with non-point ops when working in chunks. + * + * See bug #701875. + */ + + if (cache) + { + /* If we have a cache, use it directly as the temporary result + * buffer, and skip copying the cached results to result_buffer + * below. Instead, the cached results are copied together with the + * newly rendered results in a single step at the end of processing. + */ + + g_warn_if_fail (cache != dest_buffer); + + result_buffer = g_object_ref (cache); + + cache = NULL; + } + else + { + result_buffer = gegl_buffer_new ( + dest_rect, gegl_buffer_get_format (dest_buffer)); + } + } + + all_pixels = (gint64) dest_rect->width * (gint64) dest_rect->height; + done_pixels = 0; + + region = cairo_region_create_rectangle ((cairo_rectangle_int_t *) dest_rect); + + if (n_valid_rects > 0) + { + gint i; + + for (i = 0; i < n_valid_rects; i++) + { + GeglRectangle valid_rect; + + if (! gegl_rectangle_intersect (&valid_rect, + &valid_rects[i], dest_rect)) + { + continue; + } + + if (cache) + { + gimp_gegl_buffer_copy ( + cache, &valid_rect, GEGL_ABYSS_NONE, + result_buffer, &valid_rect); + } + + cairo_region_subtract_rectangle (region, + (cairo_rectangle_int_t *) + &valid_rect); + + done_pixels += (gint64) valid_rect.width * (gint64) valid_rect.height; + + if (progress) + { + gimp_progress_set_value (progress, + (gdouble) done_pixels / + (gdouble) all_pixels); + } + } + } + + gegl = gegl_node_new (); + + if (! gegl_node_get_parent (operation)) + gegl_node_add_child (gegl, operation); + + effect = operation; + + if (connect_src_buffer || crop_input) + { + GeglNode *src_node; + + operation_src_node = gegl_node_get_producer (operation, "input", NULL); + + src_node = operation_src_node; + + if (connect_src_buffer) + { + src_node = gegl_node_new_child (gegl, + "operation", "gegl:buffer-source", + "buffer", src_buffer, + NULL); + } + + if (crop_input) + { + GeglNode *crop_node; + + crop_node = gegl_node_new_child (gegl, + "operation", "gegl:crop", + "x", (gdouble) dest_rect->x, + "y", (gdouble) dest_rect->y, + "width", (gdouble) dest_rect->width, + "height", (gdouble) dest_rect->height, + NULL); + + gegl_node_connect_to (src_node, "output", + crop_node, "input"); + + src_node = crop_node; + } + + if (! gegl_node_has_pad (operation, "input")) + { + effect = gegl_node_new_child (gegl, + "operation", "gimp:normal", + NULL); + + gegl_node_connect_to (operation, "output", + effect, "aux"); + } + + gegl_node_connect_to (src_node, "output", + effect, "input"); + } + + dest_node = gegl_node_new_child (gegl, + "operation", "gegl:write-buffer", + "buffer", result_buffer, + NULL); + + gegl_node_connect_to (effect, "output", + dest_node, "input"); + + iter = gimp_chunk_iterator_new (region); + + if (progress && + /* avoid the interactive iteration interval for area filters (or meta ops + * that potentially involve area filters), since their processing speed + * tends to be sensitive to the chunk size. + */ + ! gimp_gegl_node_is_area_filter_operation (underlying_operation)) + { + /* we use a shorter iteration interval for interactive use (when there's + * progress indication), to stay responsive. + */ + gimp_chunk_iterator_set_interval ( + iter, + APPLY_OPERATION_INTERACTIVE_INTERVAL); + } + else + { + /* we use a longer iteration interval for non-interactive use (when + * there's no progress indication), or when applying an area filter (see + * above), as this generally allows for faster processing. we don't + * avoid chunking altogether, since *some* chunking is still desirable to + * reduce the space needed for intermediate results. + */ + gimp_chunk_iterator_set_interval ( + iter, + APPLY_OPERATION_NON_INTERACTIVE_INTERVAL); + } + + while (gimp_chunk_iterator_next (iter)) + { + GeglRectangle render_rect; + + if (cancelable) + { + while (! cancel && g_main_context_pending (NULL)) + g_main_context_iteration (NULL, FALSE); + + if (cancel) + break; + } + + while (gimp_chunk_iterator_get_rect (iter, &render_rect)) + { + gegl_node_blit (dest_node, 1.0, &render_rect, NULL, NULL, 0, + GEGL_BLIT_DEFAULT); + + done_pixels += (gint64) render_rect.width * + (gint64) render_rect.height; + } + + if (progress) + { + gimp_progress_set_value (progress, + (gdouble) done_pixels / + (gdouble) all_pixels); + } + } + + if (result_buffer != dest_buffer) + { + if (! cancel) + gimp_gegl_buffer_copy (result_buffer, dest_rect, GEGL_ABYSS_NONE, + dest_buffer, dest_rect); + + g_object_unref (result_buffer); + } + + gegl_buffer_thaw_changed (dest_buffer); + + g_object_unref (gegl); + + if (operation_src_node) + { + gegl_node_connect_to (operation_src_node, "output", + operation, "input"); + } + + if (progress_started) + { + gimp_progress_end (progress); + + if (cancelable) + g_signal_handlers_disconnect_by_func (progress, + gimp_gegl_apply_operation_cancel, + &cancel); + } + + return ! cancel; +} + +void +gimp_gegl_apply_dither (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + gint levels, + gint dither_type) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + levels = CLAMP (levels, 2, 65536); + + node = gegl_node_new_child (NULL, + "operation", "gegl:dither", + "red-levels", levels, + "green-levels", levels, + "blue-levels", levels, + "alpha-bits", levels, + "dither-method", dither_type, + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_flatten (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GimpRGB *background, + GimpLayerColorSpace composite_space) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + g_return_if_fail (background != NULL); + + node = gimp_gegl_create_flatten_node (background, composite_space); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_feather (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble radius_x, + gdouble radius_y, + gboolean edge_lock) +{ + GaussianBlurAbyssPolicy abyss_policy; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + if (edge_lock) + abyss_policy = GAUSSIAN_BLUR_ABYSS_CLAMP; + else + abyss_policy = GAUSSIAN_BLUR_ABYSS_NONE; + + /* 3.5 is completely magic and picked to visually match the old + * gaussian_blur_region() on a crappy laptop display + */ + gimp_gegl_apply_gaussian_blur (src_buffer, + progress, undo_desc, + dest_buffer, dest_rect, + radius_x / 3.5, + radius_y / 3.5, + abyss_policy); +} + +void +gimp_gegl_apply_border (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gint radius_x, + gint radius_y, + GimpChannelBorderStyle style, + gboolean edge_lock) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + switch (style) + { + case GIMP_CHANNEL_BORDER_STYLE_HARD: + case GIMP_CHANNEL_BORDER_STYLE_FEATHERED: + { + gboolean feather = style == GIMP_CHANNEL_BORDER_STYLE_FEATHERED; + + node = gegl_node_new_child (NULL, + "operation", "gimp:border", + "radius-x", radius_x, + "radius-y", radius_y, + "feather", feather, + "edge-lock", edge_lock, + NULL); + } + break; + + case GIMP_CHANNEL_BORDER_STYLE_SMOOTH: + { + GeglNode *input, *output; + GeglNode *grow, *shrink, *subtract; + + node = gegl_node_new (); + + input = gegl_node_get_input_proxy (node, "input"); + output = gegl_node_get_output_proxy (node, "output"); + + /* Duplicate special-case behavior of "gimp:border". */ + if (radius_x == 1 && radius_y == 1) + { + grow = gegl_node_new_child (node, + "operation", "gegl:nop", + NULL); + shrink = gegl_node_new_child (node, + "operation", "gimp:shrink", + "radius-x", 1, + "radius-y", 1, + "edge-lock", edge_lock, + NULL); + } + else + { + grow = gegl_node_new_child (node, + "operation", "gimp:grow", + "radius-x", radius_x, + "radius-y", radius_y, + NULL); + shrink = gegl_node_new_child (node, + "operation", "gimp:shrink", + "radius-x", radius_x + 1, + "radius-y", radius_y + 1, + "edge-lock", edge_lock, + NULL); + } + + subtract = gegl_node_new_child (node, + "operation", "gegl:subtract", + NULL); + + gegl_node_link_many (input, grow, subtract, output, NULL); + gegl_node_link (input, shrink); + gegl_node_connect_to (shrink, "output", subtract, "aux"); + } + break; + + default: + gimp_assert_not_reached (); + } + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, dest_rect, TRUE); + g_object_unref (node); +} + +void +gimp_gegl_apply_grow (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gint radius_x, + gint radius_y) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gimp:grow", + "radius-x", radius_x, + "radius-y", radius_y, + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, dest_rect, TRUE); + g_object_unref (node); +} + +void +gimp_gegl_apply_shrink (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gint radius_x, + gint radius_y, + gboolean edge_lock) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gimp:shrink", + "radius-x", radius_x, + "radius-y", radius_y, + "edge-lock", edge_lock, + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, dest_rect, TRUE); + g_object_unref (node); +} + +void +gimp_gegl_apply_flood (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gimp:flood", + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, dest_rect, TRUE); + g_object_unref (node); +} + +void +gimp_gegl_apply_gaussian_blur (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble std_dev_x, + gdouble std_dev_y, + GaussianBlurAbyssPolicy abyss_policy) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gegl:gaussian-blur", + "std-dev-x", std_dev_x, + "std-dev-y", std_dev_y, + "abyss-policy", abyss_policy, + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, dest_rect, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_invert_gamma (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gegl:invert-gamma", + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_invert_linear (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gegl:invert-linear", + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_opacity (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + GeglBuffer *mask, + gint mask_offset_x, + gint mask_offset_y, + gdouble opacity) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + g_return_if_fail (mask == NULL || GEGL_IS_BUFFER (mask)); + + node = gimp_gegl_create_apply_opacity_node (mask, + mask_offset_x, + mask_offset_y, + opacity); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_scale (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + GimpInterpolationType interpolation_type, + gdouble x, + gdouble y) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gegl:scale-ratio", + "origin-x", 0.0, + "origin-y", 0.0, + "sampler", interpolation_type, + "abyss-policy", GEGL_ABYSS_CLAMP, + "x", x, + "y", y, + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_set_alpha (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + gdouble value) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gimp:set-alpha", + "value", value, + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_threshold (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + gdouble value) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gegl:threshold", + "value", value, + NULL); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} + +void +gimp_gegl_apply_transform (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + GimpInterpolationType interpolation_type, + GimpMatrix3 *transform) +{ + GeglNode *node; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + node = gegl_node_new_child (NULL, + "operation", "gegl:transform", + "near-z", GIMP_TRANSFORM_NEAR_Z, + "sampler", interpolation_type, + NULL); + + gimp_gegl_node_set_matrix (node, transform); + + gimp_gegl_apply_operation (src_buffer, progress, undo_desc, + node, dest_buffer, NULL, FALSE); + g_object_unref (node); +} diff --git a/app/gegl/gimp-gegl-apply-operation.h b/app/gegl/gimp-gegl-apply-operation.h new file mode 100644 index 0000000..3b19ee0 --- /dev/null +++ b/app/gegl/gimp-gegl-apply-operation.h @@ -0,0 +1,172 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-apply-operation.h + * Copyright (C) 2012 Øyvind KolÃ¥s <pippin@gimp.org> + * Sven Neumann <sven@gimp.org> + * Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_APPLY_OPERATION_H__ +#define __GIMP_GEGL_APPLY_OPERATION_H__ + + +/* generic functions, also used by the specific ones below */ + +void gimp_gegl_apply_operation (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglNode *operation, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gboolean crop_input); + +gboolean gimp_gegl_apply_cached_operation (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglNode *operation, + gboolean connect_src_buffer, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gboolean crop_input, + GeglBuffer *cache, + const GeglRectangle *valid_rects, + gint n_valid_rects, + gboolean cancellable); + + +/* apply specific operations */ + +void gimp_gegl_apply_dither (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + gint levels, + gint dither_type); + +void gimp_gegl_apply_flatten (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GimpRGB *background, + GimpLayerColorSpace composite_space); + +void gimp_gegl_apply_feather (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble radius_x, + gdouble radius_y, + gboolean edge_lock); + +void gimp_gegl_apply_border (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gint radius_x, + gint radius_y, + GimpChannelBorderStyle style, + gboolean edge_lock); + +void gimp_gegl_apply_grow (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gint radius_x, + gint radius_y); + +void gimp_gegl_apply_shrink (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gint radius_x, + gint radius_y, + gboolean edge_lock); + +void gimp_gegl_apply_flood (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect); + +/* UGLY: private enum of gegl:gaussian-blur */ +typedef enum +{ + GAUSSIAN_BLUR_ABYSS_NONE, + GAUSSIAN_BLUR_ABYSS_CLAMP +} GaussianBlurAbyssPolicy; + +void gimp_gegl_apply_gaussian_blur (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble std_dev_x, + gdouble std_dev_y, + GaussianBlurAbyssPolicy abyss_policy); + +void gimp_gegl_apply_invert_gamma (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer); + +void gimp_gegl_apply_invert_linear (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer); + +void gimp_gegl_apply_opacity (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + GeglBuffer *mask, + gint mask_offset_x, + gint mask_offset_y, + gdouble opacity); + +void gimp_gegl_apply_scale (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + GimpInterpolationType interpolation_type, + gdouble x, + gdouble y); + +void gimp_gegl_apply_set_alpha (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + gdouble value); + +void gimp_gegl_apply_threshold (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + gdouble value); + +void gimp_gegl_apply_transform (GeglBuffer *src_buffer, + GimpProgress *progress, + const gchar *undo_desc, + GeglBuffer *dest_buffer, + GimpInterpolationType interpolation_type, + GimpMatrix3 *transform); + + +#endif /* __GIMP_GEGL_APPLY_OPERATION_H__ */ diff --git a/app/gegl/gimp-gegl-enums.c b/app/gegl/gimp-gegl-enums.c new file mode 100644 index 0000000..de9c7b5 --- /dev/null +++ b/app/gegl/gimp-gegl-enums.c @@ -0,0 +1,43 @@ + +/* Generated data (by gimp-mkenums) */ + +#include "config.h" +#include <gio/gio.h> +#include "libgimpbase/gimpbase.h" +#include "core/core-enums.h" +#include "gimp-gegl-enums.h" +#include "gimp-intl.h" + +/* enumerations from "gimp-gegl-enums.h" */ +GType +gimp_cage_mode_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_CAGE_MODE_CAGE_CHANGE, "GIMP_CAGE_MODE_CAGE_CHANGE", "cage-change" }, + { GIMP_CAGE_MODE_DEFORM, "GIMP_CAGE_MODE_DEFORM", "deform" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_CAGE_MODE_CAGE_CHANGE, NC_("cage-mode", "Create or adjust the cage"), NULL }, + { GIMP_CAGE_MODE_DEFORM, NC_("cage-mode", "Deform the cage\nto deform the image"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpCageMode", values); + gimp_type_set_translation_context (type, "cage-mode"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + + +/* Generated data ends here */ + diff --git a/app/gegl/gimp-gegl-enums.h b/app/gegl/gimp-gegl-enums.h new file mode 100644 index 0000000..022c93a --- /dev/null +++ b/app/gegl/gimp-gegl-enums.h @@ -0,0 +1,35 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-enums.h + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_ENUMS_H__ +#define __GIMP_GEGL_ENUMS_H__ + + +#define GIMP_TYPE_CAGE_MODE (gimp_cage_mode_get_type ()) + +GType gimp_cage_mode_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_CAGE_MODE_CAGE_CHANGE, /*< desc="Create or adjust the cage" >*/ + GIMP_CAGE_MODE_DEFORM /*< desc="Deform the cage\nto deform the image" >*/ +} GimpCageMode; + + +#endif /* __GIMP_GEGL_ENUMS_H__ */ diff --git a/app/gegl/gimp-gegl-loops-sse2.c b/app/gegl/gimp-gegl-loops-sse2.c new file mode 100644 index 0000000..b9bf3ae --- /dev/null +++ b/app/gegl/gimp-gegl-loops-sse2.c @@ -0,0 +1,127 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-loops-sse2.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "gimp-gegl-loops-sse2.h" + + +#if COMPILE_SSE2_INTRINISICS + +#include <emmintrin.h> + + +/* helper function of gimp_gegl_smudge_with_paint_process_sse2() + * src and dest can be the same address + */ +static inline void +gimp_gegl_smudge_with_paint_blend_sse2 (const gfloat *src1, + gfloat src1_rate, + const gfloat *src2, + gfloat src2_rate, + gfloat *dest, + gboolean no_erasing_src2) +{ + /* 2017/4/13 shark0r : According to my test, SSE decreases about 25% + * execution time + */ + + __m128 v_src1 = _mm_loadu_ps (src1); + __m128 v_src2 = _mm_loadu_ps (src2); + __m128 *v_dest = (__v4sf *) dest; + + gfloat orginal_src2_alpha; + gfloat src1_alpha; + gfloat src2_alpha; + gfloat result_alpha; + + orginal_src2_alpha = v_src2[3]; + src1_alpha = src1_rate * v_src1[3]; + src2_alpha = src2_rate * orginal_src2_alpha; + result_alpha = src1_alpha + src2_alpha; + + if (result_alpha == 0) + { + *v_dest = _mm_set1_ps (0); + return; + } + + *v_dest = (v_src1 * _mm_set1_ps (src1_alpha) + + v_src2 * _mm_set1_ps (src2_alpha)) / + _mm_set1_ps (result_alpha); + + if (no_erasing_src2) + { + result_alpha = MAX (result_alpha, orginal_src2_alpha); + } + + dest[3] = result_alpha; +} + +/* helper function of gimp_gegl_smudge_with_paint() + * + * note that it's the caller's responsibility to verify that the buffers are + * properly aligned + */ +void +gimp_gegl_smudge_with_paint_process_sse2 (gfloat *accum, + const gfloat *canvas, + gfloat *paint, + gint count, + const gfloat *brush_color, + gfloat brush_a, + gboolean no_erasing, + gfloat flow, + gfloat rate) +{ + while (count--) + { + /* blend accum_buffer and canvas_buffer to accum_buffer */ + gimp_gegl_smudge_with_paint_blend_sse2 (accum, rate, canvas, 1 - rate, + accum, no_erasing); + + /* blend accum_buffer and brush color/pixmap to paint_buffer */ + if (brush_a == 0) /* pure smudge */ + { + memcpy (paint, accum, sizeof (gfloat) * 4); + } + else + { + const gfloat *src1 = brush_color ? brush_color : paint; + + gimp_gegl_smudge_with_paint_blend_sse2 (src1, flow, accum, 1 - flow, + paint, no_erasing); + } + + accum += 4; + canvas += 4; + paint += 4; + } +} + +#endif /* COMPILE_SSE2_INTRINISICS */ diff --git a/app/gegl/gimp-gegl-loops-sse2.h b/app/gegl/gimp-gegl-loops-sse2.h new file mode 100644 index 0000000..fc8100c --- /dev/null +++ b/app/gegl/gimp-gegl-loops-sse2.h @@ -0,0 +1,40 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-loops-sse2.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_LOOPS_SSE2_H__ +#define __GIMP_GEGL_LOOPS_SSE2_H__ + + +#if COMPILE_SSE2_INTRINISICS + +void gimp_gegl_smudge_with_paint_process_sse2 (gfloat *accum, + const gfloat *canvas, + gfloat *paint, + gint count, + const gfloat *brush_color, + gfloat brush_a, + gboolean no_erasing, + gfloat flow, + gfloat rate); + +#endif /* COMPILE_SSE2_INTRINISICS */ + + +#endif /* __GIMP_GEGL_LOOPS_SSE2_H__ */ diff --git a/app/gegl/gimp-gegl-loops.cc b/app/gegl/gimp-gegl-loops.cc new file mode 100644 index 0000000..4564bcd --- /dev/null +++ b/app/gegl/gimp-gegl-loops.cc @@ -0,0 +1,1089 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-loops.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> +#include <gegl-buffer-backend.h> + +extern "C" +{ + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "gimp-gegl-types.h" + +#include "gimp-babl.h" +#include "gimp-gegl-loops.h" +#include "gimp-gegl-loops-sse2.h" + +#include "core/gimp-atomic.h" +#include "core/gimp-utils.h" +#include "core/gimpprogress.h" + + +#define PIXELS_PER_THREAD \ + (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */) + +#define SHIFTED_AREA(dest, src) \ + const GeglRectangle dest##_area_ = { \ + src##_area->x + (dest##_rect->x - src##_rect->x), \ + src##_area->y + (dest##_rect->y - src##_rect->y), \ + src##_area->width, src##_area->height \ + }; \ + const GeglRectangle * const dest##_area = &dest##_area_ + + +void +gimp_gegl_buffer_copy (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglAbyssPolicy abyss_policy, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect) +{ + GeglRectangle real_dest_rect; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (GEGL_IS_BUFFER (dest_buffer)); + + if (! src_rect) + src_rect = gegl_buffer_get_extent (src_buffer); + + if (! dest_rect) + dest_rect = src_rect; + + real_dest_rect = *dest_rect; + real_dest_rect.width = src_rect->width; + real_dest_rect.height = src_rect->height; + + dest_rect = &real_dest_rect; + + if (gegl_buffer_get_format (src_buffer) == + gegl_buffer_get_format (dest_buffer)) + { + gboolean skip_abyss = FALSE; + GeglRectangle src_abyss; + GeglRectangle dest_abyss; + + if (abyss_policy == GEGL_ABYSS_NONE) + { + src_abyss = *gegl_buffer_get_abyss (src_buffer); + dest_abyss = *gegl_buffer_get_abyss (dest_buffer); + + skip_abyss = ! (gegl_rectangle_contains (&src_abyss, src_rect) && + gegl_rectangle_contains (&dest_abyss, dest_rect)); + } + + if (skip_abyss) + { + if (src_buffer < dest_buffer) + { + gegl_tile_handler_lock (GEGL_TILE_HANDLER (src_buffer)); + gegl_tile_handler_lock (GEGL_TILE_HANDLER (dest_buffer)); + } + else + { + gegl_tile_handler_lock (GEGL_TILE_HANDLER (dest_buffer)); + gegl_tile_handler_lock (GEGL_TILE_HANDLER (src_buffer)); + } + + gegl_buffer_set_abyss (src_buffer, src_rect); + gegl_buffer_set_abyss (dest_buffer, dest_rect); + } + + gegl_buffer_copy (src_buffer, src_rect, abyss_policy, + dest_buffer, dest_rect); + + if (skip_abyss) + { + gegl_buffer_set_abyss (src_buffer, &src_abyss); + gegl_buffer_set_abyss (dest_buffer, &dest_abyss); + + gegl_tile_handler_unlock (GEGL_TILE_HANDLER (src_buffer)); + gegl_tile_handler_unlock (GEGL_TILE_HANDLER (dest_buffer)); + } + } + else + { + gegl_parallel_distribute_area ( + src_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *src_area) + { + SHIFTED_AREA (dest, src); + + gegl_buffer_copy (src_buffer, src_area, abyss_policy, + dest_buffer, dest_area); + }); + } +} + +void +gimp_gegl_clear (GeglBuffer *buffer, + const GeglRectangle *rect) +{ + const Babl *format; + gint bpp; + gint n_components; + gint bpc; + gint alpha_offset; + + g_return_if_fail (GEGL_IS_BUFFER (buffer)); + + if (! rect) + rect = gegl_buffer_get_extent (buffer); + + format = gegl_buffer_get_format (buffer); + + if (! babl_format_has_alpha (format)) + return; + + bpp = babl_format_get_bytes_per_pixel (format); + n_components = babl_format_get_n_components (format); + bpc = bpp / n_components; + alpha_offset = (n_components - 1) * bpc; + + gegl_parallel_distribute_area ( + rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *area) + { + GeglBufferIterator *iter; + + iter = gegl_buffer_iterator_new (buffer, area, 0, format, + GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, + 1); + + while (gegl_buffer_iterator_next (iter)) + { + guint8 *data = (guint8 *) iter->items[0].data; + gint i; + + data += alpha_offset; + + for (i = 0; i < iter->length; i++) + { + memset (data, 0, bpc); + + data += bpp; + } + } + }); +} + +void +gimp_gegl_convolve (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + const gfloat *kernel, + gint kernel_size, + gdouble divisor, + GimpConvolutionType mode, + gboolean alpha_weighting) +{ + gfloat *src; + gint src_rowstride; + + const Babl *src_format; + const Babl *dest_format; + gint src_components; + gint dest_components; + gfloat offset; + + if (! src_rect) + src_rect = gegl_buffer_get_extent (src_buffer); + + if (! dest_rect) + dest_rect = gegl_buffer_get_extent (dest_buffer); + + src_format = gegl_buffer_get_format (src_buffer); + + if (babl_format_is_palette (src_format)) + src_format = gimp_babl_format (GIMP_RGB, + GIMP_PRECISION_FLOAT_LINEAR, + babl_format_has_alpha (src_format)); + else + src_format = gimp_babl_format (gimp_babl_format_get_base_type (src_format), + GIMP_PRECISION_FLOAT_LINEAR, + babl_format_has_alpha (src_format)); + + dest_format = gegl_buffer_get_format (dest_buffer); + + if (babl_format_is_palette (dest_format)) + dest_format = gimp_babl_format (GIMP_RGB, + GIMP_PRECISION_FLOAT_LINEAR, + babl_format_has_alpha (dest_format)); + else + dest_format = gimp_babl_format (gimp_babl_format_get_base_type (dest_format), + GIMP_PRECISION_FLOAT_LINEAR, + babl_format_has_alpha (dest_format)); + + src_components = babl_format_get_n_components (src_format); + dest_components = babl_format_get_n_components (dest_format); + + /* Get source pixel data */ + src_rowstride = src_components * src_rect->width; + src = g_new (gfloat, src_rowstride * src_rect->height); + gegl_buffer_get (src_buffer, src_rect, 1.0, src_format, src, + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + + /* If the mode is NEGATIVE_CONVOL, the offset should be 0.5 */ + if (mode == GIMP_NEGATIVE_CONVOL) + { + offset = 0.5; + mode = GIMP_NORMAL_CONVOL; + } + else + { + offset = 0.0; + } + + gegl_parallel_distribute_area ( + dest_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *dest_area) + { + const gint components = src_components; + const gint a_component = components - 1; + const gint margin = kernel_size / 2; + GeglBufferIterator *dest_iter; + + /* Set up dest iterator */ + dest_iter = gegl_buffer_iterator_new (dest_buffer, dest_area, 0, dest_format, + GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1); + + while (gegl_buffer_iterator_next (dest_iter)) + { + /* Convolve the src image using the convolution kernel, writing + * to dest Convolve is not tile-enabled--use accordingly + */ + gfloat *dest = (gfloat *) dest_iter->items[0].data; + const gint x1 = 0; + const gint y1 = 0; + const gint x2 = src_rect->width - 1; + const gint y2 = src_rect->height - 1; + const gint dest_x1 = dest_iter->items[0].roi.x; + const gint dest_y1 = dest_iter->items[0].roi.y; + const gint dest_x2 = dest_iter->items[0].roi.x + dest_iter->items[0].roi.width; + const gint dest_y2 = dest_iter->items[0].roi.y + dest_iter->items[0].roi.height; + gint x, y; + + for (y = dest_y1; y < dest_y2; y++) + { + gfloat *d = dest; + + if (alpha_weighting) + { + for (x = dest_x1; x < dest_x2; x++) + { + const gfloat *m = kernel; + gdouble total[4] = { 0.0, 0.0, 0.0, 0.0 }; + gdouble weighted_divisor = 0.0; + gint i, j, b; + + for (j = y - margin; j <= y + margin; j++) + { + for (i = x - margin; i <= x + margin; i++, m++) + { + gint xx = CLAMP (i, x1, x2); + gint yy = CLAMP (j, y1, y2); + const gfloat *s = src + yy * src_rowstride + xx * components; + const gfloat a = s[a_component]; + + if (a) + { + gdouble mult_alpha = *m * a; + + weighted_divisor += mult_alpha; + + for (b = 0; b < a_component; b++) + total[b] += mult_alpha * s[b]; + + total[a_component] += mult_alpha; + } + } + } + + if (weighted_divisor == 0.0) + weighted_divisor = divisor; + + for (b = 0; b < a_component; b++) + total[b] /= weighted_divisor; + + total[a_component] /= divisor; + + for (b = 0; b < components; b++) + { + total[b] += offset; + + if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0) + total[b] = - total[b]; + + *d++ = CLAMP (total[b], 0.0, 1.0); + } + } + } + else + { + for (x = dest_x1; x < dest_x2; x++) + { + const gfloat *m = kernel; + gdouble total[4] = { 0.0, 0.0, 0.0, 0.0 }; + gint i, j, b; + + for (j = y - margin; j <= y + margin; j++) + { + for (i = x - margin; i <= x + margin; i++, m++) + { + gint xx = CLAMP (i, x1, x2); + gint yy = CLAMP (j, y1, y2); + const gfloat *s = src + yy * src_rowstride + xx * components; + + for (b = 0; b < components; b++) + total[b] += *m * s[b]; + } + } + + for (b = 0; b < components; b++) + { + total[b] = total[b] / divisor + offset; + + if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0) + total[b] = - total[b]; + + *d++ = CLAMP (total[b], 0.0, 1.0); + } + } + } + + dest += dest_iter->items[0].roi.width * dest_components; + } + } + }); + + g_free (src); +} + +static inline gfloat +odd_powf (gfloat x, + gfloat y) +{ + if (x >= 0.0f) + return powf ( x, y); + else + return -powf (-x, y); +} + +void +gimp_gegl_dodgeburn (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble exposure, + GimpDodgeBurnType type, + GimpTransferMode mode) +{ + if (type == GIMP_DODGE_BURN_TYPE_BURN) + exposure = -exposure; + + if (! src_rect) + src_rect = gegl_buffer_get_extent (src_buffer); + + if (! dest_rect) + dest_rect = gegl_buffer_get_extent (dest_buffer); + + gegl_parallel_distribute_area ( + src_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *src_area) + { + GeglBufferIterator *iter; + + SHIFTED_AREA (dest, src); + + iter = gegl_buffer_iterator_new (src_buffer, src_area, 0, + babl_format ("R'G'B'A float"), + GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2); + + gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0, + babl_format ("R'G'B'A float"), + GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); + + switch (mode) + { + gfloat factor; + + case GIMP_TRANSFER_HIGHLIGHTS: + factor = 1.0 + exposure * (0.333333); + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *src = (gfloat *) iter->items[0].data; + gfloat *dest = (gfloat *) iter->items[1].data; + gint count = iter->length; + + while (count--) + { + *dest++ = *src++ * factor; + *dest++ = *src++ * factor; + *dest++ = *src++ * factor; + + *dest++ = *src++; + } + } + break; + + case GIMP_TRANSFER_MIDTONES: + if (exposure < 0) + factor = 1.0 - exposure * (0.333333); + else + factor = 1.0 / (1.0 + exposure); + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *src = (gfloat *) iter->items[0].data; + gfloat *dest = (gfloat *) iter->items[1].data; + gint count = iter->length; + + while (count--) + { + *dest++ = odd_powf (*src++, factor); + *dest++ = odd_powf (*src++, factor); + *dest++ = odd_powf (*src++, factor); + + *dest++ = *src++; + } + } + break; + + case GIMP_TRANSFER_SHADOWS: + if (exposure >= 0) + factor = 0.333333 * exposure; + else + factor = -0.333333 * exposure; + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *src = (gfloat *) iter->items[0].data; + gfloat *dest = (gfloat *) iter->items[1].data; + gint count = iter->length; + + while (count--) + { + if (exposure >= 0) + { + gfloat s; + + s = *src++; *dest++ = factor + s - factor * s; + s = *src++; *dest++ = factor + s - factor * s; + s = *src++; *dest++ = factor + s - factor * s; + } + else + { + gfloat s; + + s = *src++; + if (s < factor) + *dest++ = 0; + else /* factor <= value <=1 */ + *dest++ = (s - factor) / (1.0 - factor); + + s = *src++; + if (s < factor) + *dest++ = 0; + else /* factor <= value <=1 */ + *dest++ = (s - factor) / (1.0 - factor); + + s = *src++; + if (s < factor) + *dest++ = 0; + else /* factor <= value <=1 */ + *dest++ = (s - factor) / (1.0 - factor); + } + + *dest++ = *src++; + } + } + break; + } + }); +} + +/* helper function of gimp_gegl_smudge_with_paint_process() + src and dest can be the same address + */ +static inline void +gimp_gegl_smudge_with_paint_blend (const gfloat *src1, + gfloat src1_rate, + const gfloat *src2, + gfloat src2_rate, + gfloat *dest, + gboolean no_erasing_src2) +{ + gfloat orginal_src2_alpha; + gfloat src1_alpha; + gfloat src2_alpha; + gfloat result_alpha; + gint b; + + orginal_src2_alpha = src2[3]; + src1_alpha = src1_rate * src1[3]; + src2_alpha = src2_rate * orginal_src2_alpha; + result_alpha = src1_alpha + src2_alpha; + + if (result_alpha == 0) + { + memset (dest, 0, sizeof (gfloat) * 4); + return; + } + + for (b = 0; b < 3; b++) + dest[b] = (src1[b] * src1_alpha + src2[b] * src2_alpha) / result_alpha; + + if (no_erasing_src2) + { + result_alpha = MAX (result_alpha, orginal_src2_alpha); + } + + dest[3] = result_alpha; +} + +/* helper function of gimp_gegl_smudge_with_paint() */ +static void +gimp_gegl_smudge_with_paint_process (gfloat *accum, + const gfloat *canvas, + gfloat *paint, + gint count, + const gfloat *brush_color, + gfloat brush_a, + gboolean no_erasing, + gfloat flow, + gfloat rate) +{ + while (count--) + { + /* blend accum_buffer and canvas_buffer to accum_buffer */ + gimp_gegl_smudge_with_paint_blend (accum, rate, canvas, 1 - rate, + accum, no_erasing); + + /* blend accum_buffer and brush color/pixmap to paint_buffer */ + if (brush_a == 0) /* pure smudge */ + { + memcpy (paint, accum, sizeof (gfloat) * 4); + } + else + { + const gfloat *src1 = brush_color ? brush_color : paint; + + gimp_gegl_smudge_with_paint_blend (src1, flow, accum, 1 - flow, + paint, no_erasing); + } + + accum += 4; + canvas += 4; + paint += 4; + } +} + +/* smudge painting calculation. Currently only smudge tool uses this function + * Accum = rate*Accum + (1-rate)*Canvas + * if brush_color!=NULL + * Paint = flow*brushColor + (1-flow)*Accum + * else + * Paint = flow*Paint + (1-flow)*Accum + */ +void +gimp_gegl_smudge_with_paint (GeglBuffer *accum_buffer, + const GeglRectangle *accum_rect, + GeglBuffer *canvas_buffer, + const GeglRectangle *canvas_rect, + const GimpRGB *brush_color, + GeglBuffer *paint_buffer, + gboolean no_erasing, + gdouble flow, + gdouble rate) +{ + gfloat brush_color_float[4]; + gfloat brush_a = flow; + GeglAccessMode paint_buffer_access_mode = (brush_color ? + GEGL_ACCESS_WRITE : + GEGL_ACCESS_READWRITE); +#if COMPILE_SSE2_INTRINISICS + gboolean sse2 = (gimp_cpu_accel_get_support () & + GIMP_CPU_ACCEL_X86_SSE2); +#endif + + if (! accum_rect) + accum_rect = gegl_buffer_get_extent (accum_buffer); + + if (! canvas_rect) + canvas_rect = gegl_buffer_get_extent (canvas_buffer); + + /* convert brush color from double to float */ + if (brush_color) + { + const gdouble *brush_color_ptr = &brush_color->r; + gint b; + + for (b = 0; b < 4; b++) + brush_color_float[b] = brush_color_ptr[b]; + + brush_a *= brush_color_ptr[3]; + } + + gegl_parallel_distribute_area ( + accum_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *accum_area) + { + GeglBufferIterator *iter; + + SHIFTED_AREA (canvas, accum); + + iter = gegl_buffer_iterator_new (accum_buffer, accum_area, 0, + babl_format ("RGBA float"), + GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 3); + + gegl_buffer_iterator_add (iter, canvas_buffer, canvas_area, 0, + babl_format ("RGBA float"), + GEGL_ACCESS_READ, GEGL_ABYSS_NONE); + + gegl_buffer_iterator_add (iter, paint_buffer, + GEGL_RECTANGLE (accum_area->x - accum_rect->x, + accum_area->y - accum_rect->y, + 0, 0), + 0, + babl_format ("RGBA float"), + paint_buffer_access_mode, GEGL_ABYSS_NONE); + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *accum = (gfloat *) iter->items[0].data; + const gfloat *canvas = (const gfloat *) iter->items[1].data; + gfloat *paint = (gfloat *) iter->items[2].data; + gint count = iter->length; + +#if COMPILE_SSE2_INTRINISICS + if (sse2 && ((guintptr) accum | + (guintptr) canvas | + (guintptr) (brush_color ? brush_color_float : paint) | + (guintptr) paint) % 16 == 0) + { + gimp_gegl_smudge_with_paint_process_sse2 (accum, canvas, paint, count, + brush_color ? brush_color_float : + NULL, + brush_a, + no_erasing, flow, rate); + } + else +#endif + { + gimp_gegl_smudge_with_paint_process (accum, canvas, paint, count, + brush_color ? brush_color_float : + NULL, + brush_a, + no_erasing, flow, rate); + } + } + }); +} + +void +gimp_gegl_apply_mask (GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble opacity) +{ + if (! mask_rect) + mask_rect = gegl_buffer_get_extent (mask_buffer); + + if (! dest_rect) + dest_rect = gegl_buffer_get_extent (dest_buffer); + + gegl_parallel_distribute_area ( + mask_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *mask_area) + { + GeglBufferIterator *iter; + + SHIFTED_AREA (dest, mask); + + iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0, + babl_format ("Y float"), + GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2); + + gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0, + babl_format ("RGBA float"), + GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); + + while (gegl_buffer_iterator_next (iter)) + { + const gfloat *mask = (const gfloat *) iter->items[0].data; + gfloat *dest = (gfloat *) iter->items[1].data; + gint count = iter->length; + + while (count--) + { + dest[3] *= *mask * opacity; + + mask += 1; + dest += 4; + } + } + }); +} + +void +gimp_gegl_combine_mask (GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble opacity) +{ + if (! mask_rect) + mask_rect = gegl_buffer_get_extent (mask_buffer); + + if (! dest_rect) + dest_rect = gegl_buffer_get_extent (dest_buffer); + + gegl_parallel_distribute_area ( + mask_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *mask_area) + { + GeglBufferIterator *iter; + + SHIFTED_AREA (dest, mask); + + iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0, + babl_format ("Y float"), + GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2); + + gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0, + babl_format ("Y float"), + GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); + + while (gegl_buffer_iterator_next (iter)) + { + const gfloat *mask = (const gfloat *) iter->items[0].data; + gfloat *dest = (gfloat *) iter->items[1].data; + gint count = iter->length; + + while (count--) + { + *dest *= *mask * opacity; + + mask += 1; + dest += 1; + } + } + }); +} + +void +gimp_gegl_combine_mask_weird (GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble opacity, + gboolean stipple) +{ + if (! mask_rect) + mask_rect = gegl_buffer_get_extent (mask_buffer); + + if (! dest_rect) + dest_rect = gegl_buffer_get_extent (dest_buffer); + + gegl_parallel_distribute_area ( + mask_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *mask_area) + { + GeglBufferIterator *iter; + + SHIFTED_AREA (dest, mask); + + iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0, + babl_format ("Y float"), + GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2); + + gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0, + babl_format ("Y float"), + GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); + + while (gegl_buffer_iterator_next (iter)) + { + const gfloat *mask = (const gfloat *) iter->items[0].data; + gfloat *dest = (gfloat *) iter->items[1].data; + gint count = iter->length; + + if (stipple) + { + while (count--) + { + dest[0] += (1.0 - dest[0]) * *mask * opacity; + + mask += 1; + dest += 1; + } + } + else + { + while (count--) + { + if (opacity > dest[0]) + dest[0] += (opacity - dest[0]) * *mask * opacity; + + mask += 1; + dest += 1; + } + } + } + }); +} + +void +gimp_gegl_index_to_mask (GeglBuffer *indexed_buffer, + const GeglRectangle *indexed_rect, + const Babl *indexed_format, + GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + gint index) +{ + if (! indexed_rect) + indexed_rect = gegl_buffer_get_extent (indexed_buffer); + + if (! mask_rect) + mask_rect = gegl_buffer_get_extent (mask_buffer); + + gegl_parallel_distribute_area ( + indexed_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *indexed_area) + { + GeglBufferIterator *iter; + + SHIFTED_AREA (mask, indexed); + + iter = gegl_buffer_iterator_new (indexed_buffer, indexed_area, 0, + indexed_format, + GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2); + + gegl_buffer_iterator_add (iter, mask_buffer, mask_area, 0, + babl_format ("Y float"), + GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); + + while (gegl_buffer_iterator_next (iter)) + { + const guchar *indexed = (const guchar *) iter->items[0].data; + gfloat *mask = (gfloat *) iter->items[1].data; + gint count = iter->length; + + while (count--) + { + if (*indexed == index) + *mask = 1.0; + else + *mask = 0.0; + + indexed++; + mask++; + } + } + }); +} + +static void +gimp_gegl_convert_color_profile_progress (GimpProgress *progress, + gdouble value) +{ + if (gegl_is_main_thread ()) + gimp_progress_set_value (progress, value); +} + +void +gimp_gegl_convert_color_profile (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GimpColorProfile *src_profile, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + GimpColorProfile *dest_profile, + GimpColorRenderingIntent intent, + gboolean bpc, + GimpProgress *progress) +{ + GimpColorTransform *transform; + guint flags = 0; + const Babl *src_format; + const Babl *dest_format; + + src_format = gegl_buffer_get_format (src_buffer); + dest_format = gegl_buffer_get_format (dest_buffer); + + if (bpc) + flags |= GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION; + + flags |= GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE; + + transform = gimp_color_transform_new (src_profile, src_format, + dest_profile, dest_format, + intent, + (GimpColorTransformFlags) flags); + + if (! src_rect) + src_rect = gegl_buffer_get_extent (src_buffer); + + if (! dest_rect) + dest_rect = gegl_buffer_get_extent (dest_buffer); + + if (transform) + { + if (progress) + { + g_signal_connect_swapped ( + transform, "progress", + G_CALLBACK (gimp_gegl_convert_color_profile_progress), + progress); + } + + GIMP_TIMER_START (); + + gegl_parallel_distribute_area ( + src_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *src_area) + { + SHIFTED_AREA (dest, src); + + gimp_color_transform_process_buffer (transform, + src_buffer, src_area, + dest_buffer, dest_area); + }); + + GIMP_TIMER_END ("converting buffer"); + + g_object_unref (transform); + } + else + { + gimp_gegl_buffer_copy (src_buffer, src_rect, GEGL_ABYSS_NONE, + dest_buffer, dest_rect); + + if (progress) + gimp_progress_set_value (progress, 1.0); + } +} + +void +gimp_gegl_average_color (GeglBuffer *buffer, + const GeglRectangle *rect, + gboolean clip_to_buffer, + GeglAbyssPolicy abyss_policy, + const Babl *format, + gpointer color) +{ + typedef struct + { + gfloat color[4]; + gint n; + } Sum; + + const Babl *average_format = babl_format ("RaGaBaA float"); + GeglRectangle roi; + GSList * volatile sums = NULL; + GSList *list; + Sum average = {}; + gint c; + + g_return_if_fail (GEGL_IS_BUFFER (buffer)); + g_return_if_fail (color != NULL); + + if (! rect) + rect = gegl_buffer_get_extent (buffer); + + if (! format) + format = gegl_buffer_get_format (buffer); + + if (clip_to_buffer) + gegl_rectangle_intersect (&roi, rect, gegl_buffer_get_extent (buffer)); + else + roi = *rect; + + gegl_parallel_distribute_area ( + &roi, PIXELS_PER_THREAD, + [&] (const GeglRectangle *area) + { + Sum *sum; + GeglBufferIterator *iter; + gfloat color[4] = {}; + gint n = 0; + + iter = gegl_buffer_iterator_new (buffer, area, 0, average_format, + GEGL_BUFFER_READ, abyss_policy, 1); + + while (gegl_buffer_iterator_next (iter)) + { + const gfloat *p = (const gfloat *) iter->items[0].data; + gint i; + + for (i = 0; i < iter->length; i++) + { + gint c; + + for (c = 0; c < 4; c++) + color[c] += p[c]; + + p += 4; + } + + n += iter->length; + } + + sum = g_slice_new (Sum); + + memcpy (sum->color, color, sizeof (color)); + sum->n = n; + + gimp_atomic_slist_push_head (&sums, sum); + }); + + for (list = sums; list; list = g_slist_next (list)) + { + Sum *sum = (Sum *) list->data; + + for (c = 0; c < 4; c++) + average.color[c] += sum->color[c]; + + average.n += sum->n; + + g_slice_free (Sum, sum); + } + + g_slist_free (sums); + + if (average.n > 0) + { + for (c = 0; c < 4; c++) + average.color[c] /= average.n; + } + + babl_process (babl_fish (average_format, format), average.color, color, 1); +} + +} /* extern "C" */ diff --git a/app/gegl/gimp-gegl-loops.h b/app/gegl/gimp-gegl-loops.h new file mode 100644 index 0000000..872c2b4 --- /dev/null +++ b/app/gegl/gimp-gegl-loops.h @@ -0,0 +1,109 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-loops.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_LOOPS_H__ +#define __GIMP_GEGL_LOOPS_H__ + + +void gimp_gegl_buffer_copy (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglAbyssPolicy abyss_policy, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect); + +void gimp_gegl_clear (GeglBuffer *buffer, + const GeglRectangle *rect); + +/* this is a pretty stupid port of concolve_region() that only works + * on a linear source buffer + */ +void gimp_gegl_convolve (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + const gfloat *kernel, + gint kernel_size, + gdouble divisor, + GimpConvolutionType mode, + gboolean alpha_weighting); + +void gimp_gegl_dodgeburn (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble exposure, + GimpDodgeBurnType type, + GimpTransferMode mode); + +void gimp_gegl_smudge_with_paint (GeglBuffer *accum_buffer, + const GeglRectangle *accum_rect, + GeglBuffer *canvas_buffer, + const GeglRectangle *canvas_rect, + const GimpRGB *brush_color, + GeglBuffer *paint_buffer, + gboolean no_erasing, + gdouble flow, + gdouble rate); + +void gimp_gegl_apply_mask (GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble opacity); + +void gimp_gegl_combine_mask (GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble opacity); + +void gimp_gegl_combine_mask_weird (GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + gdouble opacity, + gboolean stipple); + +void gimp_gegl_index_to_mask (GeglBuffer *indexed_buffer, + const GeglRectangle *indexed_rect, + const Babl *indexed_format, + GeglBuffer *mask_buffer, + const GeglRectangle *mask_rect, + gint index); + +void gimp_gegl_convert_color_profile (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GimpColorProfile *src_profile, + GeglBuffer *dest_buffer, + const GeglRectangle *dest_rect, + GimpColorProfile *dest_profile, + GimpColorRenderingIntent intent, + gboolean bpc, + GimpProgress *progress); + +void gimp_gegl_average_color (GeglBuffer *buffer, + const GeglRectangle *rect, + gboolean clip_to_buffer, + GeglAbyssPolicy abyss_policy, + const Babl *format, + gpointer color); + + +#endif /* __GIMP_GEGL_LOOPS_H__ */ diff --git a/app/gegl/gimp-gegl-mask-combine.cc b/app/gegl/gimp-gegl-mask-combine.cc new file mode 100644 index 0000000..0e61c0e --- /dev/null +++ b/app/gegl/gimp-gegl-mask-combine.cc @@ -0,0 +1,653 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <gio/gio.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpmath/gimpmath.h" + +extern "C" +{ + +#include "gimp-gegl-types.h" + +#include "gimp-babl.h" +#include "gimp-gegl-loops.h" +#include "gimp-gegl-mask-combine.h" + + +#define EPSILON 1e-6 + +#define PIXELS_PER_THREAD \ + (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */) + + +gboolean +gimp_gegl_mask_combine_rect (GeglBuffer *mask, + GimpChannelOps op, + gint x, + gint y, + gint w, + gint h) +{ + GeglRectangle rect; + gfloat value; + + g_return_val_if_fail (GEGL_IS_BUFFER (mask), FALSE); + + if (! gegl_rectangle_intersect (&rect, + GEGL_RECTANGLE (x, y, w, h), + gegl_buffer_get_abyss (mask))) + { + return FALSE; + } + + switch (op) + { + case GIMP_CHANNEL_OP_REPLACE: + case GIMP_CHANNEL_OP_ADD: + value = 1.0f; + break; + + case GIMP_CHANNEL_OP_SUBTRACT: + value = 0.0f; + break; + + case GIMP_CHANNEL_OP_INTERSECT: + return TRUE; + } + + gegl_buffer_set_color_from_pixel (mask, &rect, &value, + babl_format ("Y float")); + + return TRUE; +} + +gboolean +gimp_gegl_mask_combine_ellipse (GeglBuffer *mask, + GimpChannelOps op, + gint x, + gint y, + gint w, + gint h, + gboolean antialias) +{ + return gimp_gegl_mask_combine_ellipse_rect (mask, op, x, y, w, h, + w / 2.0, h / 2.0, antialias); +} + +gboolean +gimp_gegl_mask_combine_ellipse_rect (GeglBuffer *mask, + GimpChannelOps op, + gint x, + gint y, + gint w, + gint h, + gdouble rx, + gdouble ry, + gboolean antialias) +{ + GeglRectangle rect; + const Babl *format; + gint bpp; + gfloat one_f = 1.0f; + gpointer one; + gdouble cx; + gdouble cy; + gint left; + gint right; + gint top; + gint bottom; + + g_return_val_if_fail (GEGL_IS_BUFFER (mask), FALSE); + + if (rx <= EPSILON || ry <= EPSILON) + return gimp_gegl_mask_combine_rect (mask, op, x, y, w, h); + + left = x; + right = x + w; + top = y; + bottom = y + h; + + cx = (left + right) / 2.0; + cy = (top + bottom) / 2.0; + + rx = MIN (rx, w / 2.0); + ry = MIN (ry, h / 2.0); + + if (! gegl_rectangle_intersect (&rect, + GEGL_RECTANGLE (x, y, w, h), + gegl_buffer_get_abyss (mask))) + { + return FALSE; + } + + format = gegl_buffer_get_format (mask); + + if (antialias) + { + format = gimp_babl_format_change_component_type ( + format, GIMP_COMPONENT_TYPE_FLOAT); + } + + bpp = babl_format_get_bytes_per_pixel (format); + one = g_alloca (bpp); + + babl_process (babl_fish ("Y float", format), &one_f, one, 1); + + /* coordinate-system transforms. (x, y) coordinates are in the image + * coordinate-system, and (u, v) coordinates are in a coordinate-system + * aligned with the center of one of the elliptic corners, with the positive + * directions pointing away from the rectangle. when converting from (x, y) + * to (u, v), we use the closest elliptic corner. + */ + auto x_to_u = [=] (gdouble x) + { + if (x < cx) + return (left + rx) - x; + else + return x - (right - rx); + }; + + auto y_to_v = [=] (gdouble y) + { + if (y < cy) + return (top + ry) - y; + else + return y - (bottom - ry); + }; + + auto u_to_x_left = [=] (gdouble u) + { + return (left + rx) - u; + }; + + auto u_to_x_right = [=] (gdouble u) + { + return (right - rx) + u; + }; + + /* intersection of a horizontal line with the ellipse */ + auto v_to_u = [=] (gdouble v) + { + if (v > 0.0) + return sqrt (MAX (SQR (rx) - SQR (rx * v / ry), 0.0)); + else + return rx; + }; + + /* intersection of a vertical line with the ellipse */ + auto u_to_v = [=] (gdouble u) + { + if (u > 0.0) + return sqrt (MAX (SQR (ry) - SQR (ry * u / rx), 0.0)); + else + return ry; + }; + + /* signed, normalized distance of a point from the ellipse's circumference. + * the sign of the result determines if the point is inside (positive) or + * outside (negative) the ellipse. the result is normalized to the cross- + * section length of a pixel, in the direction of the closest point along the + * ellipse. + * + * we use the following method to approximate the distance: pass horizontal + * and vertical lines at the given point, P, and find their (positive) points + * of intersection with the ellipse, A and B. the segment AB is an + * approximation of the corresponding elliptic arc (see bug #147836). find + * the closest point, C, to P, along the segment AB. find the (positive) + * point of intersection, Q, of the line PC and the ellipse. Q is an + * approximation for the closest point to P along the ellipse, and the + * approximated distance is the distance from P to Q. + */ + auto ellipse_distance = [=] (gdouble u, + gdouble v) + { + gdouble du; + gdouble dv; + gdouble t; + gdouble a, b, c; + gdouble d; + + u = MAX (u, 0.0); + v = MAX (v, 0.0); + + du = v_to_u (v) - u; + dv = u_to_v (u) - v; + + t = SQR (du) / (SQR (du) + SQR (dv)); + + du *= 1.0 - t; + dv *= t; + + v *= rx / ry; + dv *= rx / ry; + + a = SQR (du) + SQR (dv); + b = u * du + v * dv; + c = SQR (u) + SQR (v) - SQR (rx); + + if (a <= EPSILON) + return 0.0; + + if (c < 0.0) + t = (-b + sqrt (MAX (SQR (b) - a * c, 0.0))) / a; + else + t = (-b - sqrt (MAX (SQR (b) - a * c, 0.0))) / a; + + dv *= ry / rx; + + d = sqrt (SQR (du * t) + SQR (dv * t)); + + if (c > 0.0) + d = -d; + + d /= sqrt (SQR (MIN (du / dv, dv / du)) + 1.0); + + return d; + }; + + /* anti-aliased value of a pixel */ + auto pixel_value = [=] (gint x, + gint y) + { + gdouble u = x_to_u (x + 0.5); + gdouble v = y_to_v (y + 0.5); + gdouble d = ellipse_distance (u, v); + + /* use the distance of the pixel's center from the ellipse to approximate + * the coverage + */ + d = CLAMP (0.5 + d, 0.0, 1.0); + + /* we're at the horizontal boundary of an elliptic corner */ + if (u < 0.5) + d = d * (0.5 + u) + (0.5 - u); + + /* we're at the vertical boundary of an elliptic corner */ + if (v < 0.5) + d = d * (0.5 + v) + (0.5 - v); + + /* opposite horizontal corners intersect the pixel */ + if (x == (right - 1) - (x - left)) + d = 2.0 * d - 1.0; + + /* opposite vertical corners intersect the pixel */ + if (y == (bottom - 1) - (y - top)) + d = 2.0 * d - 1.0; + + return d; + }; + + auto ellipse_range = [=] (gdouble y, + gdouble *x0, + gdouble *x1) + { + gdouble u = v_to_u (y_to_v (y)); + + *x0 = u_to_x_left (u); + *x1 = u_to_x_right (u); + }; + + auto fill0 = [=] (gpointer dest, + gint n) + { + switch (op) + { + case GIMP_CHANNEL_OP_REPLACE: + case GIMP_CHANNEL_OP_INTERSECT: + memset (dest, 0, bpp * n); + break; + + case GIMP_CHANNEL_OP_ADD: + case GIMP_CHANNEL_OP_SUBTRACT: + break; + } + + return (gpointer) ((guint8 *) dest + bpp * n); + }; + + auto fill1 = [=] (gpointer dest, + gint n) + { + switch (op) + { + case GIMP_CHANNEL_OP_REPLACE: + case GIMP_CHANNEL_OP_ADD: + gegl_memset_pattern (dest, one, bpp, n); + break; + + case GIMP_CHANNEL_OP_SUBTRACT: + memset (dest, 0, bpp * n); + break; + + case GIMP_CHANNEL_OP_INTERSECT: + break; + } + + return (gpointer) ((guint8 *) dest + bpp * n); + }; + + auto set = [=] (gpointer dest, + gfloat value) + { + gfloat *p = (gfloat *) dest; + + switch (op) + { + case GIMP_CHANNEL_OP_REPLACE: + *p = value; + break; + + case GIMP_CHANNEL_OP_ADD: + *p = MIN (*p + value, 1.0); + break; + + case GIMP_CHANNEL_OP_SUBTRACT: + *p = MAX (*p - value, 0.0); + break; + + case GIMP_CHANNEL_OP_INTERSECT: + *p = MIN (*p, value); + break; + } + + return (gpointer) (p + 1); + }; + + gegl_parallel_distribute_area ( + &rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *area) + { + GeglBufferIterator *iter; + + iter = gegl_buffer_iterator_new ( + mask, area, 0, format, + op == GIMP_CHANNEL_OP_REPLACE ? GEGL_ACCESS_WRITE : + GEGL_ACCESS_READWRITE, + GEGL_ABYSS_NONE, 1); + + while (gegl_buffer_iterator_next (iter)) + { + const GeglRectangle *roi = &iter->items[0].roi; + gpointer d = iter->items[0].data; + gdouble tx0, ty0; + gdouble tx1, ty1; + gdouble x0; + gdouble x1; + gint y; + + /* tile bounds */ + tx0 = roi->x; + ty0 = roi->y; + + tx1 = roi->x + roi->width; + ty1 = roi->y + roi->height; + + if (! antialias) + { + tx0 += 0.5; + ty0 += 0.5; + + tx1 -= 0.5; + ty1 -= 0.5; + } + + /* if the tile is fully inside/outside the ellipse, fill it with 1/0, + * respectively, and skip the rest. + */ + ellipse_range (ty0, &x0, &x1); + + if (tx0 >= x0 && tx1 <= x1) + { + ellipse_range (ty1, &x0, &x1); + + if (tx0 >= x0 && tx1 <= x1) + { + fill1 (d, iter->length); + + continue; + } + } + else if (tx1 < x0 || tx0 > x1) + { + ellipse_range (ty1, &x0, &x1); + + if (tx1 < x0 || tx0 > x1) + { + if ((ty0 - cy) * (ty1 - cy) >= 0.0) + { + fill0 (d, iter->length); + + continue; + } + } + } + + for (y = roi->y; y < roi->y + roi->height; y++) + { + gint a, b; + + if (antialias) + { + gdouble v = y_to_v (y + 0.5); + gdouble u0 = v_to_u (v - 0.5); + gdouble u1 = v_to_u (v + 0.5); + gint x; + + a = floor (u_to_x_left (u0)) - roi->x; + a = CLAMP (a, 0, roi->width); + + b = ceil (u_to_x_left (u1)) - roi->x; + b = CLAMP (b, a, roi->width); + + d = fill0 (d, a); + + for (x = roi->x + a; x < roi->x + b; x++) + d = set (d, pixel_value (x, y)); + + a = floor (u_to_x_right (u1)) - roi->x; + a = CLAMP (a, b, roi->width); + + d = fill1 (d, a - b); + + b = ceil (u_to_x_right (u0)) - roi->x; + b = CLAMP (b, a, roi->width); + + for (x = roi->x + a; x < roi->x + b; x++) + d = set (d, pixel_value (x, y)); + + d = fill0 (d, roi->width - b); + } + else + { + ellipse_range (y + 0.5, &x0, &x1); + + a = ceil (x0 - 0.5) - roi->x; + a = CLAMP (a, 0, roi->width); + + b = floor (x1 + 0.5) - roi->x; + b = CLAMP (b, 0, roi->width); + + d = fill0 (d, a); + d = fill1 (d, b - a); + d = fill0 (d, roi->width - b); + } + } + } + }); + + return TRUE; +} + +gboolean +gimp_gegl_mask_combine_buffer (GeglBuffer *mask, + GeglBuffer *add_on, + GimpChannelOps op, + gint off_x, + gint off_y) +{ + GeglRectangle mask_rect; + GeglRectangle add_on_rect; + const Babl *mask_format; + const Babl *add_on_format; + + g_return_val_if_fail (GEGL_IS_BUFFER (mask), FALSE); + g_return_val_if_fail (GEGL_IS_BUFFER (add_on), FALSE); + + if (! gegl_rectangle_intersect (&mask_rect, + GEGL_RECTANGLE ( + off_x + gegl_buffer_get_x (add_on), + off_y + gegl_buffer_get_y (add_on), + gegl_buffer_get_width (add_on), + gegl_buffer_get_height (add_on)), + gegl_buffer_get_abyss (mask))) + { + return FALSE; + } + + add_on_rect = mask_rect; + add_on_rect.x -= off_x; + add_on_rect.y -= off_y; + + mask_format = gegl_buffer_get_format (mask); + add_on_format = gegl_buffer_get_format (add_on); + + if (op == GIMP_CHANNEL_OP_REPLACE && + (gimp_babl_is_bounded (gimp_babl_format_get_precision (add_on_format)) || + gimp_babl_is_bounded (gimp_babl_format_get_precision (mask_format)))) + { + /* See below: this additional hack is only needed for the + * gimp-channel-combine-masks procedure, it's the only place that + * allows to combine arbitrary channels with each other. + */ + gegl_buffer_set_format ( + add_on, + gimp_babl_format_change_linear ( + add_on_format, gimp_babl_format_get_linear (mask_format))); + + gimp_gegl_buffer_copy (add_on, &add_on_rect, GEGL_ABYSS_NONE, + mask, &mask_rect); + + gegl_buffer_set_format (add_on, NULL); + + return TRUE; + } + + /* This is a hack: all selections/layer masks/channels are always + * linear except for channels in 8-bit images. We don't want these + * "Y' u8" to be converted to "Y float" because that would cause a + * gamma canversion and give unexpected results for + * "add/subtract/etc channel from selection". Instead, use all + * channel values "as-is", which makes no differce except in the + * 8-bit case where we need it. + * + * See https://bugzilla.gnome.org/show_bug.cgi?id=791519 + */ + mask_format = gimp_babl_format_change_component_type ( + mask_format, GIMP_COMPONENT_TYPE_FLOAT); + + add_on_format = gimp_babl_format_change_component_type ( + add_on_format, GIMP_COMPONENT_TYPE_FLOAT); + + gegl_parallel_distribute_area ( + &mask_rect, PIXELS_PER_THREAD, + [=] (const GeglRectangle *mask_area) + { + GeglBufferIterator *iter; + GeglRectangle add_on_area; + + add_on_area = *mask_area; + add_on_area.x -= off_x; + add_on_area.y -= off_y; + + iter = gegl_buffer_iterator_new (mask, mask_area, 0, + mask_format, + op == GIMP_CHANNEL_OP_REPLACE ? + GEGL_ACCESS_WRITE : + GEGL_ACCESS_READWRITE, + GEGL_ABYSS_NONE, 2); + + gegl_buffer_iterator_add (iter, add_on, &add_on_area, 0, + add_on_format, + GEGL_ACCESS_READ, GEGL_ABYSS_NONE); + + auto process = [=] (auto value) + { + while (gegl_buffer_iterator_next (iter)) + { + gfloat *mask_data = (gfloat *) iter->items[0].data; + const gfloat *add_on_data = (const gfloat *) iter->items[1].data; + gint count = iter->length; + + while (count--) + { + const gfloat val = value (mask_data, add_on_data); + + *mask_data = CLAMP (val, 0.0f, 1.0f); + + add_on_data++; + mask_data++; + } + } + }; + + switch (op) + { + case GIMP_CHANNEL_OP_REPLACE: + process ([] (const gfloat *mask, + const gfloat *add_on) + { + return *add_on; + }); + break; + + case GIMP_CHANNEL_OP_ADD: + process ([] (const gfloat *mask, + const gfloat *add_on) + { + return *mask + *add_on; + }); + break; + + case GIMP_CHANNEL_OP_SUBTRACT: + process ([] (const gfloat *mask, + const gfloat *add_on) + { + return *mask - *add_on; + }); + break; + + case GIMP_CHANNEL_OP_INTERSECT: + process ([] (const gfloat *mask, + const gfloat *add_on) + { + return MIN (*mask, *add_on); + }); + break; + } + }); + + return TRUE; +} + +} /* extern "C" */ diff --git a/app/gegl/gimp-gegl-mask-combine.h b/app/gegl/gimp-gegl-mask-combine.h new file mode 100644 index 0000000..d8e0fa2 --- /dev/null +++ b/app/gegl/gimp-gegl-mask-combine.h @@ -0,0 +1,51 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_MASK_COMBINE_H__ +#define __GIMP_GEGL_MASK_COMBINE_H__ + + +gboolean gimp_gegl_mask_combine_rect (GeglBuffer *mask, + GimpChannelOps op, + gint x, + gint y, + gint w, + gint h); +gboolean gimp_gegl_mask_combine_ellipse (GeglBuffer *mask, + GimpChannelOps op, + gint x, + gint y, + gint w, + gint h, + gboolean antialias); +gboolean gimp_gegl_mask_combine_ellipse_rect (GeglBuffer *mask, + GimpChannelOps op, + gint x, + gint y, + gint w, + gint h, + gdouble rx, + gdouble ry, + gboolean antialias); +gboolean gimp_gegl_mask_combine_buffer (GeglBuffer *mask, + GeglBuffer *add_on, + GimpChannelOps op, + gint off_x, + gint off_y); + + +#endif /* __GIMP_GEGL_MASK_COMBINE_H__ */ diff --git a/app/gegl/gimp-gegl-mask.c b/app/gegl/gimp-gegl-mask.c new file mode 100644 index 0000000..325289c --- /dev/null +++ b/app/gegl/gimp-gegl-mask.c @@ -0,0 +1,253 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "gegl/gimp-gegl-mask.h" + + +gboolean +gimp_gegl_mask_bounds (GeglBuffer *buffer, + gint *x1, + gint *y1, + gint *x2, + gint *y2) +{ + GeglBufferIterator *iter; + const GeglRectangle *extent; + const GeglRectangle *roi; + const Babl *format; + gint bpp; + gint tx1, tx2, ty1, ty2; + + g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE); + g_return_val_if_fail (x1 != NULL, FALSE); + g_return_val_if_fail (y1 != NULL, FALSE); + g_return_val_if_fail (x2 != NULL, FALSE); + g_return_val_if_fail (y2 != NULL, FALSE); + + extent = gegl_buffer_get_extent (buffer); + + /* go through and calculate the bounds */ + tx1 = extent->x + extent->width; + ty1 = extent->y + extent->height; + tx2 = extent->x; + ty2 = extent->y; + + format = gegl_buffer_get_format (buffer); + bpp = babl_format_get_bytes_per_pixel (format); + + iter = gegl_buffer_iterator_new (buffer, NULL, 0, format, + GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1); + roi = &iter->items[0].roi; + + while (gegl_buffer_iterator_next (iter)) + { + const guint8 *data_u8 = iter->items[0].data; + gint ex = roi->x + roi->width; + gint ey = roi->y + roi->height; + + /* only check the pixels if this tile is not fully within the + * currently computed bounds + */ + if (roi->x < tx1 || ex > tx2 || + roi->y < ty1 || ey > ty2) + { + /* Check upper left and lower right corners to see if we can + * avoid checking the rest of the pixels in this tile + */ + if (! gegl_memeq_zero (data_u8, bpp) && + ! gegl_memeq_zero (data_u8 + (iter->length - 1) * bpp, bpp)) + { + /* "ex/ey - 1" because the internal variables are the + * right/bottom pixel of the mask's contents, not one + * right/below it like the return values. + */ + + if (roi->x < tx1) tx1 = roi->x; + if (ex > tx2) tx2 = ex - 1; + + if (roi->y < ty1) ty1 = roi->y; + if (ey > ty2) ty2 = ey - 1; + } + else + { + #define FIND_BOUNDS(bpp, type) \ + G_STMT_START \ + { \ + const type *data; \ + gint y; \ + \ + if ((guintptr) data_u8 % bpp) \ + goto generic; \ + \ + data = (const type *) data_u8; \ + \ + for (y = roi->y; y < ey; y++) \ + { \ + gint x1; \ + \ + for (x1 = 0; x1 < roi->width; x1++) \ + { \ + if (data[x1]) \ + { \ + gint x2; \ + gint x2_end = MAX (x1, tx2 - roi->x); \ + \ + for (x2 = roi->width - 1; x2 > x2_end; x2--) \ + { \ + if (data[x2]) \ + break; \ + } \ + \ + x1 += roi->x; \ + x2 += roi->x; \ + \ + if (x1 < tx1) tx1 = x1; \ + if (x2 > tx2) tx2 = x2; \ + \ + if (y < ty1) ty1 = y; \ + if (y > ty2) ty2 = y; \ + \ + break; \ + } \ + } \ + \ + data += roi->width; \ + } \ + } \ + G_STMT_END + + switch (bpp) + { + case 1: + FIND_BOUNDS (1, guint8); + break; + + case 2: + FIND_BOUNDS (2, guint16); + break; + + case 4: + FIND_BOUNDS (4, guint32); + break; + + case 8: + FIND_BOUNDS (8, guint64); + break; + + default: + generic: + { + const guint8 *data = data_u8; + gint y; + + for (y = roi->y; y < ey; y++) + { + gint x1; + + for (x1 = 0; x1 < roi->width; x1++) + { + if (! gegl_memeq_zero (data + x1 * bpp, bpp)) + { + gint x2; + gint x2_end = MAX (x1, tx2 - roi->x); + + for (x2 = roi->width - 1; x2 > x2_end; x2--) + { + if (! gegl_memeq_zero (data + x2 * bpp, + bpp)) + { + break; + } + } + + x1 += roi->x; + x2 += roi->x; + + if (x1 < tx1) tx1 = x1; + if (x2 > tx2) tx2 = x2; + + if (y < ty1) ty1 = y; + if (y > ty2) ty2 = y; + } + } + + data += roi->width * bpp; + } + } + break; + } + + #undef FIND_BOUNDS + } + } + } + + tx2 = CLAMP (tx2 + 1, 0, gegl_buffer_get_width (buffer)); + ty2 = CLAMP (ty2 + 1, 0, gegl_buffer_get_height (buffer)); + + if (tx1 == gegl_buffer_get_width (buffer) && + ty1 == gegl_buffer_get_height (buffer)) + { + *x1 = 0; + *y1 = 0; + *x2 = gegl_buffer_get_width (buffer); + *y2 = gegl_buffer_get_height (buffer); + + return FALSE; + } + + *x1 = tx1; + *y1 = ty1; + *x2 = tx2; + *y2 = ty2; + + return TRUE; +} + +gboolean +gimp_gegl_mask_is_empty (GeglBuffer *buffer) +{ + GeglBufferIterator *iter; + const Babl *format; + gint bpp; + + g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE); + + format = gegl_buffer_get_format (buffer); + bpp = babl_format_get_bytes_per_pixel (format); + + iter = gegl_buffer_iterator_new (buffer, NULL, 0, format, + GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1); + + while (gegl_buffer_iterator_next (iter)) + { + if (! gegl_memeq_zero (iter->items[0].data, bpp * iter->length)) + { + gegl_buffer_iterator_stop (iter); + + return FALSE; + } + } + + return TRUE; +} diff --git a/app/gegl/gimp-gegl-mask.h b/app/gegl/gimp-gegl-mask.h new file mode 100644 index 0000000..e14d838 --- /dev/null +++ b/app/gegl/gimp-gegl-mask.h @@ -0,0 +1,30 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_MASK_H__ +#define __GIMP_GEGL_MASK_H__ + + +gboolean gimp_gegl_mask_bounds (GeglBuffer *buffer, + gint *x1, + gint *y1, + gint *x2, + gint *y2); +gboolean gimp_gegl_mask_is_empty (GeglBuffer *buffer); + + +#endif /* __GIMP_GEGL_MASK_H__ */ diff --git a/app/gegl/gimp-gegl-nodes.c b/app/gegl/gimp-gegl-nodes.c new file mode 100644 index 0000000..5067da2 --- /dev/null +++ b/app/gegl/gimp-gegl-nodes.c @@ -0,0 +1,260 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-nodes.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "operations/layer-modes/gimp-layer-modes.h" + +#include "gimp-gegl-nodes.h" +#include "gimp-gegl-utils.h" + + +GeglNode * +gimp_gegl_create_flatten_node (const GimpRGB *background, + GimpLayerColorSpace composite_space) +{ + GeglNode *node; + GeglNode *input; + GeglNode *output; + GeglNode *color; + GeglNode *mode; + GeglColor *c; + + g_return_val_if_fail (background != NULL, NULL); + g_return_val_if_fail (composite_space == GIMP_LAYER_COLOR_SPACE_RGB_LINEAR || + composite_space == GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + NULL); + + node = gegl_node_new (); + + input = gegl_node_get_input_proxy (node, "input"); + output = gegl_node_get_output_proxy (node, "output"); + + c = gimp_gegl_color_new (background); + color = gegl_node_new_child (node, + "operation", "gegl:color", + "value", c, + "format", gimp_layer_mode_get_format ( + GIMP_LAYER_MODE_NORMAL, + GIMP_LAYER_COLOR_SPACE_AUTO, + composite_space, + GIMP_LAYER_COMPOSITE_AUTO, + NULL), + NULL); + g_object_unref (c); + + gimp_gegl_node_set_underlying_operation (node, color); + + mode = gegl_node_new_child (node, + "operation", "gimp:normal", + NULL); + gimp_gegl_mode_node_set_mode (mode, + GIMP_LAYER_MODE_NORMAL, + GIMP_LAYER_COLOR_SPACE_AUTO, + composite_space, + GIMP_LAYER_COMPOSITE_AUTO); + + gegl_node_connect_to (input, "output", + mode, "aux"); + gegl_node_connect_to (color, "output", + mode, "input"); + gegl_node_connect_to (mode, "output", + output, "input"); + + return node; +} + +GeglNode * +gimp_gegl_create_apply_opacity_node (GeglBuffer *mask, + gint mask_offset_x, + gint mask_offset_y, + gdouble opacity) +{ + GeglNode *node; + GeglNode *input; + GeglNode *output; + GeglNode *opacity_node; + GeglNode *mask_source; + + g_return_val_if_fail (GEGL_IS_BUFFER (mask), NULL); + + node = gegl_node_new (); + + input = gegl_node_get_input_proxy (node, "input"); + output = gegl_node_get_output_proxy (node, "output"); + + opacity_node = gegl_node_new_child (node, + "operation", "gegl:opacity", + "value", opacity, + NULL); + + gimp_gegl_node_set_underlying_operation (node, opacity_node); + + mask_source = gimp_gegl_add_buffer_source (node, mask, + mask_offset_x, + mask_offset_y); + + gegl_node_connect_to (input, "output", + opacity_node, "input"); + gegl_node_connect_to (mask_source, "output", + opacity_node, "aux"); + gegl_node_connect_to (opacity_node, "output", + output, "input"); + + return node; +} + +GeglNode * +gimp_gegl_create_transform_node (const GimpMatrix3 *matrix) +{ + GeglNode *node; + + g_return_val_if_fail (matrix != NULL, NULL); + + node = gegl_node_new_child (NULL, + "operation", "gegl:transform", + NULL); + + gimp_gegl_node_set_matrix (node, matrix); + + return node; +} + +GeglNode * +gimp_gegl_add_buffer_source (GeglNode *parent, + GeglBuffer *buffer, + gint offset_x, + gint offset_y) +{ + GeglNode *buffer_source; + + g_return_val_if_fail (GEGL_IS_NODE (parent), NULL); + g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL); + + buffer_source = gegl_node_new_child (parent, + "operation", "gegl:buffer-source", + "buffer", buffer, + NULL); + + if (offset_x != 0 || offset_y != 0) + { + GeglNode *translate = + gegl_node_new_child (parent, + "operation", "gegl:translate", + "x", (gdouble) offset_x, + "y", (gdouble) offset_y, + NULL); + + gegl_node_connect_to (buffer_source, "output", + translate, "input"); + + buffer_source = translate; + } + + return buffer_source; +} + +void +gimp_gegl_mode_node_set_mode (GeglNode *node, + GimpLayerMode mode, + GimpLayerColorSpace blend_space, + GimpLayerColorSpace composite_space, + GimpLayerCompositeMode composite_mode) +{ + gdouble opacity; + + g_return_if_fail (GEGL_IS_NODE (node)); + + if (blend_space == GIMP_LAYER_COLOR_SPACE_AUTO) + blend_space = gimp_layer_mode_get_blend_space (mode); + + if (composite_space == GIMP_LAYER_COLOR_SPACE_AUTO) + composite_space = gimp_layer_mode_get_composite_space (mode); + + if (composite_mode == GIMP_LAYER_COMPOSITE_AUTO) + composite_mode = gimp_layer_mode_get_composite_mode (mode); + + gegl_node_get (node, + "opacity", &opacity, + NULL); + + /* setting the operation creates a new instance, so we have to set + * all its properties + */ + gegl_node_set (node, + "operation", gimp_layer_mode_get_operation (mode), + "layer-mode", mode, + "opacity", opacity, + "blend-space", blend_space, + "composite-space", composite_space, + "composite-mode", composite_mode, + NULL); +} + +void +gimp_gegl_mode_node_set_opacity (GeglNode *node, + gdouble opacity) +{ + g_return_if_fail (GEGL_IS_NODE (node)); + + gegl_node_set (node, + "opacity", opacity, + NULL); +} + +void +gimp_gegl_node_set_matrix (GeglNode *node, + const GimpMatrix3 *matrix) +{ + gchar *matrix_string; + + g_return_if_fail (GEGL_IS_NODE (node)); + g_return_if_fail (matrix != NULL); + + matrix_string = gegl_matrix3_to_string ((GeglMatrix3 *) matrix); + + gegl_node_set (node, + "transform", matrix_string, + NULL); + + g_free (matrix_string); +} + +void +gimp_gegl_node_set_color (GeglNode *node, + const GimpRGB *color) +{ + GeglColor *gegl_color; + + g_return_if_fail (GEGL_IS_NODE (node)); + g_return_if_fail (color != NULL); + + gegl_color = gimp_gegl_color_new (color); + + gegl_node_set (node, + "value", gegl_color, + NULL); + + g_object_unref (gegl_color); +} diff --git a/app/gegl/gimp-gegl-nodes.h b/app/gegl/gimp-gegl-nodes.h new file mode 100644 index 0000000..0f627ff --- /dev/null +++ b/app/gegl/gimp-gegl-nodes.h @@ -0,0 +1,52 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-nodes.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_NODES_H__ +#define __GIMP_GEGL_NODES_H__ + + +GeglNode * gimp_gegl_create_flatten_node (const GimpRGB *background, + GimpLayerColorSpace composite_space); +GeglNode * gimp_gegl_create_apply_opacity_node (GeglBuffer *mask, + gint mask_offset_x, + gint mask_offset_y, + gdouble opacity); +GeglNode * gimp_gegl_create_transform_node (const GimpMatrix3 *matrix); + +GeglNode * gimp_gegl_add_buffer_source (GeglNode *parent, + GeglBuffer *buffer, + gint offset_x, + gint offset_y); + +void gimp_gegl_mode_node_set_mode (GeglNode *node, + GimpLayerMode mode, + GimpLayerColorSpace blend_space, + GimpLayerColorSpace composite_space, + GimpLayerCompositeMode composite_mode); +void gimp_gegl_mode_node_set_opacity (GeglNode *node, + gdouble opacity); + +void gimp_gegl_node_set_matrix (GeglNode *node, + const GimpMatrix3 *matrix); +void gimp_gegl_node_set_color (GeglNode *node, + const GimpRGB *color); + + +#endif /* __GIMP_GEGL_NODES_H__ */ diff --git a/app/gegl/gimp-gegl-tile-compat.c b/app/gegl/gimp-gegl-tile-compat.c new file mode 100644 index 0000000..54d917c --- /dev/null +++ b/app/gegl/gimp-gegl-tile-compat.c @@ -0,0 +1,79 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-tile-compat.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "gimp-gegl-tile-compat.h" + + +gint +gimp_gegl_buffer_get_n_tile_rows (GeglBuffer *buffer, + gint tile_height) +{ + return (gegl_buffer_get_height (buffer) + tile_height - 1) / tile_height; +} + +gint +gimp_gegl_buffer_get_n_tile_cols (GeglBuffer *buffer, + gint tile_width) +{ + return (gegl_buffer_get_width (buffer) + tile_width - 1) / tile_width; +} + +gboolean +gimp_gegl_buffer_get_tile_rect (GeglBuffer *buffer, + gint tile_width, + gint tile_height, + gint tile_num, + GeglRectangle *rect) +{ + gint n_tile_rows; + gint n_tile_columns; + gint tile_row; + gint tile_column; + + n_tile_rows = gimp_gegl_buffer_get_n_tile_rows (buffer, tile_height); + n_tile_columns = gimp_gegl_buffer_get_n_tile_cols (buffer, tile_width); + + if (tile_num > n_tile_rows * n_tile_columns - 1) + return FALSE; + + tile_row = tile_num / n_tile_columns; + tile_column = tile_num % n_tile_columns; + + rect->x = tile_column * tile_width; + rect->y = tile_row * tile_height; + + if (tile_column == n_tile_columns - 1) + rect->width = gegl_buffer_get_width (buffer) - rect->x; + else + rect->width = tile_width; + + if (tile_row == n_tile_rows - 1) + rect->height = gegl_buffer_get_height (buffer) - rect->y; + else + rect->height = tile_height; + + return TRUE; +} diff --git a/app/gegl/gimp-gegl-tile-compat.h b/app/gegl/gimp-gegl-tile-compat.h new file mode 100644 index 0000000..e35f288 --- /dev/null +++ b/app/gegl/gimp-gegl-tile-compat.h @@ -0,0 +1,36 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-tile-compat.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_TILE_COMPAT_H__ +#define __GIMP_GEGL_TILE_COMPAT_H__ + + +gint gimp_gegl_buffer_get_n_tile_rows (GeglBuffer *buffer, + gint tile_height); +gint gimp_gegl_buffer_get_n_tile_cols (GeglBuffer *buffer, + gint tile_width); +gboolean gimp_gegl_buffer_get_tile_rect (GeglBuffer *buffer, + gint tile_width, + gint tile_height, + gint tile_num, + GeglRectangle *rect); + + +#endif /* __GIMP_GEGL_TILE_COMPAT_H__ */ diff --git a/app/gegl/gimp-gegl-types.h b/app/gegl/gimp-gegl-types.h new file mode 100644 index 0000000..ecea87e --- /dev/null +++ b/app/gegl/gimp-gegl-types.h @@ -0,0 +1,34 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-types.h + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_TYPES_H__ +#define __GIMP_GEGL_TYPES_H__ + + +#include "core/core-types.h" + +#include "gegl/gimp-gegl-enums.h" + +#include "operations/operations-types.h" + + +typedef struct _GimpApplicator GimpApplicator; + + +#endif /* __GIMP_GEGL_TYPES_H__ */ diff --git a/app/gegl/gimp-gegl-utils.c b/app/gegl/gimp-gegl-utils.c new file mode 100644 index 0000000..efc3a1e --- /dev/null +++ b/app/gegl/gimp-gegl-utils.c @@ -0,0 +1,348 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-utils.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <gegl.h> +#include <gegl-plugin.h> + +#include "gimp-gegl-types.h" + +#include "core/gimpprogress.h" + +#include "gimp-gegl-loops.h" +#include "gimp-gegl-utils.h" + + +GType +gimp_gegl_get_op_enum_type (const gchar *operation, + const gchar *property) +{ + GeglNode *node; + GObject *op; + GParamSpec *pspec; + + g_return_val_if_fail (operation != NULL, G_TYPE_NONE); + g_return_val_if_fail (property != NULL, G_TYPE_NONE); + + node = g_object_new (GEGL_TYPE_NODE, + "operation", operation, + NULL); + g_object_get (node, "gegl-operation", &op, NULL); + g_object_unref (node); + + g_return_val_if_fail (op != NULL, G_TYPE_NONE); + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (op), property); + + g_return_val_if_fail (G_IS_PARAM_SPEC_ENUM (pspec), G_TYPE_NONE); + + g_object_unref (op); + + return G_TYPE_FROM_CLASS (G_PARAM_SPEC_ENUM (pspec)->enum_class); +} + +GeglColor * +gimp_gegl_color_new (const GimpRGB *rgb) +{ + GeglColor *color; + + g_return_val_if_fail (rgb != NULL, NULL); + + color = gegl_color_new (NULL); + gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb); + + return color; +} + +static void +gimp_gegl_progress_callback (GObject *object, + gdouble value, + GimpProgress *progress) +{ + if (value == 0.0) + { + const gchar *text = g_object_get_data (object, "gimp-progress-text"); + + if (gimp_progress_is_active (progress)) + gimp_progress_set_text (progress, "%s", text); + else + gimp_progress_start (progress, FALSE, "%s", text); + } + else + { + gimp_progress_set_value (progress, value); + + if (value == 1.0) + gimp_progress_end (progress); + } +} + +void +gimp_gegl_progress_connect (GeglNode *node, + GimpProgress *progress, + const gchar *text) +{ + g_return_if_fail (GEGL_IS_NODE (node)); + g_return_if_fail (GIMP_IS_PROGRESS (progress)); + g_return_if_fail (text != NULL); + + g_signal_connect (node, "progress", + G_CALLBACK (gimp_gegl_progress_callback), + progress); + + g_object_set_data_full (G_OBJECT (node), + "gimp-progress-text", g_strdup (text), + (GDestroyNotify) g_free); +} + +gboolean +gimp_gegl_node_is_source_operation (GeglNode *node) +{ + GeglOperation *operation; + + g_return_val_if_fail (GEGL_IS_NODE (node), FALSE); + + operation = gegl_node_get_gegl_operation (node); + + if (! operation) + return FALSE; + + return GEGL_IS_OPERATION_SOURCE (operation); +} + +gboolean +gimp_gegl_node_is_point_operation (GeglNode *node) +{ + GeglOperation *operation; + + g_return_val_if_fail (GEGL_IS_NODE (node), FALSE); + + operation = gegl_node_get_gegl_operation (node); + + if (! operation) + return FALSE; + + return GEGL_IS_OPERATION_POINT_RENDER (operation) || + GEGL_IS_OPERATION_POINT_FILTER (operation) || + GEGL_IS_OPERATION_POINT_COMPOSER (operation) || + GEGL_IS_OPERATION_POINT_COMPOSER3 (operation); +} + +gboolean +gimp_gegl_node_is_area_filter_operation (GeglNode *node) +{ + GeglOperation *operation; + + g_return_val_if_fail (GEGL_IS_NODE (node), FALSE); + + operation = gegl_node_get_gegl_operation (node); + + if (! operation) + return FALSE; + + return GEGL_IS_OPERATION_AREA_FILTER (operation) || + /* be conservative and return TRUE for meta ops, since they may + * involve an area op + */ + GEGL_IS_OPERATION_META (operation); +} + +const gchar * +gimp_gegl_node_get_key (GeglNode *node, + const gchar *key) +{ + const gchar *operation_name; + + g_return_val_if_fail (GEGL_IS_NODE (node), NULL); + + operation_name = gegl_node_get_operation (node); + + if (operation_name) + return gegl_operation_get_key (operation_name, key); + else + return NULL; +} + +gboolean +gimp_gegl_node_has_key (GeglNode *node, + const gchar *key) +{ + return gimp_gegl_node_get_key (node, key) != NULL; +} + +const Babl * +gimp_gegl_node_get_format (GeglNode *node, + const gchar *pad_name) +{ + GeglOperation *op; + const Babl *format = NULL; + + g_return_val_if_fail (GEGL_IS_NODE (node), NULL); + g_return_val_if_fail (pad_name != NULL, NULL); + + g_object_get (node, "gegl-operation", &op, NULL); + + if (op) + { + format = gegl_operation_get_format (op, pad_name); + + g_object_unref (op); + } + + if (! format) + format = babl_format ("RGBA float"); + + return format; +} + +void +gimp_gegl_node_set_underlying_operation (GeglNode *node, + GeglNode *operation) +{ + g_return_if_fail (GEGL_IS_NODE (node)); + g_return_if_fail (operation == NULL || GEGL_IS_NODE (operation)); + + g_object_set_data (G_OBJECT (node), + "gimp-gegl-node-underlying-operation", operation); +} + +GeglNode * +gimp_gegl_node_get_underlying_operation (GeglNode *node) +{ + GeglNode *operation; + + g_return_val_if_fail (GEGL_IS_NODE (node), NULL); + + operation = g_object_get_data (G_OBJECT (node), + "gimp-gegl-node-underlying-operation"); + + if (operation) + return gimp_gegl_node_get_underlying_operation (operation); + else + return node; +} + +gboolean +gimp_gegl_param_spec_has_key (GParamSpec *pspec, + const gchar *key, + const gchar *value) +{ + const gchar *v = gegl_param_spec_get_property_key (pspec, key); + + if (v && ! strcmp (v, value)) + return TRUE; + + return FALSE; +} + +GeglBuffer * +gimp_gegl_buffer_dup (GeglBuffer *buffer) +{ + GeglBuffer *new_buffer; + const GeglRectangle *extent; + const GeglRectangle *abyss; + GeglRectangle rect; + gint shift_x; + gint shift_y; + gint tile_width; + gint tile_height; + + g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL); + + extent = gegl_buffer_get_extent (buffer); + abyss = gegl_buffer_get_abyss (buffer); + + g_object_get (buffer, + "shift-x", &shift_x, + "shift-y", &shift_y, + "tile-width", &tile_width, + "tile-height", &tile_height, + NULL); + + new_buffer = g_object_new (GEGL_TYPE_BUFFER, + "format", gegl_buffer_get_format (buffer), + "x", extent->x, + "y", extent->y, + "width", extent->width, + "height", extent->height, + "abyss-x", abyss->x, + "abyss-y", abyss->y, + "abyss-width", abyss->width, + "abyss-height", abyss->height, + "shift-x", shift_x, + "shift-y", shift_y, + "tile-width", tile_width, + "tile-height", tile_height, + NULL); + + gegl_rectangle_align_to_buffer (&rect, extent, buffer, + GEGL_RECTANGLE_ALIGNMENT_SUPERSET); + + gimp_gegl_buffer_copy (buffer, &rect, GEGL_ABYSS_NONE, + new_buffer, &rect); + + return new_buffer; +} + +gboolean +gimp_gegl_buffer_set_extent (GeglBuffer *buffer, + const GeglRectangle *extent) +{ + GeglRectangle aligned_old_extent; + GeglRectangle aligned_extent; + GeglRectangle old_extent_rem; + GeglRectangle diff_rects[4]; + gint n_diff_rects; + gint i; + + g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE); + g_return_val_if_fail (extent != NULL, FALSE); + + gegl_rectangle_align_to_buffer (&aligned_old_extent, + gegl_buffer_get_extent (buffer), buffer, + GEGL_RECTANGLE_ALIGNMENT_SUPERSET); + gegl_rectangle_align_to_buffer (&aligned_extent, + extent, buffer, + GEGL_RECTANGLE_ALIGNMENT_SUPERSET); + + n_diff_rects = gegl_rectangle_subtract (diff_rects, + &aligned_old_extent, + &aligned_extent); + + for (i = 0; i < n_diff_rects; i++) + gegl_buffer_clear (buffer, &diff_rects[i]); + + if (gegl_rectangle_intersect (&old_extent_rem, + gegl_buffer_get_extent (buffer), + &aligned_extent)) + { + n_diff_rects = gegl_rectangle_subtract (diff_rects, + &old_extent_rem, + extent); + + for (i = 0; i < n_diff_rects; i++) + gegl_buffer_clear (buffer, &diff_rects[i]); + } + + return gegl_buffer_set_extent (buffer, extent); +} diff --git a/app/gegl/gimp-gegl-utils.h b/app/gegl/gimp-gegl-utils.h new file mode 100644 index 0000000..cee725f --- /dev/null +++ b/app/gegl/gimp-gegl-utils.h @@ -0,0 +1,60 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl-utils.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_UTILS_H__ +#define __GIMP_GEGL_UTILS_H__ + + +GType gimp_gegl_get_op_enum_type (const gchar *operation, + const gchar *property); + +GeglColor * gimp_gegl_color_new (const GimpRGB *rgb); + +void gimp_gegl_progress_connect (GeglNode *node, + GimpProgress *progress, + const gchar *text); + +gboolean gimp_gegl_node_is_source_operation (GeglNode *node); +gboolean gimp_gegl_node_is_point_operation (GeglNode *node); +gboolean gimp_gegl_node_is_area_filter_operation (GeglNode *node); + +const gchar * gimp_gegl_node_get_key (GeglNode *node, + const gchar *key); +gboolean gimp_gegl_node_has_key (GeglNode *node, + const gchar *key); + +const Babl * gimp_gegl_node_get_format (GeglNode *node, + const gchar *pad_name); + +void gimp_gegl_node_set_underlying_operation (GeglNode *node, + GeglNode *operation); +GeglNode * gimp_gegl_node_get_underlying_operation (GeglNode *node); + +gboolean gimp_gegl_param_spec_has_key (GParamSpec *pspec, + const gchar *key, + const gchar *value); + +GeglBuffer * gimp_gegl_buffer_dup (GeglBuffer *buffer); + +gboolean gimp_gegl_buffer_set_extent (GeglBuffer *buffer, + const GeglRectangle *extent); + + +#endif /* __GIMP_GEGL_UTILS_H__ */ diff --git a/app/gegl/gimp-gegl.c b/app/gegl/gimp-gegl.c new file mode 100644 index 0000000..64046b6 --- /dev/null +++ b/app/gegl/gimp-gegl.c @@ -0,0 +1,171 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl.c + * Copyright (C) 2007 Øyvind KolÃ¥s <pippin@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gegl.h> + +#include "libgimpconfig/gimpconfig.h" + +#include "gimp-gegl-types.h" + +#include "config/gimpgeglconfig.h" + +#include "operations/gimp-operations.h" + +#include "core/gimp.h" +#include "core/gimp-parallel.h" + +#include "gimp-babl.h" +#include "gimp-gegl.h" + +#include <operation/gegl-operation.h> + + +static void gimp_gegl_notify_temp_path (GimpGeglConfig *config); +static void gimp_gegl_notify_swap_path (GimpGeglConfig *config); +static void gimp_gegl_notify_swap_compression (GimpGeglConfig *config); +static void gimp_gegl_notify_tile_cache_size (GimpGeglConfig *config); +static void gimp_gegl_notify_num_processors (GimpGeglConfig *config); +static void gimp_gegl_notify_use_opencl (GimpGeglConfig *config); + + +/* public functions */ + +void +gimp_gegl_init (Gimp *gimp) +{ + GimpGeglConfig *config; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + config = GIMP_GEGL_CONFIG (gimp->config); + + /* make sure temp and swap directories exist */ + gimp_gegl_notify_temp_path (config); + gimp_gegl_notify_swap_path (config); + + g_object_set (gegl_config (), + "swap-compression", config->swap_compression, + "tile-cache-size", (guint64) config->tile_cache_size, + "threads", config->num_processors, + "use-opencl", config->use_opencl, + NULL); + + gimp_parallel_init (gimp); + + g_signal_connect (config, "notify::temp-path", + G_CALLBACK (gimp_gegl_notify_temp_path), + NULL); + g_signal_connect (config, "notify::swap-path", + G_CALLBACK (gimp_gegl_notify_swap_path), + NULL); + g_signal_connect (config, "notify::swap-compression", + G_CALLBACK (gimp_gegl_notify_swap_compression), + NULL); + g_signal_connect (config, "notify::num-processors", + G_CALLBACK (gimp_gegl_notify_num_processors), + NULL); + g_signal_connect (config, "notify::tile-cache-size", + G_CALLBACK (gimp_gegl_notify_tile_cache_size), + NULL); + g_signal_connect (config, "notify::num-processors", + G_CALLBACK (gimp_gegl_notify_num_processors), + NULL); + g_signal_connect (config, "notify::use-opencl", + G_CALLBACK (gimp_gegl_notify_use_opencl), + NULL); + + gimp_babl_init (); + + gimp_operations_init (gimp); +} + +void +gimp_gegl_exit (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + gimp_parallel_exit (gimp); +} + + +/* private functions */ + +static void +gimp_gegl_notify_temp_path (GimpGeglConfig *config) +{ + GFile *file = gimp_file_new_for_config_path (config->temp_path, NULL); + + if (! g_file_query_exists (file, NULL)) + g_file_make_directory_with_parents (file, NULL, NULL); + + g_object_unref (file); +} + +static void +gimp_gegl_notify_swap_path (GimpGeglConfig *config) +{ + GFile *file = gimp_file_new_for_config_path (config->swap_path, NULL); + gchar *path = g_file_get_path (file); + + if (! g_file_query_exists (file, NULL)) + g_file_make_directory_with_parents (file, NULL, NULL); + + g_object_set (gegl_config (), + "swap", path, + NULL); + + g_free (path); + g_object_unref (file); +} + +static void +gimp_gegl_notify_swap_compression (GimpGeglConfig *config) +{ + g_object_set (gegl_config (), + "swap-compression", config->swap_compression, + NULL); +} + +static void +gimp_gegl_notify_tile_cache_size (GimpGeglConfig *config) +{ + g_object_set (gegl_config (), + "tile-cache-size", (guint64) config->tile_cache_size, + NULL); +} + +static void +gimp_gegl_notify_num_processors (GimpGeglConfig *config) +{ + g_object_set (gegl_config (), + "threads", config->num_processors, + NULL); +} + +static void +gimp_gegl_notify_use_opencl (GimpGeglConfig *config) +{ + g_object_set (gegl_config (), + "use-opencl", config->use_opencl, + NULL); +} diff --git a/app/gegl/gimp-gegl.h b/app/gegl/gimp-gegl.h new file mode 100644 index 0000000..a8e12c2 --- /dev/null +++ b/app/gegl/gimp-gegl.h @@ -0,0 +1,29 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-gegl.h + * Copyright (C) 2007 Øyvind KolÃ¥s <pippin@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_GEGL_H__ +#define __GIMP_GEGL_H__ + + +void gimp_gegl_init (Gimp *gimp); +void gimp_gegl_exit (Gimp *gimp); + + +#endif /* __GIMP_GEGL_H__ */ diff --git a/app/gegl/gimpapplicator.c b/app/gegl/gimpapplicator.c new file mode 100644 index 0000000..ac8c2db --- /dev/null +++ b/app/gegl/gimpapplicator.c @@ -0,0 +1,652 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpapplicator.c + * Copyright (C) 2012-2013 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "gimp-gegl-nodes.h" +#include "gimpapplicator.h" + + +static void gimp_applicator_finalize (GObject *object); +static void gimp_applicator_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_applicator_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + + +G_DEFINE_TYPE (GimpApplicator, gimp_applicator, G_TYPE_OBJECT) + +#define parent_class gimp_applicator_parent_class + + +static void +gimp_applicator_class_init (GimpApplicatorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gimp_applicator_finalize; + object_class->set_property = gimp_applicator_set_property; + object_class->get_property = gimp_applicator_get_property; +} + +static void +gimp_applicator_init (GimpApplicator *applicator) +{ + applicator->active = TRUE; + applicator->opacity = 1.0; + applicator->paint_mode = GIMP_LAYER_MODE_NORMAL; + applicator->blend_space = GIMP_LAYER_COLOR_SPACE_AUTO; + applicator->composite_space = GIMP_LAYER_COLOR_SPACE_AUTO; + applicator->composite_mode = GIMP_LAYER_COMPOSITE_AUTO; + applicator->affect = GIMP_COMPONENT_MASK_ALL; +} + +static void +gimp_applicator_finalize (GObject *object) +{ + GimpApplicator *applicator = GIMP_APPLICATOR (object); + + g_clear_object (&applicator->node); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_applicator_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_applicator_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +GimpApplicator * +gimp_applicator_new (GeglNode *parent) +{ + GimpApplicator *applicator; + + g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL); + + applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL); + + if (parent) + applicator->node = g_object_ref (parent); + else + applicator->node = gegl_node_new (); + + applicator->input_node = + gegl_node_get_input_proxy (applicator->node, "input"); + + applicator->aux_node = + gegl_node_get_input_proxy (applicator->node, "aux"); + + applicator->output_node = + gegl_node_get_output_proxy (applicator->node, "output"); + + applicator->mode_node = gegl_node_new_child (applicator->node, + "operation", "gimp:normal", + NULL); + + gimp_gegl_mode_node_set_mode (applicator->mode_node, + applicator->paint_mode, + applicator->blend_space, + applicator->composite_space, + applicator->composite_mode); + gimp_gegl_mode_node_set_opacity (applicator->mode_node, + applicator->opacity); + + gegl_node_connect_to (applicator->input_node, "output", + applicator->mode_node, "input"); + + applicator->apply_offset_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:translate", + NULL); + + gegl_node_link_many (applicator->aux_node, + applicator->apply_offset_node, + NULL); + + gegl_node_connect_to (applicator->apply_offset_node, "output", + applicator->mode_node, "aux"); + + applicator->mask_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:buffer-source", + NULL); + + applicator->mask_offset_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:translate", + NULL); + + gegl_node_connect_to (applicator->mask_node, "output", + applicator->mask_offset_node, "input"); + /* don't connect the the mask offset node to mode's aux2 yet */ + + applicator->affect_node = + gegl_node_new_child (applicator->node, + "operation", "gimp:mask-components", + "mask", applicator->affect, + NULL); + + applicator->convert_format_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:nop", + NULL); + + applicator->cache_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:nop", + NULL); + + applicator->crop_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:nop", + NULL); + + gegl_node_link_many (applicator->input_node, + applicator->affect_node, + applicator->convert_format_node, + applicator->cache_node, + applicator->crop_node, + applicator->output_node, + NULL); + + gegl_node_connect_to (applicator->mode_node, "output", + applicator->affect_node, "aux"); + + return applicator; +} + +void +gimp_applicator_set_active (GimpApplicator *applicator, + gboolean active) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (active != applicator->active) + { + applicator->active = active; + + if (active) + gegl_node_link (applicator->crop_node, applicator->output_node); + else + gegl_node_link (applicator->input_node, applicator->output_node); + } +} + +void +gimp_applicator_set_src_buffer (GimpApplicator *applicator, + GeglBuffer *src_buffer) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + g_return_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer)); + + if (src_buffer == applicator->src_buffer) + return; + + if (src_buffer) + { + if (! applicator->src_node) + { + applicator->src_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:buffer-source", + "buffer", src_buffer, + NULL); + } + else + { + gegl_node_set (applicator->src_node, + "buffer", src_buffer, + NULL); + } + + if (! applicator->src_buffer) + gegl_node_link (applicator->src_node, applicator->input_node); + } + else if (applicator->src_buffer) + { + gegl_node_disconnect (applicator->input_node, "input"); + + gegl_node_set (applicator->src_node, + "buffer", NULL, + NULL); + } + + applicator->src_buffer = src_buffer; +} + +void +gimp_applicator_set_dest_buffer (GimpApplicator *applicator, + GeglBuffer *dest_buffer) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + g_return_if_fail (dest_buffer == NULL || GEGL_IS_BUFFER (dest_buffer)); + + if (dest_buffer == applicator->dest_buffer) + return; + + if (dest_buffer) + { + if (! applicator->dest_node) + { + applicator->dest_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:write-buffer", + "buffer", dest_buffer, + NULL); + } + else + { + gegl_node_set (applicator->dest_node, + "buffer", dest_buffer, + NULL); + } + + if (! applicator->dest_buffer) + gegl_node_link (applicator->affect_node, applicator->dest_node); + } + else if (applicator->dest_buffer) + { + gegl_node_disconnect (applicator->dest_node, "input"); + + gegl_node_set (applicator->dest_node, + "buffer", NULL, + NULL); + } + + applicator->dest_buffer = dest_buffer; +} + +void +gimp_applicator_set_mask_buffer (GimpApplicator *applicator, + GeglBuffer *mask_buffer) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + g_return_if_fail (mask_buffer == NULL || GEGL_IS_BUFFER (mask_buffer)); + + if (applicator->mask_buffer == mask_buffer) + return; + + gegl_node_set (applicator->mask_node, + "buffer", mask_buffer, + NULL); + + if (mask_buffer) + { + gegl_node_connect_to (applicator->mask_offset_node, "output", + applicator->mode_node, "aux2"); + } + else + { + gegl_node_disconnect (applicator->mode_node, "aux2"); + } + + applicator->mask_buffer = mask_buffer; +} + +void +gimp_applicator_set_mask_offset (GimpApplicator *applicator, + gint mask_offset_x, + gint mask_offset_y) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->mask_offset_x != mask_offset_x || + applicator->mask_offset_y != mask_offset_y) + { + applicator->mask_offset_x = mask_offset_x; + applicator->mask_offset_y = mask_offset_y; + + gegl_node_set (applicator->mask_offset_node, + "x", (gdouble) mask_offset_x, + "y", (gdouble) mask_offset_y, + NULL); + } +} + +void +gimp_applicator_set_apply_buffer (GimpApplicator *applicator, + GeglBuffer *apply_buffer) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + g_return_if_fail (apply_buffer == NULL || GEGL_IS_BUFFER (apply_buffer)); + + if (apply_buffer == applicator->apply_buffer) + return; + + if (apply_buffer) + { + if (! applicator->apply_src_node) + { + applicator->apply_src_node = + gegl_node_new_child (applicator->node, + "operation", "gegl:buffer-source", + "buffer", apply_buffer, + NULL); + } + else + { + gegl_node_set (applicator->apply_src_node, + "buffer", apply_buffer, + NULL); + } + + if (! applicator->apply_buffer) + { + gegl_node_connect_to (applicator->apply_src_node, "output", + applicator->apply_offset_node, "input"); + } + } + else if (applicator->apply_buffer) + { + gegl_node_connect_to (applicator->aux_node, "output", + applicator->apply_offset_node, "input"); + } + + applicator->apply_buffer = apply_buffer; +} + +void +gimp_applicator_set_apply_offset (GimpApplicator *applicator, + gint apply_offset_x, + gint apply_offset_y) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->apply_offset_x != apply_offset_x || + applicator->apply_offset_y != apply_offset_y) + { + applicator->apply_offset_x = apply_offset_x; + applicator->apply_offset_y = apply_offset_y; + + gegl_node_set (applicator->apply_offset_node, + "x", (gdouble) apply_offset_x, + "y", (gdouble) apply_offset_y, + NULL); + } +} + +void +gimp_applicator_set_opacity (GimpApplicator *applicator, + gdouble opacity) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->opacity != opacity) + { + applicator->opacity = opacity; + + gimp_gegl_mode_node_set_opacity (applicator->mode_node, + opacity); + } +} + +void +gimp_applicator_set_mode (GimpApplicator *applicator, + GimpLayerMode paint_mode, + GimpLayerColorSpace blend_space, + GimpLayerColorSpace composite_space, + GimpLayerCompositeMode composite_mode) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->paint_mode != paint_mode || + applicator->blend_space != blend_space || + applicator->composite_space != composite_space || + applicator->composite_mode != composite_mode) + { + applicator->paint_mode = paint_mode; + applicator->blend_space = blend_space; + applicator->composite_space = composite_space; + applicator->composite_mode = composite_mode; + + gimp_gegl_mode_node_set_mode (applicator->mode_node, + paint_mode, blend_space, + composite_space, composite_mode); + } +} + +void +gimp_applicator_set_affect (GimpApplicator *applicator, + GimpComponentMask affect) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->affect != affect) + { + applicator->affect = affect; + + gegl_node_set (applicator->affect_node, + "mask", affect, + NULL); + } +} + +void +gimp_applicator_set_output_format (GimpApplicator *applicator, + const Babl *format) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->output_format != format) + { + if (format) + { + if (! applicator->output_format) + { + gegl_node_set (applicator->convert_format_node, + "operation", "gegl:convert-format", + "format", format, + NULL); + } + else + { + gegl_node_set (applicator->convert_format_node, + "format", format, + NULL); + } + } + else + { + gegl_node_set (applicator->convert_format_node, + "operation", "gegl:nop", + NULL); + } + + applicator->output_format = format; + } +} + +const Babl * +gimp_applicator_get_output_format (GimpApplicator *applicator) +{ + g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), NULL); + + return applicator->output_format; +} + +void +gimp_applicator_set_cache (GimpApplicator *applicator, + gboolean enable) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->cache_enabled != enable) + { + if (enable) + { + gegl_node_set (applicator->cache_node, + "operation", "gegl:cache", + NULL); + } + else + { + gegl_node_set (applicator->cache_node, + "operation", "gegl:nop", + NULL); + } + + applicator->cache_enabled = enable; + } +} + +gboolean +gimp_applicator_get_cache (GimpApplicator *applicator) +{ + g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), FALSE); + + return applicator->cache_enabled; +} + +gboolean gegl_buffer_list_valid_rectangles (GeglBuffer *buffer, + GeglRectangle **rectangles, + gint *n_rectangles); + +GeglBuffer * +gimp_applicator_get_cache_buffer (GimpApplicator *applicator, + GeglRectangle **rectangles, + gint *n_rectangles) +{ + g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), NULL); + g_return_val_if_fail (rectangles != NULL, NULL); + g_return_val_if_fail (n_rectangles != NULL, NULL); + + if (applicator->cache_enabled) + { + GeglBuffer *cache; + + gegl_node_get (applicator->cache_node, + "cache", &cache, + NULL); + + if (cache) + { + if (gegl_buffer_list_valid_rectangles (cache, + rectangles, n_rectangles)) + { + return cache; + } + + g_object_unref (cache); + } + } + + return NULL; +} + +void +gimp_applicator_set_crop (GimpApplicator *applicator, + const GeglRectangle *rect) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + if (applicator->crop_enabled != (rect != NULL) || + (rect && ! gegl_rectangle_equal (&applicator->crop_rect, rect))) + { + if (rect) + { + if (! applicator->crop_enabled) + { + gegl_node_set (applicator->crop_node, + "operation", "gimp:compose-crop", + "x", rect->x, + "y", rect->y, + "width", rect->width, + "height", rect->height, + NULL); + + gegl_node_connect_to (applicator->input_node, "output", + applicator->crop_node, "aux"); + } + else + { + gegl_node_set (applicator->crop_node, + "x", rect->x, + "y", rect->y, + "width", rect->width, + "height", rect->height, + NULL); + } + + applicator->crop_enabled = TRUE; + applicator->crop_rect = *rect; + } + else + { + gegl_node_disconnect (applicator->crop_node, "aux"); + gegl_node_set (applicator->crop_node, + "operation", "gegl:nop", + NULL); + + applicator->crop_enabled = FALSE; + } + } +} + +const GeglRectangle * +gimp_applicator_get_crop (GimpApplicator *applicator) +{ + g_return_val_if_fail (GIMP_IS_APPLICATOR (applicator), NULL); + + if (applicator->crop_enabled) + return &applicator->crop_rect; + + return NULL; +} + +void +gimp_applicator_blit (GimpApplicator *applicator, + const GeglRectangle *rect) +{ + g_return_if_fail (GIMP_IS_APPLICATOR (applicator)); + + gegl_node_blit (applicator->dest_node, 1.0, rect, + NULL, NULL, 0, GEGL_BLIT_DEFAULT); +} diff --git a/app/gegl/gimpapplicator.h b/app/gegl/gimpapplicator.h new file mode 100644 index 0000000..e2919c2 --- /dev/null +++ b/app/gegl/gimpapplicator.h @@ -0,0 +1,146 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpapplicator.h + * Copyright (C) 2012-2013 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_APPLICATOR_H__ +#define __GIMP_APPLICATOR_H__ + + +#define GIMP_TYPE_APPLICATOR (gimp_applicator_get_type ()) +#define GIMP_APPLICATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_APPLICATOR, GimpApplicator)) +#define GIMP_APPLICATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_APPLICATOR, GimpApplicatorClass)) +#define GIMP_IS_APPLICATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_APPLICATOR)) +#define GIMP_IS_APPLICATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_APPLICATOR)) +#define GIMP_APPLICATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_APPLICATOR, GimpApplicatorClass)) + + +typedef struct _GimpApplicatorClass GimpApplicatorClass; + +struct _GimpApplicator +{ + GObject parent_instance; + + GeglNode *node; + GeglNode *input_node; + GeglNode *aux_node; + GeglNode *output_node; + + gboolean active; + + GeglBuffer *apply_buffer; + GeglNode *apply_src_node; + + gint apply_offset_x; + gint apply_offset_y; + GeglNode *apply_offset_node; + + gdouble opacity; + GimpLayerMode paint_mode; + GimpLayerColorSpace blend_space; + GimpLayerColorSpace composite_space; + GimpLayerCompositeMode composite_mode; + GeglNode *mode_node; + + GimpComponentMask affect; + GeglNode *affect_node; + + const Babl *output_format; + GeglNode *convert_format_node; + + gboolean cache_enabled; + GeglNode *cache_node; + + gboolean crop_enabled; + GeglRectangle crop_rect; + GeglNode *crop_node; + + GeglBuffer *src_buffer; + GeglNode *src_node; + + GeglBuffer *dest_buffer; + GeglNode *dest_node; + + GeglBuffer *mask_buffer; + GeglNode *mask_node; + + gint mask_offset_x; + gint mask_offset_y; + GeglNode *mask_offset_node; +}; + +struct _GimpApplicatorClass +{ + GObjectClass parent_class; +}; + + +GType gimp_applicator_get_type (void) G_GNUC_CONST; + +GimpApplicator * gimp_applicator_new (GeglNode *parent); + +void gimp_applicator_set_active (GimpApplicator *applicator, + gboolean active); + +void gimp_applicator_set_src_buffer (GimpApplicator *applicator, + GeglBuffer *dest_buffer); +void gimp_applicator_set_dest_buffer (GimpApplicator *applicator, + GeglBuffer *dest_buffer); + +void gimp_applicator_set_mask_buffer (GimpApplicator *applicator, + GeglBuffer *mask_buffer); +void gimp_applicator_set_mask_offset (GimpApplicator *applicator, + gint mask_offset_x, + gint mask_offset_y); + +void gimp_applicator_set_apply_buffer (GimpApplicator *applicator, + GeglBuffer *apply_buffer); +void gimp_applicator_set_apply_offset (GimpApplicator *applicator, + gint apply_offset_x, + gint apply_offset_y); + +void gimp_applicator_set_opacity (GimpApplicator *applicator, + gdouble opacity); +void gimp_applicator_set_mode (GimpApplicator *applicator, + GimpLayerMode paint_mode, + GimpLayerColorSpace blend_space, + GimpLayerColorSpace composite_space, + GimpLayerCompositeMode composite_mode); +void gimp_applicator_set_affect (GimpApplicator *applicator, + GimpComponentMask affect); + +void gimp_applicator_set_output_format (GimpApplicator *applicator, + const Babl *format); +const Babl * gimp_applicator_get_output_format (GimpApplicator *applicator); + +void gimp_applicator_set_cache (GimpApplicator *applicator, + gboolean enable); +gboolean gimp_applicator_get_cache (GimpApplicator *applicator); +GeglBuffer * gimp_applicator_get_cache_buffer (GimpApplicator *applicator, + GeglRectangle **rectangles, + gint *n_rectangles); + +void gimp_applicator_set_crop (GimpApplicator *applicator, + const GeglRectangle *rect); +const GeglRectangle * gimp_applicator_get_crop (GimpApplicator *applicator); + +void gimp_applicator_blit (GimpApplicator *applicator, + const GeglRectangle *rect); + + +#endif /* __GIMP_APPLICATOR_H__ */ diff --git a/app/gegl/gimptilehandlervalidate.c b/app/gegl/gimptilehandlervalidate.c new file mode 100644 index 0000000..01915d5 --- /dev/null +++ b/app/gegl/gimptilehandlervalidate.c @@ -0,0 +1,766 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> + +#include "gimp-gegl-types.h" + +#include "core/gimpchunkiterator.h" +#include "core/gimpmarshal.h" + +#include "gimp-gegl-loops.h" +#include "gimp-gegl-utils.h" +#include "gimptilehandlervalidate.h" + + +enum +{ + INVALIDATED, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_FORMAT, + PROP_TILE_WIDTH, + PROP_TILE_HEIGHT, + PROP_WHOLE_TILE +}; + + +static void gimp_tile_handler_validate_finalize (GObject *object); +static void gimp_tile_handler_validate_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_tile_handler_validate_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void gimp_tile_handler_validate_real_begin_validate (GimpTileHandlerValidate *validate); +static void gimp_tile_handler_validate_real_end_validate (GimpTileHandlerValidate *validate); +static void gimp_tile_handler_validate_real_validate (GimpTileHandlerValidate *validate, + const GeglRectangle *rect, + const Babl *format, + gpointer dest_buf, + gint dest_stride); +static void gimp_tile_handler_validate_real_validate_buffer (GimpTileHandlerValidate *validate, + const GeglRectangle *rect, + GeglBuffer *buffer); + +static gpointer gimp_tile_handler_validate_command (GeglTileSource *source, + GeglTileCommand command, + gint x, + gint y, + gint z, + gpointer data); + + +G_DEFINE_TYPE (GimpTileHandlerValidate, gimp_tile_handler_validate, + GEGL_TYPE_TILE_HANDLER) + +#define parent_class gimp_tile_handler_validate_parent_class + +static guint gimp_tile_handler_validate_signals[LAST_SIGNAL]; + + +static void +gimp_tile_handler_validate_class_init (GimpTileHandlerValidateClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + gimp_tile_handler_validate_signals[INVALIDATED] = + g_signal_new ("invalidated", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpTileHandlerValidateClass, invalidated), + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, + GEGL_TYPE_RECTANGLE); + + object_class->finalize = gimp_tile_handler_validate_finalize; + object_class->set_property = gimp_tile_handler_validate_set_property; + object_class->get_property = gimp_tile_handler_validate_get_property; + + klass->begin_validate = gimp_tile_handler_validate_real_begin_validate; + klass->end_validate = gimp_tile_handler_validate_real_end_validate; + klass->validate = gimp_tile_handler_validate_real_validate; + klass->validate_buffer = gimp_tile_handler_validate_real_validate_buffer; + + g_object_class_install_property (object_class, PROP_FORMAT, + g_param_spec_pointer ("format", NULL, NULL, + GIMP_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_TILE_WIDTH, + g_param_spec_int ("tile-width", NULL, NULL, + 1, G_MAXINT, 1, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_TILE_HEIGHT, + g_param_spec_int ("tile-height", NULL, NULL, + 1, G_MAXINT, 1, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_WHOLE_TILE, + g_param_spec_boolean ("whole-tile", NULL, NULL, + FALSE, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_tile_handler_validate_init (GimpTileHandlerValidate *validate) +{ + GeglTileSource *source = GEGL_TILE_SOURCE (validate); + + source->command = gimp_tile_handler_validate_command; + + validate->dirty_region = cairo_region_create (); +} + +static void +gimp_tile_handler_validate_finalize (GObject *object) +{ + GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (object); + + g_clear_object (&validate->graph); + g_clear_pointer (&validate->dirty_region, cairo_region_destroy); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_tile_handler_validate_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (object); + + switch (property_id) + { + case PROP_FORMAT: + validate->format = g_value_get_pointer (value); + break; + case PROP_TILE_WIDTH: + validate->tile_width = g_value_get_int (value); + break; + case PROP_TILE_HEIGHT: + validate->tile_height = g_value_get_int (value); + break; + case PROP_WHOLE_TILE: + validate->whole_tile = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_tile_handler_validate_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (object); + + switch (property_id) + { + case PROP_FORMAT: + g_value_set_pointer (value, (gpointer) validate->format); + break; + case PROP_TILE_WIDTH: + g_value_set_int (value, validate->tile_width); + break; + case PROP_TILE_HEIGHT: + g_value_set_int (value, validate->tile_height); + break; + case PROP_WHOLE_TILE: + g_value_set_boolean (value, validate->whole_tile); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_tile_handler_validate_real_begin_validate (GimpTileHandlerValidate *validate) +{ + validate->suspend_validate++; +} + +static void +gimp_tile_handler_validate_real_end_validate (GimpTileHandlerValidate *validate) +{ + validate->suspend_validate--; +} + +static void +gimp_tile_handler_validate_real_validate (GimpTileHandlerValidate *validate, + const GeglRectangle *rect, + const Babl *format, + gpointer dest_buf, + gint dest_stride) +{ +#if 0 + g_printerr ("validating at %d %d %d %d\n", + rect.x, + rect.y, + rect.width, + rect.height); +#endif + + gegl_node_blit (validate->graph, 1.0, rect, format, + dest_buf, dest_stride, + GEGL_BLIT_DEFAULT); +} + +static void +gimp_tile_handler_validate_real_validate_buffer (GimpTileHandlerValidate *validate, + const GeglRectangle *rect, + GeglBuffer *buffer) +{ + GimpTileHandlerValidateClass *klass; + + klass = GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate); + + if (klass->validate == gimp_tile_handler_validate_real_validate) + { + gegl_node_blit_buffer (validate->graph, buffer, rect, 0, + GEGL_ABYSS_NONE); + } + else + { + const Babl *format = gegl_buffer_get_format (buffer); + gpointer data; + gint stride; + + data = gegl_buffer_linear_open (buffer, rect, &stride, format); + + klass->validate (validate, rect, format, data, stride); + + gegl_buffer_linear_close (buffer, data); + } +} + +static GeglTile * +gimp_tile_handler_validate_validate_tile (GeglTileSource *source, + gint x, + gint y) +{ + GimpTileHandlerValidate *validate = GIMP_TILE_HANDLER_VALIDATE (source); + GeglTile *tile; + cairo_rectangle_int_t tile_rect; + cairo_region_overlap_t overlap; + + if (validate->suspend_validate || + cairo_region_is_empty (validate->dirty_region)) + { + return gegl_tile_handler_source_command (source, + GEGL_TILE_GET, x, y, 0, NULL); + } + + tile_rect.x = x * validate->tile_width; + tile_rect.y = y * validate->tile_height; + tile_rect.width = validate->tile_width; + tile_rect.height = validate->tile_height; + + overlap = cairo_region_contains_rectangle (validate->dirty_region, + &tile_rect); + + if (overlap == CAIRO_REGION_OVERLAP_OUT) + { + return gegl_tile_handler_source_command (source, + GEGL_TILE_GET, x, y, 0, NULL); + } + + if (overlap == CAIRO_REGION_OVERLAP_IN || validate->whole_tile) + { + gint tile_bpp; + gint tile_stride; + + cairo_region_subtract_rectangle (validate->dirty_region, &tile_rect); + + tile_bpp = babl_format_get_bytes_per_pixel (validate->format); + tile_stride = tile_bpp * validate->tile_width; + + tile = gegl_tile_handler_get_source_tile (GEGL_TILE_HANDLER (source), + x, y, 0, FALSE); + + gimp_tile_handler_validate_begin_validate (validate); + + gegl_tile_lock (tile); + + GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->validate + (validate, + GEGL_RECTANGLE (tile_rect.x, + tile_rect.y, + tile_rect.width, + tile_rect.height), + validate->format, + gegl_tile_get_data (tile), + tile_stride); + + gegl_tile_unlock (tile); + + gimp_tile_handler_validate_end_validate (validate); + } + else + { + cairo_region_t *tile_region; + gint tile_bpp; + gint tile_stride; + gint n_rects; + gint i; + + tile_region = cairo_region_copy (validate->dirty_region); + cairo_region_intersect_rectangle (tile_region, &tile_rect); + + cairo_region_subtract_rectangle (validate->dirty_region, &tile_rect); + + tile_bpp = babl_format_get_bytes_per_pixel (validate->format); + tile_stride = tile_bpp * validate->tile_width; + + tile = gegl_tile_handler_source_command (source, + GEGL_TILE_GET, x, y, 0, NULL); + + if (! tile) + { + tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (source), + x, y, 0); + + memset (gegl_tile_get_data (tile), + 0, tile_stride * validate->tile_height); + } + + gimp_tile_handler_validate_begin_validate (validate); + + gegl_tile_lock (tile); + + n_rects = cairo_region_num_rectangles (tile_region); + +#if 0 + g_printerr ("%d chunks\n", n_rects); +#endif + + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t blit_rect; + gint tile_x; + gint tile_y; + + cairo_region_get_rectangle (tile_region, i, &blit_rect); + + tile_x = blit_rect.x % validate->tile_width; + if (tile_x < 0) tile_x += validate->tile_width; + + tile_y = blit_rect.y % validate->tile_height; + if (tile_y < 0) tile_y += validate->tile_height; + + GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->validate + (validate, + GEGL_RECTANGLE (blit_rect.x, + blit_rect.y, + blit_rect.width, + blit_rect.height), + validate->format, + gegl_tile_get_data (tile) + + tile_y * tile_stride + + tile_x * tile_bpp, + tile_stride); + } + + gegl_tile_unlock (tile); + + gimp_tile_handler_validate_end_validate (validate); + + cairo_region_destroy (tile_region); + } + + return tile; +} + +static gpointer +gimp_tile_handler_validate_command (GeglTileSource *source, + GeglTileCommand command, + gint x, + gint y, + gint z, + gpointer data) +{ + if (command == GEGL_TILE_GET && z == 0) + return gimp_tile_handler_validate_validate_tile (source, x, y); + + return gegl_tile_handler_source_command (source, command, x, y, z, data); +} + + +/* public functions */ + +GeglTileHandler * +gimp_tile_handler_validate_new (GeglNode *graph) +{ + GimpTileHandlerValidate *validate; + + g_return_val_if_fail (GEGL_IS_NODE (graph), NULL); + + validate = g_object_new (GIMP_TYPE_TILE_HANDLER_VALIDATE, NULL); + + validate->graph = g_object_ref (graph); + + return GEGL_TILE_HANDLER (validate); +} + +void +gimp_tile_handler_validate_assign (GimpTileHandlerValidate *validate, + GeglBuffer *buffer) +{ + g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate)); + g_return_if_fail (GEGL_IS_BUFFER (buffer)); + g_return_if_fail (gimp_tile_handler_validate_get_assigned (buffer) == NULL); + + gegl_buffer_add_handler (buffer, validate); + + g_object_get (buffer, + "format", &validate->format, + "tile-width", &validate->tile_width, + "tile-height", &validate->tile_height, + NULL); + + g_object_set_data (G_OBJECT (buffer), + "gimp-tile-handler-validate", validate); +} + +void +gimp_tile_handler_validate_unassign (GimpTileHandlerValidate *validate, + GeglBuffer *buffer) +{ + g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate)); + g_return_if_fail (GEGL_IS_BUFFER (buffer)); + g_return_if_fail (gimp_tile_handler_validate_get_assigned (buffer) == validate); + + g_object_set_data (G_OBJECT (buffer), + "gimp-tile-handler-validate", NULL); + + gegl_buffer_remove_handler (buffer, validate); +} + +GimpTileHandlerValidate * +gimp_tile_handler_validate_get_assigned (GeglBuffer *buffer) +{ + g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL); + + return g_object_get_data (G_OBJECT (buffer), + "gimp-tile-handler-validate"); +} + +void +gimp_tile_handler_validate_invalidate (GimpTileHandlerValidate *validate, + const GeglRectangle *rect) +{ + g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate)); + g_return_if_fail (rect != NULL); + + cairo_region_union_rectangle (validate->dirty_region, + (cairo_rectangle_int_t *) rect); + + gegl_tile_handler_damage_rect (GEGL_TILE_HANDLER (validate), rect); + + g_signal_emit (validate, gimp_tile_handler_validate_signals[INVALIDATED], + 0, rect, NULL); +} + +void +gimp_tile_handler_validate_undo_invalidate (GimpTileHandlerValidate *validate, + const GeglRectangle *rect) +{ + g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate)); + g_return_if_fail (rect != NULL); + + cairo_region_subtract_rectangle (validate->dirty_region, + (cairo_rectangle_int_t *) rect); +} + +void +gimp_tile_handler_validate_begin_validate (GimpTileHandlerValidate *validate) +{ + g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate)); + + if (validate->validating++ == 0) + GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->begin_validate (validate); +} + +void +gimp_tile_handler_validate_end_validate (GimpTileHandlerValidate *validate) +{ + g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate)); + g_return_if_fail (validate->validating > 0); + + if (--validate->validating == 0) + GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate)->end_validate (validate); +} + +void +gimp_tile_handler_validate_validate (GimpTileHandlerValidate *validate, + GeglBuffer *buffer, + const GeglRectangle *rect, + gboolean intersect, + gboolean chunked) +{ + GimpTileHandlerValidateClass *klass; + cairo_region_t *region = NULL; + + g_return_if_fail (GIMP_IS_TILE_HANDLER_VALIDATE (validate)); + g_return_if_fail (gimp_tile_handler_validate_get_assigned (buffer) == + validate); + + klass = GIMP_TILE_HANDLER_VALIDATE_GET_CLASS (validate); + + if (! rect) + rect = gegl_buffer_get_extent (buffer); + + if (intersect) + { + region = cairo_region_copy (validate->dirty_region); + + cairo_region_intersect_rectangle (region, + (const cairo_rectangle_int_t *) rect); + } + else if (chunked) + { + region = cairo_region_create_rectangle ( + (const cairo_rectangle_int_t *) rect); + } + + if (region) + { + if (! cairo_region_is_empty (region)) + { + gimp_tile_handler_validate_begin_validate (validate); + + if (chunked) + { + GimpChunkIterator *iter; + + iter = gimp_chunk_iterator_new (region); + region = NULL; + + while (gimp_chunk_iterator_next (iter)) + { + GeglRectangle blit_rect; + + while (gimp_chunk_iterator_get_rect (iter, &blit_rect)) + klass->validate_buffer (validate, &blit_rect, buffer); + } + } + else + { + gint n_rects; + gint i; + + n_rects = cairo_region_num_rectangles (region); + + for (i = 0; i < n_rects; i++) + { + cairo_rectangle_int_t blit_rect; + + cairo_region_get_rectangle (region, i, &blit_rect); + + klass->validate_buffer (validate, + (const GeglRectangle *) &blit_rect, + buffer); + } + } + + gimp_tile_handler_validate_end_validate (validate); + + cairo_region_subtract_rectangle ( + validate->dirty_region, + (const cairo_rectangle_int_t *) rect); + } + + g_clear_pointer (®ion, cairo_region_destroy); + } + else + { + gimp_tile_handler_validate_begin_validate (validate); + + klass->validate_buffer (validate, rect, buffer); + + gimp_tile_handler_validate_end_validate (validate); + + cairo_region_subtract_rectangle ( + validate->dirty_region, + (const cairo_rectangle_int_t *) rect); + } +} + +gboolean +gimp_tile_handler_validate_buffer_set_extent (GeglBuffer *buffer, + const GeglRectangle *extent) +{ + GimpTileHandlerValidate *validate; + + g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE); + g_return_val_if_fail (extent != NULL, FALSE); + + validate = gimp_tile_handler_validate_get_assigned (buffer); + + g_return_val_if_fail (validate != NULL, FALSE); + + validate->suspend_validate++; + + if (gimp_gegl_buffer_set_extent (buffer, extent)) + { + validate->suspend_validate--; + + cairo_region_intersect_rectangle (validate->dirty_region, + (const cairo_rectangle_int_t *) extent); + + return TRUE; + } + + validate->suspend_validate--; + + return FALSE; +} + +void +gimp_tile_handler_validate_buffer_copy (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglBuffer *dst_buffer, + const GeglRectangle *dst_rect) +{ + GimpTileHandlerValidate *src_validate; + GimpTileHandlerValidate *dst_validate; + GeglRectangle real_src_rect; + GeglRectangle real_dst_rect; + + g_return_if_fail (GEGL_IS_BUFFER (src_buffer)); + g_return_if_fail (GEGL_IS_BUFFER (dst_buffer)); + g_return_if_fail (src_rect != dst_rect); + + src_validate = gimp_tile_handler_validate_get_assigned (src_buffer); + dst_validate = gimp_tile_handler_validate_get_assigned (dst_buffer); + + g_return_if_fail (dst_validate != NULL); + + if (! src_rect) + src_rect = gegl_buffer_get_extent (src_buffer); + + if (! dst_rect) + dst_rect = src_rect; + + real_src_rect = *src_rect; + + gegl_rectangle_intersect (&real_dst_rect, + dst_rect, gegl_buffer_get_extent (dst_buffer)); + + real_src_rect.x += real_dst_rect.x - dst_rect->x; + real_src_rect.y += real_dst_rect.y - dst_rect->y; + real_src_rect.width -= real_dst_rect.x - dst_rect->x; + real_src_rect.height -= real_dst_rect.y - dst_rect->y; + + real_src_rect.width = CLAMP (real_src_rect.width, 0, real_dst_rect.width); + real_src_rect.height = CLAMP (real_src_rect.height, 0, real_dst_rect.height); + + /* temporarily remove the source buffer's validate handler, so that + * gegl_buffer_copy() can use fast tile copying, using the TILE_COPY command. + * currently, gegl only uses TILE_COPY when the source buffer has no user- + * provided tile handlers. + */ + if (src_validate) + { + g_object_ref (src_validate); + + gimp_tile_handler_validate_unassign (src_validate, src_buffer); + } + + dst_validate->suspend_validate++; + + gimp_gegl_buffer_copy (src_buffer, &real_src_rect, GEGL_ABYSS_NONE, + dst_buffer, &real_dst_rect); + + dst_validate->suspend_validate--; + + if (src_validate) + { + gimp_tile_handler_validate_assign (src_validate, src_buffer); + + g_object_unref (src_validate); + } + + cairo_region_subtract_rectangle (dst_validate->dirty_region, + (cairo_rectangle_int_t *) &real_dst_rect); + + if (src_validate) + { + if (real_src_rect.x == real_dst_rect.x && + real_src_rect.y == real_dst_rect.y && + gegl_rectangle_equal (&real_src_rect, + gegl_buffer_get_extent (src_buffer))) + { + cairo_region_union (dst_validate->dirty_region, + src_validate->dirty_region); + } + else if (cairo_region_contains_rectangle ( + src_validate->dirty_region, + (cairo_rectangle_int_t *) &real_src_rect) != + CAIRO_REGION_OVERLAP_OUT) + { + cairo_region_t *region; + + region = cairo_region_copy (src_validate->dirty_region); + + if (! gegl_rectangle_equal (&real_src_rect, + gegl_buffer_get_extent (src_buffer))) + { + cairo_region_intersect_rectangle ( + region, (cairo_rectangle_int_t *) &real_src_rect); + } + + cairo_region_translate (region, + real_dst_rect.x - real_src_rect.x, + real_dst_rect.y - real_src_rect.y); + + if (cairo_region_is_empty (dst_validate->dirty_region)) + { + cairo_region_destroy (dst_validate->dirty_region); + + dst_validate->dirty_region = region; + } + else + { + cairo_region_union (dst_validate->dirty_region, region); + + cairo_region_destroy (region); + } + } + } +} diff --git a/app/gegl/gimptilehandlervalidate.h b/app/gegl/gimptilehandlervalidate.h new file mode 100644 index 0000000..998430f --- /dev/null +++ b/app/gegl/gimptilehandlervalidate.h @@ -0,0 +1,112 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_TILE_HANDLER_VALIDATE_H__ +#define __GIMP_TILE_HANDLER_VALIDATE_H__ + +#include <gegl-buffer-backend.h> + +/*** + * GimpTileHandlerValidate is a GeglTileHandler that renders the + * projection. + */ + +G_BEGIN_DECLS + +#define GIMP_TYPE_TILE_HANDLER_VALIDATE (gimp_tile_handler_validate_get_type ()) +#define GIMP_TILE_HANDLER_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TILE_HANDLER_VALIDATE, GimpTileHandlerValidate)) +#define GIMP_TILE_HANDLER_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TILE_HANDLER_VALIDATE, GimpTileHandlerValidateClass)) +#define GIMP_IS_TILE_HANDLER_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TILE_HANDLER_VALIDATE)) +#define GIMP_IS_TILE_HANDLER_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TILE_HANDLER_VALIDATE)) +#define GIMP_TILE_HANDLER_VALIDATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TILE_HANDLER_VALIDATE, GimpTileHandlerValidateClass)) + + +typedef struct _GimpTileHandlerValidate GimpTileHandlerValidate; +typedef struct _GimpTileHandlerValidateClass GimpTileHandlerValidateClass; + +struct _GimpTileHandlerValidate +{ + GeglTileHandler parent_instance; + + GeglNode *graph; + cairo_region_t *dirty_region; + const Babl *format; + gint tile_width; + gint tile_height; + gboolean whole_tile; + gint validating; + gint suspend_validate; +}; + +struct _GimpTileHandlerValidateClass +{ + GeglTileHandlerClass parent_class; + + /* signals */ + void (* invalidated) (GimpTileHandlerValidate *validate, + const GeglRectangle *rect); + + /* virtual functions */ + void (* begin_validate) (GimpTileHandlerValidate *validate); + void (* end_validate) (GimpTileHandlerValidate *validate); + void (* validate) (GimpTileHandlerValidate *validate, + const GeglRectangle *rect, + const Babl *format, + gpointer dest_buf, + gint dest_stride); + void (* validate_buffer) (GimpTileHandlerValidate *validate, + const GeglRectangle *rect, + GeglBuffer *buffer); +}; + + +GType gimp_tile_handler_validate_get_type (void) G_GNUC_CONST; + +GeglTileHandler * gimp_tile_handler_validate_new (GeglNode *graph); + +void gimp_tile_handler_validate_assign (GimpTileHandlerValidate *validate, + GeglBuffer *buffer); +void gimp_tile_handler_validate_unassign (GimpTileHandlerValidate *validate, + GeglBuffer *buffer); +GimpTileHandlerValidate * gimp_tile_handler_validate_get_assigned (GeglBuffer *buffer); + +void gimp_tile_handler_validate_invalidate (GimpTileHandlerValidate *validate, + const GeglRectangle *rect); +void gimp_tile_handler_validate_undo_invalidate (GimpTileHandlerValidate *validate, + const GeglRectangle *rect); + +void gimp_tile_handler_validate_begin_validate (GimpTileHandlerValidate *validate); +void gimp_tile_handler_validate_end_validate (GimpTileHandlerValidate *validate); + +void gimp_tile_handler_validate_validate (GimpTileHandlerValidate *validate, + GeglBuffer *buffer, + const GeglRectangle *rect, + gboolean intersect, + gboolean chunked); + +gboolean gimp_tile_handler_validate_buffer_set_extent (GeglBuffer *buffer, + const GeglRectangle *extent); + +void gimp_tile_handler_validate_buffer_copy (GeglBuffer *src_buffer, + const GeglRectangle *src_rect, + GeglBuffer *dst_buffer, + const GeglRectangle *dst_rect); + + +G_END_DECLS + +#endif /* __GIMP_TILE_HANDLER_VALIDATE_H__ */ |