When rendering a gradient with a repeat mode of NONE, don't sample
the gradient at 0.0 and 1.0, for pixels that lie to the left and to
the right of the gradient, respectively. Instead, use the left
color of the leftmost segment directly, and, likewise, the right
color of the rightmost segment. This always gives us the right
color for such pixels, even when there are gradient stops, that may
use different colors, at 0.0 and 1.0,
Remember the gradient segment at which the most-recent sample lies,
and pass it to gimp_gradient_get_color_at() as a seed for segement
lookup on the next sample. This improves the performance
marginally.
Pass through mode uses the same compositing logic as REPLACE mode,
however, it's a special case of REPLACE, where the layer is already
composited against the backdrop. This allows us to take a few
shortcuts that aren't generally applicable to REPLACE mode.
Add a dedicated op class for pass through mode, derived from the
REPLACE mode op, implementing these shortcuts.
this commit changes just those which make no difference to
functionality: property and object member defaults that get overridden
anyway, return values of g_return_val_if_fail(), some other stuff.
Commit 3635cf04ab moved the special
handling of bottom-layer compositing to GimpOperationLayerMode.
This required giving the op more control over the process()
function of its subclasses. As a temporary workaround, the commit
bypassed the subclasses entirely, using "gimp:layer-mode" for all
modes. This is the reckoning :)
Add a process() virtual function to GimpOperationLayerMode, which
its subclasses should override instead of
GeglOperationPointComposer3's process() functions. Reinstate the
subclasses (by returning the correct op in
gimp_layer_mode_get_oepration()), and have them override this
function.
Improve the way gimp_operation_layer_mode_process() dispatches to
the actual process function, to slightly lower its overhead and
fix some thread-safety issues.
Remove the "function" field of the layer-mode info array, and have
gimp_layer_mode_get_function() return the
GimpOperationLayerMode::process() function of the corresponding
op's class (caching the result, to keep it cheap.) This reduces
redundancy, allows us to make the ops' process() functions private,
and simplifies SSE dispatching (only used by NORMAL mode,
currently.)
Move the blend and composite functions of the non-specialized
layer modes to gimpoperationlayermode-{blend,composite}.[hc],
respectively, to improve code organization.
Move the SSE2 composite functions to a separate file, so that they
can be built as part of libapplayermodes_sse2, allowing
libapplayermodes to be built without SSE2 compiler flags. This
allows building GIMP with SSE acceleration enabled, while running
the resulting binary on a target with no SSE accelration.
Add a "blend_function" field to the layer-mode info array, and use
it to specify the blend function for the non-specialized modes.
This replaces the separate switch() statement that we used
previously.
Remove the "affected_region" field of the layer-mode info array.
We don't need it anymore, since we can go back to using
GimpOperationLayerMode's virtual get_affected_region() function.
Last but not least, a bunch of code cleanups and consistency
adjustments.
GimpFilter's is_last_node field only reflects the item's position
within the parent stack. When a layer is contained in a pass-
through group, it can be the last layer of the group, while not
being the last layer in the graph as a whole (paticularly, if
there are visible layers below the group). In fact, when we have
nested pass-through groups, whether or not a layer is the last
node depends on which group we're considering as the root (since
we exclude the backdrop from the group's projection, resulting in
different graphs for different groups).
Instead of rolling our own graph traversal, just move the relevant
logic to GimpOperationLayerMode, and let GEGL do the work for us.
At processing time, we can tell if we're the last node by checking
if we have any input.
For this to work, GimpOperationLayerMode's process() function needs
to have control over what's going on. Replace the derived op
classes, which override process(), with a call to the layer mode's
function (as per gimp_layer_mode_get_function()) in
GimpOperationLayerMode's process() function. (Well, actually, this
commit keeps the ops around, and just hacks around them in
gimp_layer_mode_get_operation(), because laziness :P)
Keep using the layer's is_last_node property to do the invalidation.
More than 2000 lines of code less in app/, instead of
if (instance->member)
{
g_object_unref/g_free/g_whatever (instance->member);
instance->member = NULL;
}
we now simply use
g_clear_object/pointer (&instance->member);
which is the same as g_object_class_list_properties() but filters
out the properties for which we don't want to create a GUI.
Use it in gimp_prop_gui_new().
Return only the config object's GType and do the g_object_new() in the
caller (one caller only needs the type, there is no need to create a
dummy object just to get to its type).
Commit 1e6acbd4e1 modified the
generated enum recipes to run gimp-mkenums from the source
directory, instead of the build directory, so that only the
basenames of the corresponding header files would appear in
the comment at the top of the generated files. This was a
mistake -- $(GIMP_MKENUMS) is expecting to be invoked from the
build directory.
Switch back to running gimp-mkenums from the build directory. To
avoid including the relative path from the build directory to the
source directory in the generated file, add a @basename@ production
variable to gimp-mkenums, which exapnds to the basename of the
input file, and use it instead of @filename@ in the recipes for the
generated enum files.
When regenerating an enum file, don't copy it back to the source
directory if it hasn't actually changed. This allows using a read-
only source directory where the enum header is newer than the
generated file, as long as they're not really out of sync.
OTOH, *do* touch the generated source-dir file even when unchanged,
in order to avoid re-running its recipe on the next build, however,
allow this to silently fail (which is harmless).
Takes a layer mode and a composite mode, and returns the region
included in the composition.
Use this function in GimpOperationLayerMode, instead of testing
for specific composite modes directly. Will also be used by
the next commit.
Indentation cleanup in gimp_layer_modes.h
... so that we can use it for other functions that involve
compositing regions (which we do in the next commit).
Rename gimp_operation_layer_mode_get_affect_mask() and
friends to _get_affected_region().
We check them into git, so this makes it easier to keep them in
sync when using a separate build directory.
Case in point -- this commit also syncs a few enum files that went
out-of-sync with their headers.
Commit 9d4084c82f skips conversion and
blending of (some) transparent source and destination pixels. When
`blend_out == blend_layer`, it banks on the fact that the alpha values
of `blend_out` would be the same as those of `blend_layer`, and hence
the same as those of `layer`; thing is, we only copy those values from
`layer` to `blend_layer` for the pixels that we *don't* skip, so this
assumption is just wrong :P This leaves us with bogus alpha values in
`blend_out` for the skipped pixels, when the above equality holds.
For composite modes that use the alpha values of `blend_op` (aka `comp`)
even for transparent input pixels (i.e., src-atop and src-in), this may
result in artifacts.
Fix this by simply initializing the alpha values of `blend_out` for
skipped pixels unconditionally.
from gimpdir/tool-options/ to gimpdir/filters/, and only if moving
fails try reading from the old location as fallback. We don't normally
move files around, but this one-liner nicely avoids cluttering
gimpdir.
Filters settings used to be serialized and deserialized only
when a filter tool's GUI was shown, too late for the code that
re-runs/re-shows filters with previous values.
Move the entire loading/saving code to gimp-operation-config.c, even
adding/removing the dummy separator item between timestamped automatic
history and manually saved settings. Load the settings automatically
when a settings container is requested, but still trigger saving from
the few places the container is changed in the GUI; could also
automate that later.
This commit also moves all settings of filters that have their own
tools from gimpdir/tool-options/ to gimpdir/filters/. Add compat code
to try the old filename if the new doesn't exist, so files are
migrated automatically.
WIP, but this step already fixes the bug.
which unlike HSL Lightness is actually physically meaningful and
also generally speaking much more useful than HSL Lightness.
Change "Lightness" to "Lightness (HSL)" to make it clear that
the "Lightness" in the Colors/Desaturate/Desaturate menu is not the
same as "Lightness" in LAB/LCH.
For completeness add the option to desaturate to "Value (HSV)".
Add links in app/operations/gimpoperationdesaturate.c
to the Wikipedia article with definitions of L/I/V in HSL/HSI/HSV.
... since that's the color space it actually works in.
Keep the legacy "Color (HSV)" mode's name as is, wrong as it is,
since, well, that's what it used to be called...
No need to do full back and forth RGB/HSV conversions.
Change the behavior such that fully desaturated values remain
desaturated, instead of saturating towards red.
Pixels whose source or destination alpha is zero are not blended, and
therefore do not need to be converted between the composite and blend
spaces (assuming a conversion is necessary to begin with.) When there
is a large enough segment of consecutive pixels that don't need
blending, split the conversion/blending process around it, so that
we don't convert too many unblended pixels unnecessarily.
For layers with lots of transparency, this can dramatically reduce
compositing time; for layers with no transparency, the added
overhead is rather negligible.
Merge mode lays the source layer on top of the destination, same as
normal mode, however, it assumes the source and destination are two
parts of an original whole, and are therefore mutually exclusive.
This is useful for blending cut & pasted content without artifacts,
or for replacing erased content in general.
Calculates the dot product of the two input colors, and uses that
as the value for all the output color's components. Basically,
a per-pixel mono mixer.
Useful for custom desaturation, component extraction, and crazier
stuff (bump mapping!)
Include erase mode in the menu for layers and general paint tools.
This makes the eraser tool somewhat unnecessary, but allows for
interesting use cases (e.g., airbrush eraser, etc.)
... possibly due to small win32 stack
Limit the number of samples processed in one go by gimp_composite_blend()
so that we don't overflow the stack when we alloca() buffers on it.
... and get rid of the dedicated op. This gives us support for all
the blend/composite options for this mode.
Rename COLOR_ERASE to COLOR_ERASE_LEGACY, with perceptual blending/
compositing and immutable everything, and add a new COLOR_ERASE
mode, defaulting to linear blending/compositing, with mutable
everything. Modify affected code.
These are more general, and more expensive, versions of the non-
subtractive compositing functions. They are used with modes that
specify the SUBTRACTIVE flag. This doesn't affect anything yet, but
the next commit ports color-erase mode to a blendfun.
Most modes only modify the *color* of overlapping dest/src regions,
however, erase and color-erase may also reduce their *alpha*, i.e.,
eliminate some of the overlapping content. Flag these modes with
the new SUBTRACTIVE flag, as they require more general compositing
code. The next commit adds the said code.
The mode group switching combo box is hard to discover, until we use the
default group instead of legacy group as default - it is better to make legacy
resemble the full old set to.
Need to provide the pixels in a format that matches the profile,
simply using "RGBA float" here was a brain bug of mine. Two profiles
and two formats are parameters the used GimpProfileTransform needs to
work correctly.
which returns an array of modes in the order they would appear in a
GimpLayerModeContext's UI (like tool options or the layers dialog),
without the separators.
Use it in context-commands.c and layers-commands.c instead of static
(and outdated) arrays for the actions that cycle through modes.
Instead, add a gimp_layer_mode_get_format() function, which takes
the layer mode, composite space, and blend space, and returns the
I/O format.
Currently, we always use the composite space format as the I/O
format. This simplifies gimp_composite_blend(), and gives us
composite-space support for the "special" layer mode ops for free.
Replace the 'with-behind' and 'with-replace' properties with a
single 'context' property, and use it to select the included
layer modes, according to their context mask.
Add a dummy GIMP_LAYER_MODE_SEPARATOR value to the GimpLayerMode
enum, and use it to explicitly mark the menu separators in the
layer-mode group arrays; add separators to the layer-mode menu
accordingly.
Update the rest of the code to use 'context' instead of 'with-behind'
and 'with-replace'. In particular, in the layers and layer options
dialogs, select the right context based on whether or not the
selected layer is a group.
A bitmask, specifying in which contexts a layer mode is applicable.
Can be a combination of:
- LAYER: usable as a layer mode for actual layers.
- GROUP: usable as a layer mode for layer groups. Currently, all
modes that specify LAYER also specify GROUP, and vice versa,
but the planned pass-through mode will be GROUP only.
- PAINT: can be used as a paint mode.
- FADE: can be used for fading.
Add a 'context' field to _GimpLayerModeInfo, and provide context
masks to all the modes.
Use the context mask for validation when setting a layer's mode.
The next commit will use the mask when populating the layer mode
menus.
Add a "paint_composite_mode" field to GimpLayerModeInfo and set the
mode of the eraser to SRC_ATOP. Defaulting to SRC_OVER for all
painting didn't quite do it for all modes.
set all legacy modes to completely immutable and the LAB modes'
blend mode to immutable. Change GimpLayer setters and the UI
accordingly. Remove the LAB color spaces from the GUI, they can
only be used with the LAB blend modes anyway and not changed.