diff --git a/libs/image/CMakeLists.txt b/libs/image/CMakeLists.txt index 12449658eb..a28bbf86ca 100644 --- a/libs/image/CMakeLists.txt +++ b/libs/image/CMakeLists.txt @@ -1,379 +1,380 @@ add_subdirectory( tests ) add_subdirectory( tiles3 ) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty ${CMAKE_CURRENT_SOURCE_DIR}/brushengine ${CMAKE_CURRENT_SOURCE_DIR}/commands ${CMAKE_CURRENT_SOURCE_DIR}/commands_new ${CMAKE_CURRENT_SOURCE_DIR}/filter ${CMAKE_CURRENT_SOURCE_DIR}/floodfill ${CMAKE_CURRENT_SOURCE_DIR}/generator ${CMAKE_CURRENT_SOURCE_DIR}/layerstyles ${CMAKE_CURRENT_SOURCE_DIR}/processing ${CMAKE_SOURCE_DIR}/sdk/tests ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ) if(FFTW3_FOUND) include_directories(${FFTW3_INCLUDE_DIR}) endif() if(HAVE_VC) include_directories(SYSTEM ${Vc_INCLUDE_DIR} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}) ko_compile_for_all_implementations(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp) else() set(__per_arch_circle_mask_generator_objs kis_brush_mask_applicator_factories.cpp) endif() set(kritaimage_LIB_SRCS tiles3/kis_tile.cc tiles3/kis_tile_data.cc tiles3/kis_tile_data_store.cc tiles3/kis_tile_data_pooler.cc tiles3/kis_tiled_data_manager.cc tiles3/KisTiledExtentManager.cpp tiles3/kis_memento_manager.cc tiles3/kis_hline_iterator.cpp tiles3/kis_vline_iterator.cpp tiles3/kis_random_accessor.cc tiles3/swap/kis_abstract_compression.cpp tiles3/swap/kis_lzf_compression.cpp tiles3/swap/kis_abstract_tile_compressor.cpp tiles3/swap/kis_legacy_tile_compressor.cpp tiles3/swap/kis_tile_compressor_2.cpp tiles3/swap/kis_chunk_allocator.cpp tiles3/swap/kis_memory_window.cpp tiles3/swap/kis_swapped_data_store.cpp tiles3/swap/kis_tile_data_swapper.cpp kis_distance_information.cpp kis_painter.cc kis_painter_blt_multi_fixed.cpp kis_marker_painter.cpp KisPrecisePaintDeviceWrapper.cpp kis_progress_updater.cpp brushengine/kis_paint_information.cc brushengine/kis_random_source.cpp brushengine/KisPerStrokeRandomSource.cpp brushengine/kis_stroke_random_source.cpp brushengine/kis_paintop.cc brushengine/kis_paintop_factory.cpp brushengine/kis_paintop_preset.cpp brushengine/kis_paintop_registry.cc brushengine/kis_paintop_settings.cpp brushengine/kis_paintop_settings_update_proxy.cpp brushengine/kis_paintop_utils.cpp brushengine/kis_no_size_paintop_settings.cpp brushengine/kis_locked_properties.cc brushengine/kis_locked_properties_proxy.cpp brushengine/kis_locked_properties_server.cpp brushengine/kis_paintop_config_widget.cpp brushengine/kis_uniform_paintop_property.cpp brushengine/kis_combo_based_paintop_property.cpp brushengine/kis_slider_based_paintop_property.cpp brushengine/kis_standard_uniform_properties_factory.cpp brushengine/KisStrokeSpeedMeasurer.cpp brushengine/KisPaintopSettingsIds.cpp commands/kis_deselect_global_selection_command.cpp commands/KisDeselectActiveSelectionCommand.cpp commands/kis_image_change_layers_command.cpp commands/kis_image_change_visibility_command.cpp commands/kis_image_command.cpp commands/kis_image_set_projection_color_space_command.cpp commands/kis_image_layer_add_command.cpp commands/kis_image_layer_move_command.cpp commands/kis_image_layer_remove_command.cpp commands/kis_image_layer_remove_command_impl.cpp commands/kis_image_lock_command.cpp commands/kis_node_command.cpp commands/kis_node_compositeop_command.cpp commands/kis_node_opacity_command.cpp commands/kis_node_property_list_command.cpp commands/kis_reselect_global_selection_command.cpp commands/KisReselectActiveSelectionCommand.cpp commands/kis_set_global_selection_command.cpp commands/KisNodeRenameCommand.cpp commands_new/kis_saved_commands.cpp commands_new/kis_processing_command.cpp commands_new/kis_image_resize_command.cpp commands_new/kis_image_set_resolution_command.cpp commands_new/kis_node_move_command2.cpp commands_new/kis_set_layer_style_command.cpp commands_new/kis_selection_move_command2.cpp commands_new/kis_update_command.cpp commands_new/kis_switch_current_time_command.cpp commands_new/kis_change_projection_color_command.cpp commands_new/kis_activate_selection_mask_command.cpp commands_new/kis_transaction_based_command.cpp commands_new/KisHoldUIUpdatesCommand.cpp processing/kis_do_nothing_processing_visitor.cpp processing/kis_simple_processing_visitor.cpp processing/kis_crop_processing_visitor.cpp processing/kis_crop_selections_processing_visitor.cpp processing/kis_transform_processing_visitor.cpp processing/kis_mirror_processing_visitor.cpp processing/KisSelectionBasedProcessingHelper.cpp filter/kis_filter.cc filter/kis_filter_category_ids.cpp filter/kis_filter_configuration.cc filter/kis_color_transformation_configuration.cc filter/kis_filter_registry.cc filter/kis_color_transformation_filter.cc generator/kis_generator.cpp generator/kis_generator_layer.cpp generator/kis_generator_registry.cpp floodfill/kis_fill_interval_map.cpp floodfill/kis_scanline_fill.cpp lazybrush/kis_min_cut_worker.cpp lazybrush/kis_lazy_fill_tools.cpp lazybrush/kis_multiway_cut.cpp lazybrush/KisWatershedWorker.cpp lazybrush/kis_colorize_mask.cpp lazybrush/kis_colorize_stroke_strategy.cpp KisDelayedUpdateNodeInterface.cpp KisCroppedOriginalLayerInterface.cpp kis_adjustment_layer.cc kis_selection_based_layer.cpp kis_node_filter_interface.cpp kis_base_accessor.cpp kis_base_node.cpp kis_base_processor.cpp kis_bookmarked_configuration_manager.cc kis_node_uuid_info.cpp kis_clone_layer.cpp kis_colorspace_convert_visitor.cpp kis_config_widget.cpp kis_convolution_kernel.cc kis_convolution_painter.cc kis_gaussian_kernel.cpp kis_edge_detection_kernel.cpp kis_cubic_curve.cpp kis_default_bounds.cpp kis_default_bounds_base.cpp kis_effect_mask.cc kis_fast_math.cpp kis_fill_painter.cc kis_filter_mask.cpp kis_filter_strategy.cc kis_transform_mask.cpp kis_transform_mask_params_interface.cpp kis_recalculate_transform_mask_job.cpp kis_recalculate_generator_layer_job.cpp kis_transform_mask_params_factory_registry.cpp kis_safe_transform.cpp kis_gradient_painter.cc kis_gradient_shape_strategy.cpp kis_cached_gradient_shape_strategy.cpp kis_polygonal_gradient_shape_strategy.cpp kis_iterator_ng.cpp kis_async_merger.cpp kis_merge_walker.cc kis_updater_context.cpp kis_update_job_item.cpp kis_stroke_strategy_undo_command_based.cpp kis_simple_stroke_strategy.cpp KisRunnableBasedStrokeStrategy.cpp KisRunnableStrokeJobDataBase.cpp KisRunnableStrokeJobData.cpp KisRunnableStrokeJobsInterface.cpp KisFakeRunnableStrokeJobsExecutor.cpp kis_stroke_job_strategy.cpp kis_stroke_strategy.cpp kis_stroke.cpp kis_strokes_queue.cpp KisStrokesQueueMutatedJobInterface.cpp kis_simple_update_queue.cpp kis_update_scheduler.cpp kis_queues_progress_updater.cpp kis_composite_progress_proxy.cpp kis_sync_lod_cache_stroke_strategy.cpp kis_lod_capable_layer_offset.cpp kis_update_time_monitor.cpp KisImageConfigNotifier.cpp kis_group_layer.cc kis_count_visitor.cpp kis_histogram.cc kis_image_interfaces.cpp kis_image_animation_interface.cpp kis_time_range.cpp kis_node_graph_listener.cpp kis_image.cc kis_image_signal_router.cpp KisImageSignals.cpp kis_image_config.cpp kis_projection_updates_filter.cpp kis_suspend_projection_updates_stroke_strategy.cpp kis_regenerate_frame_stroke_strategy.cpp kis_switch_time_stroke_strategy.cpp kis_crop_saved_extra_data.cpp kis_timed_signal_threshold.cpp kis_layer.cc kis_indirect_painting_support.cpp kis_abstract_projection_plane.cpp kis_layer_projection_plane.cpp kis_layer_utils.cpp kis_mask_projection_plane.cpp kis_projection_leaf.cpp KisSafeNodeProjectionStore.cpp kis_mask.cc kis_base_mask_generator.cpp kis_rect_mask_generator.cpp kis_circle_mask_generator.cpp kis_gauss_circle_mask_generator.cpp kis_gauss_rect_mask_generator.cpp ${__per_arch_circle_mask_generator_objs} kis_curve_circle_mask_generator.cpp kis_curve_rect_mask_generator.cpp kis_math_toolbox.cpp kis_memory_statistics_server.cpp kis_name_server.cpp kis_node.cpp kis_node_facade.cpp kis_node_progress_proxy.cpp kis_busy_progress_indicator.cpp kis_node_visitor.cpp kis_paint_device.cc kis_paint_device_debug_utils.cpp kis_fixed_paint_device.cpp KisOptimizedByteArray.cpp kis_paint_layer.cc kis_perspective_math.cpp kis_pixel_selection.cpp kis_processing_information.cpp kis_properties_configuration.cc kis_random_accessor_ng.cpp kis_random_generator.cc kis_random_sub_accessor.cpp kis_wrapped_random_accessor.cpp kis_selection.cc KisSelectionUpdateCompressor.cpp kis_selection_mask.cpp kis_update_outline_job.cpp kis_update_selection_job.cpp kis_serializable_configuration.cc kis_transaction_data.cpp kis_transform_worker.cc kis_perspectivetransform_worker.cpp bsplines/kis_bspline_1d.cpp bsplines/kis_bspline_2d.cpp bsplines/kis_nu_bspline_2d.cpp kis_warptransform_worker.cc kis_cage_transform_worker.cpp kis_liquify_transform_worker.cpp kis_green_coordinates_math.cpp kis_transparency_mask.cc kis_undo_adapter.cpp kis_macro_based_undo_store.cpp kis_surrogate_undo_adapter.cpp kis_legacy_undo_adapter.cpp kis_post_execution_undo_adapter.cpp kis_processing_visitor.cpp kis_processing_applicator.cpp krita_utils.cpp kis_outline_generator.cpp kis_layer_composition.cpp kis_selection_filters.cpp KisProofingConfiguration.h KisRecycleProjectionsJob.cpp kis_keyframe.cpp kis_keyframe_channel.cpp kis_keyframe_commands.cpp kis_scalar_keyframe_channel.cpp kis_raster_keyframe_channel.cpp kis_onion_skin_compositor.cpp kis_onion_skin_cache.cpp kis_idle_watcher.cpp kis_psd_layer_style.cpp kis_layer_properties_icons.cpp layerstyles/kis_multiple_projection.cpp layerstyles/kis_layer_style_filter.cpp layerstyles/kis_layer_style_filter_environment.cpp layerstyles/kis_layer_style_filter_projection_plane.cpp layerstyles/kis_layer_style_projection_plane.cpp layerstyles/kis_ls_drop_shadow_filter.cpp layerstyles/kis_ls_satin_filter.cpp layerstyles/kis_ls_stroke_filter.cpp layerstyles/kis_ls_bevel_emboss_filter.cpp layerstyles/kis_ls_overlay_filter.cpp layerstyles/kis_ls_utils.cpp layerstyles/gimp_bump_map.cpp + layerstyles/KisLayerStyleKnockoutBlower.cpp KisProofingConfiguration.cpp kis_node_query_path.cc ) set(einspline_SRCS 3rdparty/einspline/bspline_create.cpp 3rdparty/einspline/bspline_data.cpp 3rdparty/einspline/multi_bspline_create.cpp 3rdparty/einspline/nubasis.cpp 3rdparty/einspline/nubspline_create.cpp 3rdparty/einspline/nugrid.cpp ) add_library(kritaimage SHARED ${kritaimage_LIB_SRCS} ${einspline_SRCS}) generate_export_header(kritaimage BASE_NAME kritaimage) target_link_libraries(kritaimage PUBLIC kritaversion kritawidgets kritaglobal kritapsd kritaodf kritapigment kritacommand kritawidgetutils kritametadata Qt5::Concurrent ) target_link_libraries(kritaimage PUBLIC ${Boost_SYSTEM_LIBRARY}) if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) target_link_libraries(kritaimage PUBLIC atomic) endif() endif() if(OPENEXR_FOUND) target_link_libraries(kritaimage PUBLIC ${OPENEXR_LIBRARIES}) endif() if(FFTW3_FOUND) target_link_libraries(kritaimage PRIVATE ${FFTW3_LIBRARIES}) endif() if(HAVE_VC) target_link_libraries(kritaimage PUBLIC ${Vc_LIBRARIES}) endif() if (NOT GSL_FOUND) message (WARNING "KRITA WARNING! No GNU Scientific Library was found! Krita's Shaped Gradients might be non-normalized! Please install GSL library.") else () target_link_libraries(kritaimage PRIVATE ${GSL_LIBRARIES} ${GSL_CBLAS_LIBRARIES}) endif () target_include_directories(kritaimage PUBLIC $ $ $ $ $ ) set_target_properties(kritaimage PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaimage ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/image/layerstyles/KisLayerStyleKnockoutBlower.cpp b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.cpp new file mode 100644 index 0000000000..ea88544ee2 --- /dev/null +++ b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Dmitry Kazakov + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "KisLayerStyleKnockoutBlower.h" + +#include "kis_painter.h" +#include "KoCompositeOpRegistry.h" + +KisSelectionSP KisLayerStyleKnockoutBlower::knockoutSelection() const +{ + return m_knockoutSelection; +} + +void KisLayerStyleKnockoutBlower::setKnockoutSelection(KisSelectionSP selection) +{ + m_knockoutSelection = selection; +} + +void KisLayerStyleKnockoutBlower::apply(KisPainter *painter, KisPaintDeviceSP mergedStyle, const QRect &rect) const +{ + KIS_SAFE_ASSERT_RECOVER_NOOP(m_knockoutSelection); + + painter->setOpacity(OPACITY_OPAQUE_U8); + painter->setChannelFlags(QBitArray()); + painter->setCompositeOp(COMPOSITE_COPY); + painter->setSelection(m_knockoutSelection); + painter->bitBlt(rect.topLeft(), mergedStyle, rect); +} + +bool KisLayerStyleKnockoutBlower::isEmpty() const { + return !m_knockoutSelection; +} diff --git a/libs/image/layerstyles/KisLayerStyleKnockoutBlower.h b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.h new file mode 100644 index 0000000000..b12cca6644 --- /dev/null +++ b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Dmitry Kazakov + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KISLAYERSTYLEKNOCKOUTBLOWER_H +#define KISLAYERSTYLEKNOCKOUTBLOWER_H + +#include "kis_selection.h" + +class KisPainter; + + +class KisLayerStyleKnockoutBlower +{ +public: + KisSelectionSP knockoutSelection() const; + void setKnockoutSelection(KisSelectionSP selection); + + + void apply(KisPainter *painter, KisPaintDeviceSP mergedStyle, const QRect &rect) const; + bool isEmpty() const; + +private: + KisSelectionSP m_knockoutSelection; +}; + +#endif // KISLAYERSTYLEKNOCKOUTBLOWER_H diff --git a/libs/image/layerstyles/kis_layer_style_filter.h b/libs/image/layerstyles/kis_layer_style_filter.h index 30a311d404..2aca6515a0 100644 --- a/libs/image/layerstyles/kis_layer_style_filter.h +++ b/libs/image/layerstyles/kis_layer_style_filter.h @@ -1,72 +1,74 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_LAYER_STYLE_FILTER_H #define __KIS_LAYER_STYLE_FILTER_H #include "kis_types.h" #include "kis_shared.h" #include "kritaimage_export.h" #include "kis_psd_layer_style.h" #include class KisLayerStyleFilterEnvironment; class KisMultipleProjection; +class KisLayerStyleKnockoutBlower; class KRITAIMAGE_EXPORT KisLayerStyleFilter : public KisShared { public: KisLayerStyleFilter(const KoID &id); virtual ~KisLayerStyleFilter(); /** * \return Unique identifier for this filter */ QString id() const; virtual KisLayerStyleFilter* clone() const = 0; virtual void processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const = 0; /** * Some filters need pixels outside the current processing rect to compute the new * value (for instance, convolution filters) */ virtual QRect neededRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const = 0; /** * Similar to \ref neededRect: some filters will alter a lot of pixels that are * near to each other at the same time. So when you changed a single rectangle * in a device, the actual rectangle that will feel the influence of this change * might be bigger. Use this function to determine that rect. */ virtual QRect changedRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const = 0; protected: KisLayerStyleFilter(const KisLayerStyleFilter &rhs); private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_LAYER_STYLE_FILTER_H */ diff --git a/libs/image/layerstyles/kis_layer_style_filter_projection_plane.cpp b/libs/image/layerstyles/kis_layer_style_filter_projection_plane.cpp index a22bba8343..edc1f35503 100644 --- a/libs/image/layerstyles/kis_layer_style_filter_projection_plane.cpp +++ b/libs/image/layerstyles/kis_layer_style_filter_projection_plane.cpp @@ -1,147 +1,155 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_style_filter_projection_plane.h" #include "filter/kis_filter.h" #include "filter/kis_filter_configuration.h" #include "filter/kis_filter_registry.h" #include "kis_layer_style_filter.h" #include "kis_layer_style_filter_environment.h" #include "kis_psd_layer_style.h" #include "kis_painter.h" #include "kis_multiple_projection.h" +#include "KisLayerStyleKnockoutBlower.h" struct KisLayerStyleFilterProjectionPlane::Private { Private(KisLayer *_sourceLayer) : sourceLayer(_sourceLayer), environment(new KisLayerStyleFilterEnvironment(_sourceLayer)) { KIS_SAFE_ASSERT_RECOVER_NOOP(_sourceLayer); } Private(const Private &rhs, KisLayer *_sourceLayer, KisPSDLayerStyleSP clonedStyle) : sourceLayer(_sourceLayer), filter(rhs.filter ? rhs.filter->clone() : 0), style(clonedStyle), environment(new KisLayerStyleFilterEnvironment(_sourceLayer)), projection(rhs.projection) { KIS_SAFE_ASSERT_RECOVER_NOOP(_sourceLayer); } KisLayer *sourceLayer; QScopedPointer filter; KisPSDLayerStyleSP style; QScopedPointer environment; + KisLayerStyleKnockoutBlower knockoutBlower; KisMultipleProjection projection; }; KisLayerStyleFilterProjectionPlane:: KisLayerStyleFilterProjectionPlane(KisLayer *sourceLayer) : m_d(new Private(sourceLayer)) { } KisLayerStyleFilterProjectionPlane::KisLayerStyleFilterProjectionPlane(const KisLayerStyleFilterProjectionPlane &rhs, KisLayer *sourceLayer, KisPSDLayerStyleSP clonedStyle) : m_d(new Private(*rhs.m_d, sourceLayer, clonedStyle)) { } KisLayerStyleFilterProjectionPlane::~KisLayerStyleFilterProjectionPlane() { } void KisLayerStyleFilterProjectionPlane::setStyle(KisLayerStyleFilter *filter, KisPSDLayerStyleSP style) { m_d->filter.reset(filter); m_d->style = style; } QRect KisLayerStyleFilterProjectionPlane::recalculate(const QRect& rect, KisNodeSP filthyNode) { Q_UNUSED(filthyNode); if (!m_d->sourceLayer || !m_d->filter) { warnKrita << "KisLayerStyleFilterProjectionPlane::recalculate(): [BUG] is not initialized"; return QRect(); } m_d->projection.clear(rect); m_d->filter->processDirectly(m_d->sourceLayer->projection(), &m_d->projection, + &m_d->knockoutBlower, rect, m_d->style, m_d->environment.data()); return rect; } void KisLayerStyleFilterProjectionPlane::apply(KisPainter *painter, const QRect &rect) { m_d->projection.apply(painter->device(), rect, m_d->environment.data()); } KisPaintDeviceList KisLayerStyleFilterProjectionPlane::getLodCapableDevices() const { return m_d->projection.getLodCapableDevices(); } bool KisLayerStyleFilterProjectionPlane::isEmpty() const { return m_d->projection.isEmpty(); } +KisLayerStyleKnockoutBlower *KisLayerStyleFilterProjectionPlane::knockoutBlower() const +{ + return &m_d->knockoutBlower; +} + QRect KisLayerStyleFilterProjectionPlane::needRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { if (!m_d->sourceLayer || !m_d->filter) { warnKrita << "KisLayerStyleFilterProjectionPlane::needRect(): [BUG] is not initialized"; return rect; } KIS_ASSERT_RECOVER_NOOP(pos == KisLayer::N_ABOVE_FILTHY); return m_d->filter->neededRect(rect, m_d->style, m_d->environment.data()); } QRect KisLayerStyleFilterProjectionPlane::changeRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { if (!m_d->sourceLayer || !m_d->filter) { warnKrita << "KisLayerStyleFilterProjectionPlane::changeRect(): [BUG] is not initialized"; return rect; } KIS_ASSERT_RECOVER_NOOP(pos == KisLayer::N_ABOVE_FILTHY); return m_d->filter->changedRect(rect, m_d->style, m_d->environment.data()); } QRect KisLayerStyleFilterProjectionPlane::accessRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { return needRect(rect, pos); } QRect KisLayerStyleFilterProjectionPlane::needRectForOriginal(const QRect &rect) const { return needRect(rect, KisLayer::N_ABOVE_FILTHY); } diff --git a/libs/image/layerstyles/kis_layer_style_filter_projection_plane.h b/libs/image/layerstyles/kis_layer_style_filter_projection_plane.h index 077c4acfce..71b6bb2e38 100644 --- a/libs/image/layerstyles/kis_layer_style_filter_projection_plane.h +++ b/libs/image/layerstyles/kis_layer_style_filter_projection_plane.h @@ -1,63 +1,66 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __KIS_LAYER_STYLE_FILTER_PROJECTION_PLANE_H #define __KIS_LAYER_STYLE_FILTER_PROJECTION_PLANE_H #include "kis_abstract_projection_plane.h" #include #include "kis_types.h" +class KisLayerStyleKnockoutBlower; + class KisLayerStyleFilterProjectionPlane : public KisAbstractProjectionPlane { public: KisLayerStyleFilterProjectionPlane(KisLayer *sourceLayer); KisLayerStyleFilterProjectionPlane(const KisLayerStyleFilterProjectionPlane &rhs, KisLayer *sourceLayer, KisPSDLayerStyleSP clonedStyle); ~KisLayerStyleFilterProjectionPlane() override; void setStyle(KisLayerStyleFilter *filter, KisPSDLayerStyleSP style); QRect recalculate(const QRect& rect, KisNodeSP filthyNode) override; void apply(KisPainter *painter, const QRect &rect) override; QRect needRect(const QRect &rect, KisLayer::PositionToFilthy pos) const override; QRect changeRect(const QRect &rect, KisLayer::PositionToFilthy pos) const override; QRect accessRect(const QRect &rect, KisLayer::PositionToFilthy pos) const override; QRect needRectForOriginal(const QRect &rect) const override; KisPaintDeviceList getLodCapableDevices() const override; /** * \returns true if a call to apply() will actually paint anything. Basically, * it is a cached version of isEnabled(), though the state may change after calling * to recalculate(). */ bool isEmpty() const; + KisLayerStyleKnockoutBlower *knockoutBlower() const; private: struct Private; const QScopedPointer m_d; }; typedef QSharedPointer KisLayerStyleFilterProjectionPlaneSP; typedef QWeakPointer KisLayerStyleFilterProjectionPlaneWSP; #endif /* __KIS_LAYER_STYLE_FILTER_PROJECTION_PLANE_H */ diff --git a/libs/image/layerstyles/kis_layer_style_projection_plane.cpp b/libs/image/layerstyles/kis_layer_style_projection_plane.cpp index e89a900cad..19bf57fea0 100644 --- a/libs/image/layerstyles/kis_layer_style_projection_plane.cpp +++ b/libs/image/layerstyles/kis_layer_style_projection_plane.cpp @@ -1,365 +1,408 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_style_projection_plane.h" #include "kis_global.h" #include "kis_layer_style_filter_projection_plane.h" #include "kis_layer_projection_plane.h" #include "kis_psd_layer_style.h" #include "kis_ls_drop_shadow_filter.h" #include "kis_ls_satin_filter.h" #include "kis_ls_overlay_filter.h" #include "kis_ls_stroke_filter.h" #include "kis_ls_bevel_emboss_filter.h" #include "kis_projection_leaf.h" #include "kis_cached_paint_device.h" #include "kis_painter.h" #include "kis_ls_utils.h" +#include "KisLayerStyleKnockoutBlower.h" struct Q_DECL_HIDDEN KisLayerStyleProjectionPlane::Private { KisLayerProjectionPlaneWSP sourceProjectionPlane; QVector stylesBefore; QVector stylesAfter; QVector stylesOverlay; KisCachedPaintDevice cachedPaintDevice; KisCachedSelection cachedSelection; KisLayer *sourceLayer = 0; KisPSDLayerStyleSP style; bool canHaveChildNodes = false; bool dependsOnLowerNodes = false; void initSourcePlane(KisLayer *sourceLayer) { KIS_SAFE_ASSERT_RECOVER_RETURN(sourceLayer); sourceProjectionPlane = sourceLayer->internalProjectionPlane(); canHaveChildNodes = sourceLayer->projectionLeaf()->canHaveChildLayers(); dependsOnLowerNodes = sourceLayer->projectionLeaf()->dependsOnLowerNodes(); this->sourceLayer = sourceLayer; } QVector allStyles() const { return stylesBefore + stylesOverlay + stylesAfter; } - bool hasOverlayStylesReady() const { + bool hasOverlayStyles() const { Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesOverlay) { if (!plane->isEmpty()) return true; } return false; } + + bool hasKnockoutStyles() const { + Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesBefore) { + if (!plane->knockoutBlower()->isEmpty()) return true; + } + + Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesAfter) { + if (!plane->knockoutBlower()->isEmpty()) return true; + } + + return false; + } + + void applyComplexPlane(KisPainter *painter, + KisLayerStyleFilterProjectionPlaneSP plane, + const QRect &rect, + KisPaintDeviceSP originalClone); }; KisLayerStyleProjectionPlane::KisLayerStyleProjectionPlane(KisLayer *sourceLayer) : m_d(new Private) { KisPSDLayerStyleSP style = sourceLayer->layerStyle(); KIS_ASSERT_RECOVER(style) { style = toQShared(new KisPSDLayerStyle()); } init(sourceLayer, style); } KisLayerStyleProjectionPlane::KisLayerStyleProjectionPlane(const KisLayerStyleProjectionPlane &rhs, KisLayer *sourceLayer, KisPSDLayerStyleSP clonedStyle) : m_d(new Private) { m_d->initSourcePlane(sourceLayer); m_d->style = clonedStyle; KIS_SAFE_ASSERT_RECOVER(m_d->style) { m_d->style = toQShared(new KisPSDLayerStyle()); } Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, rhs.m_d->allStyles()) { m_d->stylesBefore << toQShared(new KisLayerStyleFilterProjectionPlane(*plane, sourceLayer, m_d->style)); } } // for testing purposes only! KisLayerStyleProjectionPlane::KisLayerStyleProjectionPlane(KisLayer *sourceLayer, KisPSDLayerStyleSP layerStyle) : m_d(new Private) { init(sourceLayer, layerStyle); } void KisLayerStyleProjectionPlane::init(KisLayer *sourceLayer, KisPSDLayerStyleSP style) { KIS_SAFE_ASSERT_RECOVER_RETURN(sourceLayer); m_d->initSourcePlane(sourceLayer); m_d->style = style; { KisLayerStyleFilterProjectionPlane *dropShadow = new KisLayerStyleFilterProjectionPlane(sourceLayer); dropShadow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::DropShadow), style); m_d->stylesBefore << toQShared(dropShadow); } { KisLayerStyleFilterProjectionPlane *outerGlow = new KisLayerStyleFilterProjectionPlane(sourceLayer); outerGlow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::OuterGlow), style); m_d->stylesAfter << toQShared(outerGlow); } { KisLayerStyleFilterProjectionPlane *stroke = new KisLayerStyleFilterProjectionPlane(sourceLayer); stroke->setStyle(new KisLsStrokeFilter(), style); m_d->stylesAfter << toQShared(stroke); } { KisLayerStyleFilterProjectionPlane *bevelEmboss = new KisLayerStyleFilterProjectionPlane(sourceLayer); bevelEmboss->setStyle(new KisLsBevelEmbossFilter(), style); m_d->stylesAfter << toQShared(bevelEmboss); } { KisLayerStyleFilterProjectionPlane *patternOverlay = new KisLayerStyleFilterProjectionPlane(sourceLayer); patternOverlay->setStyle(new KisLsOverlayFilter(KisLsOverlayFilter::Pattern), style); m_d->stylesOverlay << toQShared(patternOverlay); } { KisLayerStyleFilterProjectionPlane *gradientOverlay = new KisLayerStyleFilterProjectionPlane(sourceLayer); gradientOverlay->setStyle(new KisLsOverlayFilter(KisLsOverlayFilter::Gradient), style); m_d->stylesOverlay << toQShared(gradientOverlay); } { KisLayerStyleFilterProjectionPlane *colorOverlay = new KisLayerStyleFilterProjectionPlane(sourceLayer); colorOverlay->setStyle(new KisLsOverlayFilter(KisLsOverlayFilter::Color), style); m_d->stylesOverlay << toQShared(colorOverlay); } { KisLayerStyleFilterProjectionPlane *satin = new KisLayerStyleFilterProjectionPlane(sourceLayer); satin->setStyle(new KisLsSatinFilter(), style); m_d->stylesOverlay << toQShared(satin); } { KisLayerStyleFilterProjectionPlane *innerGlow = new KisLayerStyleFilterProjectionPlane(sourceLayer); innerGlow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::InnerGlow), style); m_d->stylesOverlay << toQShared(innerGlow); } { KisLayerStyleFilterProjectionPlane *innerShadow = new KisLayerStyleFilterProjectionPlane(sourceLayer); innerShadow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::InnerShadow), style); m_d->stylesOverlay << toQShared(innerShadow); } } KisLayerStyleProjectionPlane::~KisLayerStyleProjectionPlane() { } KisAbstractProjectionPlaneSP KisLayerStyleProjectionPlane::factoryObject(KisLayer *sourceLayer) { Q_ASSERT(sourceLayer); return toQShared(new KisLayerStyleProjectionPlane(sourceLayer)); } QRect KisLayerStyleProjectionPlane::recalculate(const QRect& rect, KisNodeSP filthyNode) { KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); QRect result = sourcePlane->recalculate(stylesNeedRect(rect), filthyNode); if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { plane->recalculate(rect, filthyNode); } } return result; } +void KisLayerStyleProjectionPlane::Private::applyComplexPlane(KisPainter *painter, + KisLayerStyleFilterProjectionPlaneSP plane, + const QRect &rect, + KisPaintDeviceSP originalClone) +{ + if (plane->isEmpty()) return; + + if (!plane->knockoutBlower()->isEmpty()) { + KisCachedPaintDevice::Guard d1(originalClone, cachedPaintDevice); + KisPaintDeviceSP mergedStyle = d1.device(); + mergedStyle->makeCloneFromRough(originalClone, rect); + + KisPainter overlayPainter(mergedStyle); + plane->apply(&overlayPainter, rect); + plane->knockoutBlower()->apply(painter, mergedStyle, rect); + + } else { + plane->apply(painter, rect); + } +} + void KisLayerStyleProjectionPlane::apply(KisPainter *painter, const QRect &rect) { KisLayerProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); if (m_d->style->isEnabled()) { - if (m_d->hasOverlayStylesReady()) { - + if (m_d->hasOverlayStyles() || m_d->hasKnockoutStyles()) { KisCachedPaintDevice::Guard d1(painter->device(), m_d->cachedPaintDevice); KisPaintDeviceSP originalClone = d1.device(); originalClone->makeCloneFromRough(painter->device(), rect); - Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesBefore) { - plane->apply(painter, rect); + Q_FOREACH (const KisLayerStyleFilterProjectionPlaneSP plane, m_d->stylesBefore) { + m_d->applyComplexPlane(painter, plane, rect, originalClone); } - KisCachedSelection::Guard s1(m_d->cachedSelection); - KisSelectionSP knockoutSelection = s1.selection(); - KisLsUtils::selectionFromAlphaChannel(m_d->sourceLayer->projection(), knockoutSelection, rect); + if (m_d->hasOverlayStyles()) { + KisCachedSelection::Guard s1(m_d->cachedSelection); + KisSelectionSP knockoutSelection = s1.selection(); + KisLsUtils::selectionFromAlphaChannel(m_d->sourceLayer->projection(), knockoutSelection, rect); - { - KisPainter overlayPainter(originalClone); - sourcePlane->applyMaxOutAlpha(&overlayPainter, rect); + KisCachedPaintDevice::Guard d2(painter->device(), m_d->cachedPaintDevice); + KisPaintDeviceSP sourceProjection = d2.device(); + sourceProjection->makeCloneFromRough(painter->device(), rect); - Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesOverlay) { - plane->apply(&overlayPainter, rect); - } - } + { + KisPainter overlayPainter(sourceProjection); + sourcePlane->applyMaxOutAlpha(&overlayPainter, rect); - painter->setOpacity(OPACITY_OPAQUE_U8); - painter->setChannelFlags(QBitArray()); - painter->setCompositeOp(COMPOSITE_COPY); - painter->setSelection(knockoutSelection); - painter->bitBlt(rect.topLeft(), originalClone, rect); + Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesOverlay) { + plane->apply(&overlayPainter, rect); + } + } - Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesAfter) { - plane->apply(painter, rect); + KisLayerStyleKnockoutBlower blower; + blower.setKnockoutSelection(knockoutSelection); + blower.apply(painter, sourceProjection, rect); + } else { + sourcePlane->apply(painter, rect); } + Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, m_d->stylesAfter) { + m_d->applyComplexPlane(painter, plane, rect, originalClone); + } } else { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesBefore) { plane->apply(painter, rect); } sourcePlane->apply(painter, rect); Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesAfter) { plane->apply(painter, rect); } } } else { sourcePlane->apply(painter, rect); } } KisPaintDeviceList KisLayerStyleProjectionPlane::getLodCapableDevices() const { KisPaintDeviceList list; KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { list << plane->getLodCapableDevices(); } list << sourcePlane->getLodCapableDevices(); } else { list << sourcePlane->getLodCapableDevices(); } return list; } QRect KisLayerStyleProjectionPlane::needRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { /** * Need rect should also be adjust for the layers that generate their 'original' * based on the contents of the underlying layers like KisAdjustmentLayer * * \see bug 390299 */ QRect needRect = rect; const bool adjustmentAboveDirty = m_d->dependsOnLowerNodes && (pos & KisLayer::N_FILTHY || pos & KisLayer::N_ABOVE_FILTHY); if (m_d->style->isEnabled() && adjustmentAboveDirty) { needRect |= stylesNeedRect(rect); } KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); needRect = sourcePlane->needRect(needRect, pos); return needRect; } QRect KisLayerStyleProjectionPlane::changeRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); QRect layerChangeRect = sourcePlane->changeRect(rect, pos); QRect changeRect = layerChangeRect; if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { changeRect |= plane->changeRect(layerChangeRect, KisLayer::N_ABOVE_FILTHY); } } return changeRect; } QRect KisLayerStyleProjectionPlane::accessRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); QRect accessRect = sourcePlane->accessRect(rect, pos); if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { accessRect |= plane->accessRect(rect, KisLayer::N_ABOVE_FILTHY); } } return accessRect; } QRect KisLayerStyleProjectionPlane::needRectForOriginal(const QRect &rect) const { /** * Need rect should also be adjust for the layers that generate their 'original' * based on the contents of the child layers like KisGroupLayer * * \see bug 366419 */ QRect needRect = rect; if (m_d->style->isEnabled()) { needRect |= stylesNeedRect(needRect); } KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); needRect = sourcePlane->needRectForOriginal(needRect); return needRect; } QRect KisLayerStyleProjectionPlane::stylesNeedRect(const QRect &rect) const { QRect needRect = rect; Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { needRect |= plane->needRect(rect, KisLayer::N_ABOVE_FILTHY); } return needRect; } diff --git a/libs/image/layerstyles/kis_ls_bevel_emboss_filter.cpp b/libs/image/layerstyles/kis_ls_bevel_emboss_filter.cpp index 79aee34514..6dd739390c 100644 --- a/libs/image/layerstyles/kis_ls_bevel_emboss_filter.cpp +++ b/libs/image/layerstyles/kis_ls_bevel_emboss_filter.cpp @@ -1,517 +1,519 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * See LayerFX plugin for Gimp as a reference implementation of this style: * http://registry.gimp.org/node/186 * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_ls_bevel_emboss_filter.h" #include #include #include #include #include #include "psd.h" #include "kis_convolution_kernel.h" #include "kis_convolution_painter.h" #include "kis_gaussian_kernel.h" #include "kis_pixel_selection.h" #include "kis_fill_painter.h" #include "kis_gradient_painter.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "kis_psd_layer_style.h" #include "kis_layer_style_filter_environment.h" #include "kis_ls_utils.h" #include "gimp_bump_map.h" #include "kis_transaction.h" #include "kis_multiple_projection.h" #include "kis_cached_paint_device.h" KisLsBevelEmbossFilter::KisLsBevelEmbossFilter() : KisLayerStyleFilter(KoID("lsstroke", i18n("Stroke (style)"))) { } KisLayerStyleFilter *KisLsBevelEmbossFilter::clone() const { return new KisLsBevelEmbossFilter(*this); } KisLsBevelEmbossFilter::KisLsBevelEmbossFilter(const KisLsBevelEmbossFilter &rhs) : KisLayerStyleFilter(rhs) { } void paintBevelSelection(KisPixelSelectionSP srcSelection, KisPixelSelectionSP dstSelection, const QRect &applyRect, int size, int initialSize, bool invert, KisLayerStyleFilterEnvironment *env) { KisCachedSelection::Guard s1(*env->cachedSelection()); KisSelectionSP tmpBaseSelection = s1.selection(); KisPixelSelectionSP tmpSelection = tmpBaseSelection->pixelSelection(); // NOTE: we are not using createCompositionSourceDevice() intentionally, // because the source device doesn't have alpha channel KisCachedSelection::Guard s2(*env->cachedSelection()); KisPixelSelectionSP fillDevice = s2.selection()->pixelSelection(); KisPainter gc(dstSelection); gc.setCompositeOp(COMPOSITE_COPY); for (int i = 0; i < size; i++) { const int growSize = initialSize - i - 1; quint8 selectedness = invert ? qRound(qreal(size - i - 1) / size * 255.0) : qRound(qreal(i + 1) / size * 255.0); fillDevice->setDefaultPixel(KoColor(&selectedness, fillDevice->colorSpace())); tmpSelection->makeCloneFromRough(srcSelection, srcSelection->selectedRect()); QRect changeRect = KisLsUtils::growSelectionUniform(tmpSelection, growSize, applyRect); gc.setSelection(tmpBaseSelection); gc.bitBlt(changeRect.topLeft(), fillDevice, changeRect); } } struct ContrastOp { static const bool supportsCaching = false; ContrastOp(qreal contrast) : m_contrast(contrast) { } int operator() (int iValue) { qreal value = qreal(iValue - 127) / 127.0; qreal slant = std::tan ((m_contrast + 1) * M_PI_4); value = (value - 0.5) * slant + 0.5; return qRound(value * 255.0); } private: qreal m_contrast; }; struct HighlightsFetchOp { static const bool supportsCaching = true; int operator() (int value) { return qRound(qMax(0, value - 127) * (255.0 / (255 - 127))); } }; struct ShadowsFetchOp { static const bool supportsCaching = true; int operator() (int value) { return 255 - qRound(qMin(value, 127) * (255.0 / 127.0)); } }; template void mapPixelValues(KisPixelSelectionSP srcSelection, KisPixelSelectionSP dstSelection, MapOp mapOp, const QRect &applyRect) { static quint8 mapTable[256]; static bool mapInitialized = false; if (!MapOp::supportsCaching || !mapInitialized) { mapInitialized = true; for (int i = 0; i < 256; i++) { mapTable[i] = mapOp(i); } } KisSequentialConstIterator srcIt(srcSelection, applyRect); KisSequentialIterator dstIt(dstSelection, applyRect); while (srcIt.nextPixel() && dstIt.nextPixel()) { const quint8 *srcPtr = srcIt.rawDataConst(); quint8 *dstPtr = dstIt.rawData(); *dstPtr = mapTable[*srcPtr]; } } template void mapPixelValues(KisPixelSelectionSP dstSelection, MapOp mapOp, const QRect &applyRect) { static quint8 mapTable[256]; static bool mapInitialized = false; if (!MapOp::supportsCaching || !mapInitialized) { mapInitialized = true; for (int i = 0; i < 256; i++) { mapTable[i] = mapOp(i); } } KisSequentialIterator dstIt(dstSelection, applyRect); while (dstIt.nextPixel()) { quint8 *dstPtr = dstIt.rawData(); *dstPtr = mapTable[*dstPtr]; } } struct BevelEmbossRectCalculator { BevelEmbossRectCalculator(const QRect &applyRect, const psd_layer_effects_bevel_emboss *config) { shadowHighlightsFinalRect = applyRect; applyGaussianRect = shadowHighlightsFinalRect; applyGlossContourRect = KisLsUtils::growRectFromRadius(applyGaussianRect, config->soften()); applyBumpmapRect = applyGlossContourRect; applyContourRect = applyBumpmapRect; applyTextureRect = applyContourRect; applyBevelRect = calcBevelNeedRect(applyTextureRect, config); initialFetchRect = kisGrowRect(applyBevelRect, 1); } QRect totalChangeRect(const QRect &applyRect, const psd_layer_effects_bevel_emboss *config) { QRect changeRect = calcBevelChangeRect(applyRect, config); changeRect = kisGrowRect(changeRect, 1); // bumpmap method changeRect = KisLsUtils::growRectFromRadius(changeRect, config->soften()); return changeRect; } QRect totalNeedRect(const QRect &applyRect, const psd_layer_effects_bevel_emboss *config) { QRect changeRect = applyRect; changeRect = KisLsUtils::growRectFromRadius(changeRect, config->soften()); changeRect = kisGrowRect(changeRect, 1); // bumpmap method changeRect = calcBevelNeedRect(applyRect, config); return changeRect; } QRect initialFetchRect; QRect applyBevelRect; QRect applyTextureRect; QRect applyContourRect; QRect applyBumpmapRect; QRect applyGlossContourRect; QRect applyGaussianRect; QRect shadowHighlightsFinalRect; private: QRect calcBevelChangeRect(const QRect &applyRect, const psd_layer_effects_bevel_emboss *config) { const int size = config->size(); int limitingGrowSize = 0; switch (config->style()) { case psd_bevel_outer_bevel: limitingGrowSize = size; break; case psd_bevel_inner_bevel: limitingGrowSize = 0; break; case psd_bevel_emboss: { const int initialSize = std::ceil(qreal(size) / 2.0); limitingGrowSize = initialSize; break; } case psd_bevel_pillow_emboss: { const int halfSizeC = std::ceil(qreal(size) / 2.0); limitingGrowSize = halfSizeC; break; } case psd_bevel_stroke_emboss: warnKrita << "WARNING: Stroke Emboss style is not implemented yet!"; return applyRect; } return kisGrowRect(applyRect, limitingGrowSize); } QRect calcBevelNeedRect(const QRect &applyRect, const psd_layer_effects_bevel_emboss *config) { const int size = config->size(); int limitingGrowSize = size; return kisGrowRect(applyRect, limitingGrowSize); } }; void KisLsBevelEmbossFilter::applyBevelEmboss(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_bevel_emboss *config, KisLayerStyleFilterEnvironment *env) const { if (applyRect.isEmpty()) return; BevelEmbossRectCalculator d(applyRect, config); KisCachedSelection::Guard s1(*env->cachedSelection()); KisSelectionSP baseSelection = s1.selection(); KisLsUtils::selectionFromAlphaChannel(srcDevice, baseSelection, d.initialFetchRect); KisPixelSelectionSP selection = baseSelection->pixelSelection(); //selection->convertToQImage(0, QRect(0,0,300,300)).save("0_selection_initial.png"); const int size = config->size(); int limitingGrowSize = 0; KisCachedSelection::Guard s2(*env->cachedSelection()); KisPixelSelectionSP bumpmapSelection = s2.selection()->pixelSelection(); switch (config->style()) { case psd_bevel_outer_bevel: paintBevelSelection(selection, bumpmapSelection, d.applyBevelRect, size, size, false, env); limitingGrowSize = size; break; case psd_bevel_inner_bevel: paintBevelSelection(selection, bumpmapSelection, d.applyBevelRect, size, 0, false, env); limitingGrowSize = 0; break; case psd_bevel_emboss: { const int initialSize = std::ceil(qreal(size) / 2.0); paintBevelSelection(selection, bumpmapSelection, d.applyBevelRect, size, initialSize, false, env); limitingGrowSize = initialSize; break; } case psd_bevel_pillow_emboss: { const int halfSizeF = std::floor(qreal(size) / 2.0); const int halfSizeC = std::ceil(qreal(size) / 2.0); // TODO: probably not correct! paintBevelSelection(selection, bumpmapSelection, d.applyBevelRect, halfSizeC, halfSizeC, false, env); paintBevelSelection(selection, bumpmapSelection, d.applyBevelRect, halfSizeF, 0, true, env); limitingGrowSize = halfSizeC; break; } case psd_bevel_stroke_emboss: warnKrita << "WARNING: Stroke Emboss style is not implemented yet!"; return; } KisCachedSelection::Guard s3(*env->cachedSelection()); KisPixelSelectionSP limitingSelection = s3.selection()->pixelSelection(); limitingSelection->makeCloneFromRough(selection, selection->selectedRect()); { QRect changeRectUnused = KisLsUtils::growSelectionUniform(limitingSelection, limitingGrowSize, d.applyBevelRect); Q_UNUSED(changeRectUnused); } //bumpmapSelection->convertToQImage(0, QRect(0,0,300,300)).save("1_selection_xconv.png"); if (config->textureEnabled()) { KisCachedSelection::Guard s4(*env->cachedSelection()); KisPixelSelectionSP textureSelection = s4.selection()->pixelSelection(); KisLsUtils::fillPattern(textureSelection, d.applyTextureRect, env, config->textureScale(), config->texturePattern(), config->textureHorizontalPhase(), config->textureVerticalPhase(), config->textureAlignWithLayer()); int contrastadj = 0; { using namespace std; int tex_depth = config->textureDepth(); if (tex_depth >= 0.0) { if (tex_depth <= 100.0) { contrastadj = int(qRound((1-(tex_depth/100.0)) * -127)); } else { contrastadj = int(qRound(((tex_depth-100.0)/900.0) * 127)); } } else { textureSelection->invert(); if (tex_depth >= -100.0) { contrastadj = int(qRound((1-(abs(tex_depth)/100.0)) * -127)); } else { contrastadj = int(qRound(((abs(tex_depth)-100.0)/900.0) * 127)); } } } qreal contrast = qBound(-1.0, qreal(contrastadj) / 127.0, 1.0); mapPixelValues(textureSelection, ContrastOp(contrast), d.applyTextureRect); { KisPainter gc(bumpmapSelection); gc.setCompositeOp(COMPOSITE_MULT); gc.bitBlt(d.applyTextureRect.topLeft(), textureSelection, d.applyTextureRect); gc.end(); } } //bumpmapSelection->convertToQImage(0, QRect(0,0,300,300)).save("15_selection_texture.png"); if (config->contourEnabled()) { if (config->range() != KisLsUtils::FULL_PERCENT_RANGE) { KisLsUtils::adjustRange(bumpmapSelection, d.applyContourRect, config->range()); } KisLsUtils::applyContourCorrection(bumpmapSelection, d.applyContourRect, config->contourLookupTable(), config->antiAliased(), true); } bumpmap_vals_t bmvals; bmvals.azimuth = config->angle(); bmvals.elevation = config->altitude(); bmvals.depth = config->depth(); bmvals.ambient = 0; bmvals.compensate = true; bmvals.invert = config->direction() == psd_direction_down; bmvals.type = LINEAR; bumpmap(bumpmapSelection, d.applyBumpmapRect, bmvals); //bumpmapSelection->convertToQImage(0, QRect(0,0,300,300)).save("3_selection_bumpmap.png"); { // TODO: optimize! KisLsUtils::applyContourCorrection(bumpmapSelection, d.applyGlossContourRect, config->glossContourLookupTable(), config->glossAntiAliased(), true); } if (config->soften()) { KisLsUtils::applyGaussianWithTransaction(bumpmapSelection, d.applyGaussianRect, config->soften()); } if (config->textureEnabled() && config->textureInvert()) { bumpmapSelection->invert(); } selection->clear(); mapPixelValues(bumpmapSelection, selection, ShadowsFetchOp(), d.shadowHighlightsFinalRect); selection->applySelection(limitingSelection, SELECTION_INTERSECT); //dstDevice->convertToQImage(0, QRect(0,0,300,300)).save("4_dst_before_apply.png"); //selection->convertToQImage(0, QRect(0,0,300,300)).save("4_shadows_sel.png"); { KisPaintDeviceSP dstDevice = dst->getProjection("00_bevel_shadow", config->shadowBlendMode(), config->shadowOpacity(), QBitArray(), srcDevice); const KoColor fillColor(config->shadowColor(), dstDevice->colorSpace()); const QRect &fillRect = d.shadowHighlightsFinalRect; KisCachedPaintDevice::Guard d1(dstDevice, *env->cachedPaintDevice()); KisPaintDeviceSP fillDevice = d1.device(); fillDevice->setDefaultPixel(fillColor); KisPainter::copyAreaOptimized(fillRect.topLeft(), fillDevice, dstDevice, fillRect, baseSelection); } selection->clear(); mapPixelValues(bumpmapSelection, selection, HighlightsFetchOp(), d.shadowHighlightsFinalRect); selection->applySelection(limitingSelection, SELECTION_INTERSECT); //selection->convertToQImage(0, QRect(0,0,300,300)).save("5_highlights_sel.png"); { KisPaintDeviceSP dstDevice = dst->getProjection("01_bevel_highlight", config->highlightBlendMode(), config->highlightOpacity(), QBitArray(), srcDevice); const KoColor fillColor(config->highlightColor(), dstDevice->colorSpace()); const QRect &fillRect = d.shadowHighlightsFinalRect; KisCachedPaintDevice::Guard d1(dstDevice, *env->cachedPaintDevice()); KisPaintDeviceSP fillDevice = d1.device(); fillDevice->setDefaultPixel(fillColor); KisPainter::copyAreaOptimized(fillRect.topLeft(), fillDevice, dstDevice, fillRect, baseSelection); } } void KisLsBevelEmbossFilter::processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, - const QRect &applyRect, - KisPSDLayerStyleSP style, - KisLayerStyleFilterEnvironment *env) const + KisLayerStyleKnockoutBlower *blower, + const QRect &applyRect, + KisPSDLayerStyleSP style, + KisLayerStyleFilterEnvironment *env) const { Q_UNUSED(env); + Q_UNUSED(blower); KIS_ASSERT_RECOVER_RETURN(style); const psd_layer_effects_bevel_emboss *config = style->bevelAndEmboss(); if (!KisLsUtils::checkEffectEnabled(config, dst)) return; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); applyBevelEmboss(src, dst, applyRect, w.config, env); } QRect KisLsBevelEmbossFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_bevel_emboss *config = style->bevelAndEmboss(); if (!config->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); BevelEmbossRectCalculator d(rect, w.config); return d.totalNeedRect(rect, w.config); } QRect KisLsBevelEmbossFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_bevel_emboss *config = style->bevelAndEmboss(); if (!config->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); BevelEmbossRectCalculator d(rect, w.config); return d.totalChangeRect(rect, w.config); } diff --git a/libs/image/layerstyles/kis_ls_bevel_emboss_filter.h b/libs/image/layerstyles/kis_ls_bevel_emboss_filter.h index 32787846ae..914f40c82f 100644 --- a/libs/image/layerstyles/kis_ls_bevel_emboss_filter.h +++ b/libs/image/layerstyles/kis_ls_bevel_emboss_filter.h @@ -1,57 +1,58 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LS_BEVEL_EMBOSS_FILTER_H #define KIS_LS_BEVEL_EMBOSS_FILTER_H #include #include "kis_layer_style_filter.h" #include struct psd_layer_effects_bevel_emboss; class KRITAIMAGE_EXPORT KisLsBevelEmbossFilter : public KisLayerStyleFilter { public: KisLsBevelEmbossFilter(); KisLayerStyleFilter* clone() const override; void processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect neededRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect changedRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; private: KisLsBevelEmbossFilter(const KisLsBevelEmbossFilter &rhs); void applyBevelEmboss(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_bevel_emboss *config, KisLayerStyleFilterEnvironment *env) const; }; #endif diff --git a/libs/image/layerstyles/kis_ls_drop_shadow_filter.cpp b/libs/image/layerstyles/kis_ls_drop_shadow_filter.cpp index b0da105efe..a9149e9f3b 100644 --- a/libs/image/layerstyles/kis_ls_drop_shadow_filter.cpp +++ b/libs/image/layerstyles/kis_ls_drop_shadow_filter.cpp @@ -1,298 +1,300 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_ls_drop_shadow_filter.h" #include #include #include #include #include "psd.h" #include "kis_convolution_kernel.h" #include "kis_convolution_painter.h" #include "kis_gaussian_kernel.h" #include "kis_pixel_selection.h" #include "kis_fill_painter.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "kis_psd_layer_style.h" #include "kis_multiple_projection.h" #include "kis_ls_utils.h" #include "kis_layer_style_filter_environment.h" #include "kis_cached_paint_device.h" KisLsDropShadowFilter::KisLsDropShadowFilter(Mode mode) : KisLayerStyleFilter(KoID("lsdropshadow", i18n("Drop Shadow (style)"))) , m_mode(mode) { } KisLsDropShadowFilter::KisLsDropShadowFilter(const KisLsDropShadowFilter &rhs) : KisLayerStyleFilter(rhs), m_mode(rhs.m_mode) { } KisLayerStyleFilter *KisLsDropShadowFilter::clone() const { return new KisLsDropShadowFilter(*this); } struct ShadowRectsData { enum Direction { NEED_RECT, CHANGE_RECT }; ShadowRectsData(const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_shadow_base *shadow, Direction direction) { spread_size = (shadow->spread() * shadow->size() + 50) / 100; blur_size = shadow->size() - spread_size; offset = shadow->calculateOffset(context); // need rect calculation in reverse order dstRect = applyRect; const int directionCoeff = direction == NEED_RECT ? -1 : 1; srcRect = dstRect.translated(directionCoeff * offset); noiseNeedRect = shadow->noise() > 0 ? kisGrowRect(srcRect, KisLsUtils::noiseNeedBorder) : srcRect; blurNeedRect = blur_size ? KisLsUtils::growRectFromRadius(noiseNeedRect, blur_size) : noiseNeedRect; spreadNeedRect = spread_size ? KisLsUtils::growRectFromRadius(blurNeedRect, spread_size) : blurNeedRect; // dbgKrita << ppVar(dstRect); // dbgKrita << ppVar(srcRect); // dbgKrita << ppVar(noiseNeedRect); // dbgKrita << ppVar(blurNeedRect); // dbgKrita << ppVar(spreadNeedRect); } inline QRect finalNeedRect() const { return spreadNeedRect; } inline QRect finalChangeRect() const { // TODO: is it correct? return spreadNeedRect; } qint32 spread_size; qint32 blur_size; QPoint offset; QRect srcRect; QRect dstRect; QRect noiseNeedRect; QRect blurNeedRect; QRect spreadNeedRect; }; void KisLsDropShadowFilter::applyDropShadow(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_shadow_base *shadow, KisLayerStyleFilterEnvironment *env) const { if (applyRect.isEmpty()) return; ShadowRectsData d(applyRect, context, shadow, ShadowRectsData::NEED_RECT); KisCachedSelection::Guard s1(*env->cachedSelection()); KisSelectionSP baseSelection = s1.selection(); KisLsUtils::selectionFromAlphaChannel(srcDevice, baseSelection, d.spreadNeedRect); KisPixelSelectionSP selection = baseSelection->pixelSelection(); //selection->convertToQImage(0, QRect(0,0,300,300)).save("0_selection_initial.png"); if (shadow->invertsSelection()) { selection->invert(); } /** * Copy selection which will be erased from the original later */ KisCachedSelection::Guard s2(*env->cachedSelection()); KisPixelSelectionSP knockOutSelection; if (shadow->knocksOut()) { knockOutSelection = s2.selection()->pixelSelection(); knockOutSelection->makeCloneFromRough(selection, selection->selectedRect()); } if (shadow->technique() == psd_technique_precise) { KisLsUtils::findEdge(selection, d.blurNeedRect, true); } /** * Spread and blur the selection */ if (d.spread_size) { KisLsUtils::applyGaussianWithTransaction(selection, d.blurNeedRect, d.spread_size); // TODO: find out why in libpsd we pass false here. If we do so, // the result is fully black, which is not expected KisLsUtils::findEdge(selection, d.blurNeedRect, true /*shadow->edgeHidden()*/); } //selection->convertToQImage(0, QRect(0,0,300,300)).save("1_selection_spread.png"); if (d.blur_size) { KisLsUtils::applyGaussianWithTransaction(selection, d.noiseNeedRect, d.blur_size); } //selection->convertToQImage(0, QRect(0,0,300,300)).save("2_selection_blur.png"); if (shadow->range() != KisLsUtils::FULL_PERCENT_RANGE) { KisLsUtils::adjustRange(selection, d.noiseNeedRect, shadow->range()); } const psd_layer_effects_inner_glow *iglow = 0; if ((iglow = dynamic_cast(shadow)) && iglow->source() == psd_glow_center) { selection->invert(); } /** * Contour correction */ KisLsUtils::applyContourCorrection(selection, d.noiseNeedRect, shadow->contourLookupTable(), shadow->antiAliased(), shadow->edgeHidden()); //selection->convertToQImage(0, QRect(0,0,300,300)).save("3_selection_contour.png"); /** * Noise */ if (shadow->noise() > 0) { KisLsUtils::applyNoise(selection, d.srcRect, shadow->noise(), context, env); } //selection->convertToQImage(0, QRect(0,0,300,300)).save("4_selection_noise.png"); if (!d.offset.isNull()) { selection->setX(d.offset.x()); selection->setY(d.offset.y()); } /** * Knock-out original outline of the device from the resulting shade */ if (shadow->knocksOut()) { KIS_ASSERT_RECOVER_RETURN(knockOutSelection); QRect knockOutRect = !shadow->invertsSelection() ? d.srcRect : d.spreadNeedRect; knockOutRect &= d.dstRect; KisPainter gc(selection); gc.setCompositeOp(COMPOSITE_ERASE); gc.bitBlt(knockOutRect.topLeft(), knockOutSelection, knockOutRect); } //selection->convertToQImage(0, QRect(0,0,300,300)).save("5_selection_knockout.png"); KisLsUtils::applyFinalSelection(KisMultipleProjection::defaultProjectionId(), baseSelection, srcDevice, dst, d.srcRect, d.dstRect, context, shadow, env); } const psd_layer_effects_shadow_base* KisLsDropShadowFilter::getShadowStruct(KisPSDLayerStyleSP style) const { const psd_layer_effects_shadow_base *config = 0; if (m_mode == DropShadow) { config = style->dropShadow(); } else if (m_mode == InnerShadow) { config = style->innerShadow(); } else if (m_mode == OuterGlow) { config = style->outerGlow(); } else if (m_mode == InnerGlow) { config = style->innerGlow(); } return config; } void KisLsDropShadowFilter::processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { + Q_UNUSED(blower); KIS_ASSERT_RECOVER_RETURN(style); const psd_layer_effects_shadow_base *config = getShadowStruct(style); if (!KisLsUtils::checkEffectEnabled(config, dst)) return; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); applyDropShadow(src, dst, applyRect, style->context(), w.config, env); } QRect KisLsDropShadowFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_shadow_base *shadowStruct = getShadowStruct(style); if (!shadowStruct->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), shadowStruct); ShadowRectsData d(rect, style->context(), w.config, ShadowRectsData::NEED_RECT); return rect | d.finalNeedRect(); } QRect KisLsDropShadowFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_shadow_base *shadowStruct = getShadowStruct(style); if (!shadowStruct->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), shadowStruct); ShadowRectsData d(rect, style->context(), w.config, ShadowRectsData::CHANGE_RECT); return style->context()->keep_original ? d.finalChangeRect() : rect | d.finalChangeRect(); } diff --git a/libs/image/layerstyles/kis_ls_drop_shadow_filter.h b/libs/image/layerstyles/kis_ls_drop_shadow_filter.h index ff847950e1..5494f56572 100644 --- a/libs/image/layerstyles/kis_ls_drop_shadow_filter.h +++ b/libs/image/layerstyles/kis_ls_drop_shadow_filter.h @@ -1,69 +1,70 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LS_DROP_SHADOW_FILTER_H #define KIS_LS_DROP_SHADOW_FILTER_H #include #include "kis_layer_style_filter.h" #include class psd_layer_effects_shadow_base; class KRITAIMAGE_EXPORT KisLsDropShadowFilter : public KisLayerStyleFilter { public: enum Mode { DropShadow, InnerShadow, OuterGlow, InnerGlow }; KisLsDropShadowFilter(Mode mode = DropShadow); KisLayerStyleFilter* clone() const override; void processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect neededRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect changedRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; private: KisLsDropShadowFilter(const KisLsDropShadowFilter &rhs); const psd_layer_effects_shadow_base* getShadowStruct(KisPSDLayerStyleSP style) const; void applyDropShadow(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_shadow_base *shadow, KisLayerStyleFilterEnvironment *env) const; private: const Mode m_mode; }; #endif diff --git a/libs/image/layerstyles/kis_ls_overlay_filter.cpp b/libs/image/layerstyles/kis_ls_overlay_filter.cpp index d5a4db2e74..9a424b9ec9 100644 --- a/libs/image/layerstyles/kis_ls_overlay_filter.cpp +++ b/libs/image/layerstyles/kis_ls_overlay_filter.cpp @@ -1,129 +1,131 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_ls_overlay_filter.h" #include #include #include #include #include "psd.h" #include "kis_convolution_kernel.h" #include "kis_convolution_painter.h" #include "kis_gaussian_kernel.h" #include "kis_pixel_selection.h" #include "kis_fill_painter.h" #include "kis_gradient_painter.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "kis_psd_layer_style.h" #include "kis_layer_style_filter_environment.h" #include "kis_ls_utils.h" #include "kis_multiple_projection.h" KisLsOverlayFilter::KisLsOverlayFilter(Mode mode) : KisLayerStyleFilter(KoID("lsoverlay", i18n("Overlay (style)"))), m_mode(mode) { } KisLsOverlayFilter::KisLsOverlayFilter(const KisLsOverlayFilter &rhs) : KisLayerStyleFilter(rhs), m_mode(rhs.m_mode) { } KisLayerStyleFilter *KisLsOverlayFilter::clone() const { return new KisLsOverlayFilter(*this); } void KisLsOverlayFilter::applyOverlay(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_overlay_base *config, KisLayerStyleFilterEnvironment *env) const { if (applyRect.isEmpty()) return; const QString compositeOp = config->blendMode(); const quint8 opacityU8 = quint8(qRound(255.0 / 100.0 * config->opacity())); KisPaintDeviceSP dstDevice = dst->getProjection(KisMultipleProjection::defaultProjectionId(), compositeOp, opacityU8, QBitArray(), srcDevice); KisLsUtils::fillOverlayDevice(dstDevice, applyRect, config, env); } const psd_layer_effects_overlay_base* KisLsOverlayFilter::getOverlayStruct(KisPSDLayerStyleSP style) const { const psd_layer_effects_overlay_base *config = 0; if (m_mode == Color) { config = style->colorOverlay(); } else if (m_mode == Gradient) { config = style->gradientOverlay(); } else if (m_mode == Pattern) { config = style->patternOverlay(); } return config; } void KisLsOverlayFilter::processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { Q_UNUSED(env); + Q_UNUSED(blower); KIS_ASSERT_RECOVER_RETURN(style); const psd_layer_effects_overlay_base *config = getOverlayStruct(style); if (!KisLsUtils::checkEffectEnabled(config, dst)) return; applyOverlay(src, dst, applyRect, config, env); } QRect KisLsOverlayFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { Q_UNUSED(style); Q_UNUSED(env); return rect; } QRect KisLsOverlayFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { Q_UNUSED(style); Q_UNUSED(env); return rect; } diff --git a/libs/image/layerstyles/kis_ls_overlay_filter.h b/libs/image/layerstyles/kis_ls_overlay_filter.h index d7c4b8d7ed..73a624831c 100644 --- a/libs/image/layerstyles/kis_ls_overlay_filter.h +++ b/libs/image/layerstyles/kis_ls_overlay_filter.h @@ -1,68 +1,69 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LS_OVERLAY_FILTER_H #define KIS_LS_OVERLAY_FILTER_H #include #include "kis_layer_style_filter.h" #include struct psd_layer_effects_overlay_base; class KRITAIMAGE_EXPORT KisLsOverlayFilter : public KisLayerStyleFilter { public: enum Mode { Color, Gradient, Pattern }; public: KisLsOverlayFilter(Mode mode); KisLayerStyleFilter* clone() const override; void processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect neededRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect changedRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; private: KisLsOverlayFilter(const KisLsOverlayFilter &rhs); const psd_layer_effects_overlay_base* getOverlayStruct(KisPSDLayerStyleSP style) const; void applyOverlay(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_overlay_base *config, KisLayerStyleFilterEnvironment *env) const; private: Mode m_mode; }; #endif diff --git a/libs/image/layerstyles/kis_ls_satin_filter.cpp b/libs/image/layerstyles/kis_ls_satin_filter.cpp index cc557cda2c..90887601fe 100644 --- a/libs/image/layerstyles/kis_ls_satin_filter.cpp +++ b/libs/image/layerstyles/kis_ls_satin_filter.cpp @@ -1,226 +1,228 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_ls_satin_filter.h" #include #include #include #include "psd.h" #include "kis_convolution_kernel.h" #include "kis_convolution_painter.h" #include "kis_gaussian_kernel.h" #include "kis_pixel_selection.h" #include "kis_fill_painter.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "kis_psd_layer_style.h" #include "kis_multiple_projection.h" #include "kis_ls_utils.h" #include "kis_layer_style_filter_environment.h" #include "kis_cached_paint_device.h" KisLsSatinFilter::KisLsSatinFilter() : KisLayerStyleFilter(KoID("lssatin", i18n("Satin (style)"))) { } KisLsSatinFilter::KisLsSatinFilter(const KisLsSatinFilter &rhs) : KisLayerStyleFilter(rhs) { } KisLayerStyleFilter *KisLsSatinFilter::clone() const { return new KisLsSatinFilter(*this); } struct SatinRectsData { enum Direction { NEED_RECT, CHANGE_RECT }; SatinRectsData(const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_satin *shadow, Direction direction) { Q_UNUSED(direction); blur_size = shadow->size(); offset = shadow->calculateOffset(context); // need rect calculation in reverse order dstRect = applyRect; srcRect = dstRect; int xGrow = qAbs(offset.x()); int yGrow = qAbs(offset.y()); satinNeedRect = srcRect.adjusted(-xGrow, -yGrow, xGrow, yGrow); blurNeedRect = blur_size ? KisLsUtils::growRectFromRadius(satinNeedRect, blur_size) : satinNeedRect; } inline QRect finalNeedRect() const { return blurNeedRect; } inline QRect finalChangeRect() const { // TODO: is it correct? return blurNeedRect; } qint32 blur_size; QPoint offset; QRect srcRect; QRect dstRect; QRect satinNeedRect; QRect blurNeedRect; }; void blendAndOffsetSatinSelection(KisPixelSelectionSP dstSelection, KisPixelSelectionSP srcSelection, const bool invert, const QPoint &offset, const QRect &applyRect) { KisSequentialIterator srcIt1(srcSelection, applyRect.translated(offset)); KisSequentialIterator srcIt2(srcSelection, applyRect.translated(-offset)); KisSequentialIterator dstIt(dstSelection, applyRect); while(dstIt.nextPixel() && srcIt1.nextPixel() && srcIt2.nextPixel()) { quint8 *dstPixelPtr = dstIt.rawData(); quint8 *src1PixelPtr = srcIt1.rawData(); quint8 *src2PixelPtr = srcIt2.rawData(); if (!invert) { *dstPixelPtr = qAbs(*src1PixelPtr - *src2PixelPtr); } else { *dstPixelPtr = (255 - qAbs(*src1PixelPtr - *src2PixelPtr)); } } } //#include "kis_paint_device_debug_utils.h" void KisLsSatinFilter::applySatin(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_satin *config, KisLayerStyleFilterEnvironment *env) const { if (applyRect.isEmpty()) return; SatinRectsData d(applyRect, context, config, SatinRectsData::NEED_RECT); KisCachedSelection::Guard s1(*env->cachedSelection()); KisSelectionSP baseSelection = s1.selection(); KisLsUtils::selectionFromAlphaChannel(srcDevice, baseSelection, d.blurNeedRect); KisPixelSelectionSP selection = baseSelection->pixelSelection(); KisCachedSelection::Guard s2(*env->cachedSelection()); KisPixelSelectionSP tempSelection = s2.selection()->pixelSelection(); tempSelection->makeCloneFromRough(selection, selection->selectedRect()); //KIS_DUMP_DEVICE_2(tempSelection, QRect(0,0,64,64), "00_selection", "dd"); KisLsUtils::applyGaussianWithTransaction(tempSelection, d.satinNeedRect, d.blur_size); //KIS_DUMP_DEVICE_2(tempSelection, QRect(0,0,64,64), "01_gauss", "dd"); /** * Contour correction */ KisLsUtils::applyContourCorrection(tempSelection, d.satinNeedRect, config->contourLookupTable(), config->antiAliased(), config->edgeHidden()); //KIS_DUMP_DEVICE_2(tempSelection, QRect(0,0,64,64), "02_contour", "dd"); blendAndOffsetSatinSelection(selection, tempSelection, config->invert(), d.offset, d.dstRect); //KIS_DUMP_DEVICE_2(selection, QRect(0,0,64,64), "03_blended", "dd"); KisLsUtils::applyFinalSelection(KisMultipleProjection::defaultProjectionId(), baseSelection, srcDevice, dst, d.srcRect, d.dstRect, context, config, env); } void KisLsSatinFilter::processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { + Q_UNUSED(blower); KIS_ASSERT_RECOVER_RETURN(style); const psd_layer_effects_satin *config = style->satin(); if (!KisLsUtils::checkEffectEnabled(config, dst)) return; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); applySatin(src, dst, applyRect, style->context(), w.config, env); } QRect KisLsSatinFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_satin *config = style->satin(); if (!config->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); SatinRectsData d(rect, style->context(), w.config, SatinRectsData::NEED_RECT); return rect | d.finalNeedRect(); } QRect KisLsSatinFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_satin *config = style->satin(); if (!config->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); SatinRectsData d(rect, style->context(), w.config, SatinRectsData::CHANGE_RECT); return style->context()->keep_original ? d.finalChangeRect() : rect | d.finalChangeRect(); } diff --git a/libs/image/layerstyles/kis_ls_satin_filter.h b/libs/image/layerstyles/kis_ls_satin_filter.h index 056429726a..205eac0335 100644 --- a/libs/image/layerstyles/kis_ls_satin_filter.h +++ b/libs/image/layerstyles/kis_ls_satin_filter.h @@ -1,57 +1,58 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LS_SATIN_FILTER_H #define KIS_LS_SATIN_FILTER_H #include #include "kis_layer_style_filter.h" #include class KRITAIMAGE_EXPORT KisLsSatinFilter : public KisLayerStyleFilter { public: KisLsSatinFilter(); KisLayerStyleFilter* clone() const override; void processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect neededRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect changedRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; private: KisLsSatinFilter(const KisLsSatinFilter &rhs); void applySatin(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &applyRect, const psd_layer_effects_context *context, const psd_layer_effects_satin *config, KisLayerStyleFilterEnvironment *env) const; }; #endif diff --git a/libs/image/layerstyles/kis_ls_stroke_filter.cpp b/libs/image/layerstyles/kis_ls_stroke_filter.cpp index 38cf9eba89..5d6f4bf002 100644 --- a/libs/image/layerstyles/kis_ls_stroke_filter.cpp +++ b/libs/image/layerstyles/kis_ls_stroke_filter.cpp @@ -1,172 +1,174 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_ls_stroke_filter.h" #include #include #include #include #include "psd.h" #include "kis_convolution_kernel.h" #include "kis_convolution_painter.h" #include "kis_gaussian_kernel.h" #include "kis_pixel_selection.h" #include "kis_fill_painter.h" #include "kis_gradient_painter.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "kis_psd_layer_style.h" #include "kis_layer_style_filter_environment.h" #include "kis_ls_utils.h" #include "kis_multiple_projection.h" #include "kis_cached_paint_device.h" #include "krita_utils.h" +#include "KisLayerStyleKnockoutBlower.h" + namespace { int borderSize(psd_stroke_position position, int size) { int border = 0; switch (position) { case psd_stroke_outside: border = size + 1; break; case psd_stroke_center: border = qCeil(0.5 * size) + 1; break; case psd_stroke_inside: border = 1; break; } return border; } } KisLsStrokeFilter::KisLsStrokeFilter() : KisLayerStyleFilter(KoID("lsstroke", i18n("Stroke (style)"))) { } KisLsStrokeFilter::KisLsStrokeFilter(const KisLsStrokeFilter &rhs) : KisLayerStyleFilter(rhs) { } KisLayerStyleFilter *KisLsStrokeFilter::clone() const { return new KisLsStrokeFilter(*this); } void KisLsStrokeFilter::applyStroke(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, const psd_layer_effects_stroke *config, KisLayerStyleFilterEnvironment *env) const { if (applyRect.isEmpty()) return; const QRect needRect = kisGrowRect(applyRect, borderSize(config->position(), config->size())); - KisCachedSelection::Guard s1(*env->cachedSelection()); - KisSelectionSP baseSelection = s1.selection(); + KisSelectionSP baseSelection = blower->knockoutSelection(); + if (!baseSelection) { + baseSelection = new KisSelection(new KisSelectionEmptyBounds(0)); + blower->setKnockoutSelection(baseSelection); + } KisLsUtils::selectionFromAlphaChannel(srcDevice, baseSelection, needRect); KisPixelSelectionSP selection = baseSelection->pixelSelection(); // KritaUtils::filterAlpha8Device(selection, needRect, // [](quint8 pixel) { // return pixel > 0 ? 255 : 0; // }); // KisGaussianKernel::applyGaussian(selection, needRect, 1.0, 1.0, QBitArray(), 0); { KisCachedSelection::Guard s2(*env->cachedSelection()); KisPixelSelectionSP knockOutSelection = s2.selection()->pixelSelection(); knockOutSelection->makeCloneFromRough(selection, needRect); if (config->position() == psd_stroke_outside) { KisGaussianKernel::applyDilate(selection, needRect, config->size(), QBitArray(), 0, true); } else if (config->position() == psd_stroke_inside) { KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, config->size(), QBitArray(), 0, true); } else if (config->position() == psd_stroke_center) { KisGaussianKernel::applyDilate(selection, needRect, 0.5 * config->size(), QBitArray(), 0, true); KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, 0.5 * config->size(), QBitArray(), 0, true); } KisPainter gc(selection); gc.setCompositeOp(COMPOSITE_ERASE); gc.bitBlt(needRect.topLeft(), knockOutSelection, needRect); gc.end(); } - KisCachedPaintDevice::Guard d1(srcDevice, *env->cachedPaintDevice()); - KisPaintDeviceSP fillDevice = d1.device(); - KisLsUtils::fillOverlayDevice(fillDevice, applyRect, config, env); - const QString compositeOp = config->blendMode(); const quint8 opacityU8 = quint8(qRound(255.0 / 100.0 * config->opacity())); KisPaintDeviceSP dstDevice = dst->getProjection(KisMultipleProjection::defaultProjectionId(), compositeOp, opacityU8, QBitArray(), srcDevice); - - KisPainter::copyAreaOptimized(applyRect.topLeft(), fillDevice, dstDevice, applyRect, baseSelection); + KisLsUtils::fillOverlayDevice(dstDevice, applyRect, config, env); } void KisLsStrokeFilter::processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, - const QRect &applyRect, - KisPSDLayerStyleSP style, - KisLayerStyleFilterEnvironment *env) const + KisLayerStyleKnockoutBlower *blower, + const QRect &applyRect, + KisPSDLayerStyleSP style, + KisLayerStyleFilterEnvironment *env) const { Q_UNUSED(env); KIS_ASSERT_RECOVER_RETURN(style); const psd_layer_effects_stroke *config = style->stroke(); if (!KisLsUtils::checkEffectEnabled(config, dst)) return; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); - applyStroke(src, dst, applyRect, w.config, env); + applyStroke(src, dst, blower, applyRect, w.config, env); } QRect KisLsStrokeFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_stroke *config = style->stroke(); if (!config->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); return kisGrowRect(rect, borderSize(w.config->position(), w.config->size())); } QRect KisLsStrokeFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { return neededRect(rect, style, env); } diff --git a/libs/image/layerstyles/kis_ls_stroke_filter.h b/libs/image/layerstyles/kis_ls_stroke_filter.h index 48a9c893ba..a9df43f64f 100644 --- a/libs/image/layerstyles/kis_ls_stroke_filter.h +++ b/libs/image/layerstyles/kis_ls_stroke_filter.h @@ -1,56 +1,58 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_LS_STROKE_FILTER_H #define KIS_LS_STROKE_FILTER_H #include #include #include "kis_layer_style_filter.h" struct psd_layer_effects_stroke; class KRITAIMAGE_EXPORT KisLsStrokeFilter : public KisLayerStyleFilter { public: KisLsStrokeFilter(); KisLayerStyleFilter* clone() const override; void processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect neededRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; QRect changedRect(const QRect & rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const override; private: KisLsStrokeFilter(const KisLsStrokeFilter &rhs); void applyStroke(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, + KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, const psd_layer_effects_stroke *config, KisLayerStyleFilterEnvironment *env) const; }; #endif