diff --git a/source/blender/editors/grease_pencil/CMakeLists.txt b/source/blender/editors/grease_pencil/CMakeLists.txt index 437c2c109f5..c2d9637c5ae 100644 --- a/source/blender/editors/grease_pencil/CMakeLists.txt +++ b/source/blender/editors/grease_pencil/CMakeLists.txt @@ -14,6 +14,8 @@ set(INC ../../../../extern/curve_fit_nd ../../geometry ../sculpt_paint + ../../gpencil_modifiers_legacy + ../../gpencil_modifiers_legacy/intern/lineart # RNA_prototypes.hh ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -29,6 +31,7 @@ set(SRC intern/grease_pencil_geom.cc intern/grease_pencil_image_render.cc intern/grease_pencil_layers.cc + intern/grease_pencil_lineart.cc intern/grease_pencil_material.cc intern/grease_pencil_ops.cc intern/grease_pencil_primitive.cc diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_lineart.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_lineart.cc new file mode 100644 index 00000000000..6df420d5b00 --- /dev/null +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_lineart.cc @@ -0,0 +1,533 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edgreasepencil + */ + +#include +#include + +#include "BLI_array_utils.hh" +#include "BLI_enumerable_thread_specific.hh" +#include "BLI_kdtree.h" +#include "BLI_listbase.h" +#include "BLI_math_vector.hh" +#include "BLI_offset_indices.hh" +#include "BLI_rect.h" +#include "BLI_stack.hh" +#include "BLI_task.hh" + +#include "BKE_context.hh" +#include "BKE_curves.hh" +#include "BKE_global.hh" +#include "BKE_grease_pencil.hh" +#include "BKE_material.h" +#include "BKE_modifier.hh" +#include "BKE_report.hh" +#include "BKE_scene.hh" + +#include "DNA_curves_types.h" +#include "DNA_modifier_types.h" + +#include "RNA_access.hh" +#include "RNA_define.hh" + +#include "ED_grease_pencil.hh" +#include "ED_view3d.hh" + +#include "DEG_depsgraph.hh" +#include "DEG_depsgraph_query.hh" + +/* For shared legacy cache function, will be removed when v2 is removed. */ +#include "MOD_gpencil_legacy_lineart.h" +#include "MOD_lineart.h" + +namespace blender::ed::greasepencil { + +void get_lineart_modifier_limits(const Object &ob, + blender::ed::greasepencil::LineartLimitInfo &info) +{ + bool is_first = true; + LISTBASE_FOREACH (const ModifierData *, md, &ob.modifiers) { + if (md->type == eModifierType_GreasePencilLineart) { + const auto *lmd = reinterpret_cast(md); + if (is_first || (lmd->flags & MOD_LINEART_USE_CACHE)) { + info.min_level = std::min(info.min_level, lmd->level_start); + info.max_level = std::max( + info.max_level, lmd->use_multiple_levels ? lmd->level_end : lmd->level_start); + info.edge_types |= lmd->edge_types; + info.shadow_selection = std::max(info.shadow_selection, lmd->shadow_selection); + info.silhouette_selection = std::max(info.silhouette_selection, lmd->silhouette_selection); + is_first = false; + } + } + } +} + +void set_lineart_modifier_limits(GreasePencilLineartModifierData &lmd, + const blender::ed::greasepencil::LineartLimitInfo &info, + const bool is_first_lineart) +{ + BLI_assert(lmd.modifier.type == eModifierType_GreasePencilLineart); + if (is_first_lineart || lmd.flags & MOD_LINEART_USE_CACHE) { + lmd.level_start_override = info.min_level; + lmd.level_end_override = info.max_level; + lmd.edge_types_override = info.edge_types; + lmd.shadow_selection_override = info.shadow_selection; + lmd.shadow_use_silhouette_override = info.silhouette_selection; + } + else { + lmd.level_start_override = lmd.level_start; + lmd.level_end_override = lmd.level_end; + lmd.edge_types_override = lmd.edge_types; + lmd.shadow_selection_override = lmd.shadow_selection; + lmd.shadow_use_silhouette_override = lmd.silhouette_selection; + } +} + +GreasePencilLineartModifierData *get_first_lineart_modifier(const Object &ob) +{ + LISTBASE_FOREACH (ModifierData *, i_md, &ob.modifiers) { + if (i_md->type == eModifierType_GreasePencilLineart) { + return reinterpret_cast(i_md); + } + } + return nullptr; +} + +} // namespace blender::ed::greasepencil + +struct LineartBakeJob { + wmWindowManager *wm; + void *owner; + bool *stop, *do_update; + float *progress; + + /* C or ob must have one != nullptr. */ + bContext *C; + blender::Vector objects; + Scene *scene; + Depsgraph *dg; + int frame; + int frame_begin; + int frame_end; + int frame_orig; + int frame_increment; + bool overwrite_frames; +}; + +static bool clear_strokes(Object *ob, ModifierData *md, int frame) +{ + if (md->type != eModifierType_GreasePencilLineart) { + return false; + } + GreasePencilLineartModifierData *lmd = reinterpret_cast(md); + GreasePencil *grease_pencil = reinterpret_cast(ob->data); + + blender::bke::greasepencil::TreeNode *node = grease_pencil->find_node_by_name(lmd->target_layer); + if (!node || !node->is_layer()) { + return false; + } + blender::bke::greasepencil::Layer &layer = node->as_layer(); + + if (layer.start_frame_at(frame) == frame) { + blender::bke::greasepencil::Drawing *drawing = grease_pencil->get_drawing_at(layer, frame); + if (!drawing) { + return false; + } + drawing->strokes_for_write() = {}; + } + + return true; +} + +static bool lineart_mod_is_disabled(Scene *scene, GreasePencilLineartModifierData *md) +{ + BLI_assert(md->modifier.type == eModifierType_GreasePencilLineart); + + /* Toggle on and off the baked flag as we are only interested in if something else is disabling + * it. We can assume that the guard function has already toggled this on for all modifiers that + * are sent here. */ + md->flags &= (~MOD_LINEART_IS_BAKED); + + bool enabled = BKE_modifier_is_enabled( + scene, &md->modifier, eModifierMode_Render | eModifierMode_Realtime); + + md->flags |= MOD_LINEART_IS_BAKED; + + return !enabled; +} + +static bool bake_strokes(Object *ob, + Depsgraph *dg, + LineartCache **lc, + GreasePencilLineartModifierData *md, + int frame, + bool is_first) +{ + /* Modifier data sanity check. */ + if (lineart_mod_is_disabled(DEG_get_evaluated_scene(dg), md)) { + return false; + } + + GreasePencilLineartModifierData *lmd = reinterpret_cast(md); + GreasePencil *grease_pencil = reinterpret_cast(ob->data); + + blender::bke::greasepencil::TreeNode *node = grease_pencil->find_node_by_name(lmd->target_layer); + if (!node || !node->is_layer()) { + return false; + } + blender::bke::greasepencil::Layer &layer = node->as_layer(); + + blender::bke::greasepencil::Drawing *drawing = nullptr; + if (layer.start_frame_at(frame) == frame) { + drawing = grease_pencil->get_drawing_at(layer, frame); + } + else { + drawing = grease_pencil->insert_frame(layer, frame); + } + if (UNLIKELY(!drawing)) { + return false; + } + + LineartCache *local_lc = *lc; + if (!(*lc)) { + MOD_lineart_compute_feature_lines_v3(dg, *lmd, lc, !(ob->dtx & OB_DRAW_IN_FRONT)); + MOD_lineart_destroy_render_data_v3(lmd); + } + else { + if (is_first || !(lmd->flags & MOD_LINEART_USE_CACHE)) { + MOD_lineart_compute_feature_lines_v3(dg, *lmd, &local_lc, !(ob->dtx & OB_DRAW_IN_FRONT)); + MOD_lineart_destroy_render_data_v3(lmd); + } + MOD_lineart_chain_clear_picked_flag(local_lc); + lmd->cache = local_lc; + } + + MOD_lineart_gpencil_generate_v3( + lmd->cache, + ob->object_to_world(), + dg, + *drawing, + lmd->source_type, + lmd->source_object, + lmd->source_collection, + lmd->level_start, + lmd->use_multiple_levels ? lmd->level_end : lmd->level_start, + lmd->target_material ? BKE_object_material_index_get(ob, lmd->target_material) : 0, + lmd->edge_types, + lmd->mask_switches, + lmd->material_mask_bits, + lmd->intersection_mask, + float(lmd->thickness) / 1000.0f, + lmd->opacity, + lmd->shadow_selection, + lmd->silhouette_selection, + lmd->source_vertex_group, + lmd->vgname, + lmd->flags, + lmd->calculation_flags); + + if (!(lmd->flags & MOD_LINEART_USE_CACHE)) { + /* Clear local cache. */ + if (!is_first) { + MOD_lineart_clear_cache(&local_lc); + } + } + + return true; +} + +static bool bake_single_target(LineartBakeJob *bj, Object *ob, int frame) +{ + bool touched = false; + if (G.is_break || ob->type != OB_GREASE_PENCIL) { + return false; + } + + if (bj->overwrite_frames) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_GreasePencilLineart) { + if (clear_strokes(ob, md, frame)) { + touched = true; + } + } + } + } + + blender::ed::greasepencil::LineartLimitInfo info; + blender::ed::greasepencil::get_lineart_modifier_limits(*ob, info); + + LineartCache *lc = nullptr; + bool is_first = true; + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type != eModifierType_GreasePencilLineart) { + continue; + } + GreasePencilLineartModifierData *lmd = reinterpret_cast(md); + blender::ed::greasepencil::set_lineart_modifier_limits(*lmd, info, is_first); + + if (bake_strokes(ob, bj->dg, &lc, lmd, frame, is_first)) { + touched = true; + is_first = false; + } + } + MOD_lineart_clear_cache(&lc); + + return touched; +} + +static void guard_modifiers(LineartBakeJob &bj) +{ + for (const int object : bj.objects.index_range()) { + Object *ob = bj.objects[object]; + + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_GreasePencilLineart) { + GreasePencilLineartModifierData *lmd = reinterpret_cast( + md); + lmd->flags |= MOD_LINEART_IS_BAKED; + } + } + } +} + +static void lineart_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status) +{ + LineartBakeJob *bj = static_cast(customdata); + bj->stop = &worker_status->stop; + bj->do_update = &worker_status->do_update; + bj->progress = &worker_status->progress; + + guard_modifiers(*bj); + + for (int frame = bj->frame_begin; frame <= bj->frame_end; frame += bj->frame_increment) { + + if (G.is_break) { + G.is_break = false; + break; + } + + BKE_scene_frame_set(bj->scene, frame); + BKE_scene_graph_update_for_newframe(bj->dg); + DEG_graph_build_from_view_layer(bj->dg); + + for (const int object : bj->objects.index_range()) { + Object *ob = bj->objects[object]; + if (bake_single_target(bj, ob, frame)) { + DEG_id_tag_update(static_cast(ob->data), ID_RECALC_GEOMETRY); + WM_event_add_notifier(bj->C, NC_GPENCIL | ND_DATA | NA_EDITED, ob); + } + } + + /* Update and refresh the progress bar. */ + *bj->progress = float(frame - bj->frame_begin) / (bj->frame_end - bj->frame_begin); + *bj->do_update = true; + } + + /* This need to be reset manually. */ + G.is_break = false; + + /* Restore original frame. */ + BKE_scene_frame_set(bj->scene, bj->frame_orig); + BKE_scene_graph_update_for_newframe(bj->dg); +} + +static void lineart_bake_endjob(void *customdata) +{ + LineartBakeJob *bj = static_cast(customdata); + + WM_set_locked_interface(CTX_wm_manager(bj->C), false); + + WM_main_add_notifier(NC_SCENE | ND_FRAME, bj->scene); + + for (const int object : bj->objects.index_range()) { + Object *ob = bj->objects[object]; + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, ob); + } +} + +static void lineart_bake_job_free(void *customdata) +{ + LineartBakeJob *bj = static_cast(customdata); + MEM_delete(bj); +} + +static int lineart_bake_common(bContext *C, + wmOperator *op, + bool bake_all_targets, + bool do_background) +{ + LineartBakeJob *bj = MEM_new(__func__); + + if (!bake_all_targets) { + Object *ob = CTX_data_active_object(C); + if (!ob || ob->type != OB_GREASE_PENCIL) { + WM_report(RPT_ERROR, "No active object, or active object isn't a Grease Pencil object"); + return OPERATOR_FINISHED; + } + bj->objects.append(ob); + } + else { + /* #CTX_DATA_BEGIN is not available for iterating in objects while using the job system. */ + CTX_DATA_BEGIN (C, Object *, ob, visible_objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_GreasePencilLineart) { + bj->objects.append(ob); + break; + } + } + } + CTX_DATA_END; + } + bj->C = C; + Scene *scene = CTX_data_scene(C); + bj->scene = scene; + bj->dg = CTX_data_depsgraph_pointer(C); + bj->frame_begin = scene->r.sfra; + bj->frame_end = scene->r.efra; + bj->frame_orig = scene->r.cfra; + bj->frame_increment = scene->r.frame_step; + bj->overwrite_frames = true; + + if (do_background) { + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + "Line Art", + WM_JOB_PROGRESS, + WM_JOB_TYPE_LINEART); + + WM_jobs_customdata_set(wm_job, bj, lineart_bake_job_free); + WM_jobs_timer(wm_job, 0.1, NC_GPENCIL | ND_DATA | NA_EDITED, NC_GPENCIL | ND_DATA | NA_EDITED); + WM_jobs_callbacks(wm_job, lineart_bake_startjob, nullptr, nullptr, lineart_bake_endjob); + + WM_set_locked_interface(CTX_wm_manager(C), true); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + + wmJobWorkerStatus worker_status = {}; + lineart_bake_startjob(bj, &worker_status); + + MEM_delete(bj); + + return OPERATOR_FINISHED; +} + +static int lineart_bake_strokes_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) +{ + bool bake_all = RNA_boolean_get(op->ptr, "bake_all"); + return lineart_bake_common(C, op, bake_all, true); +} +static int lineart_bake_strokes_exec(bContext *C, wmOperator *op) +{ + bool bake_all = RNA_boolean_get(op->ptr, "bake_all"); + return lineart_bake_common(C, op, bake_all, false); +} +static int lineart_bake_strokes_common_modal(bContext *C, + wmOperator *op, + const wmEvent * /*event*/) +{ + Scene *scene = static_cast(op->customdata); + + /* no running blender, remove handler and pass through. */ + if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_LINEART) == 0) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + } + + return OPERATOR_PASS_THROUGH; +} + +static void lineart_gpencil_clear_strokes_exec_common(Object *ob) +{ + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type != eModifierType_GreasePencilLineart) { + continue; + } + GreasePencilLineartModifierData *lmd = reinterpret_cast(md); + GreasePencil *grease_pencil = reinterpret_cast(ob->data); + + blender::bke::greasepencil::TreeNode *node = grease_pencil->find_node_by_name( + lmd->target_layer); + if (!node || !node->is_layer()) { + return; + } + blender::bke::greasepencil::Layer &layer = node->as_layer(); + + /* Remove all the keyframes in this layer. */ + grease_pencil->remove_frames(layer, layer.sorted_keys()); + grease_pencil->insert_frame(layer, 0); + + md->mode |= eModifierMode_Realtime | eModifierMode_Render; + + lmd->flags &= (~MOD_LINEART_IS_BAKED); + } + DEG_id_tag_update(static_cast(ob->data), ID_RECALC_GEOMETRY); +} + +static int lineart_gpencil_clear_strokes_exec(bContext *C, wmOperator *op) +{ + bool clear_all = RNA_boolean_get(op->ptr, "clear_all"); + + if (clear_all) { + CTX_DATA_BEGIN (C, Object *, ob, visible_objects) { + if (ob->type != OB_GREASE_PENCIL) { + continue; + } + lineart_gpencil_clear_strokes_exec_common(ob); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, ob); + } + CTX_DATA_END; + BKE_report(op->reports, RPT_INFO, "All Line Art objects are now cleared of bakes"); + } + else { + Object *ob = CTX_data_active_object(C); + if (ob->type != OB_GREASE_PENCIL) { + return OPERATOR_FINISHED; + } + lineart_gpencil_clear_strokes_exec_common(ob); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, ob); + BKE_report(op->reports, RPT_INFO, "Baked strokes are cleared"); + } + + return OPERATOR_FINISHED; +} + +static void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot) +{ + ot->name = "Bake Line Art"; + ot->description = "Bake Line Art for current Grease Pencil object"; + ot->idname = "OBJECT_OT_lineart_bake_strokes"; + + ot->poll = blender::ed::greasepencil::active_grease_pencil_poll; + ot->invoke = lineart_bake_strokes_invoke; + ot->exec = lineart_bake_strokes_exec; + ot->modal = lineart_bake_strokes_common_modal; + + RNA_def_boolean(ot->srna, "bake_all", false, "Bake All", "Bake all line art modifiers"); +} + +static void OBJECT_OT_lineart_clear(wmOperatorType *ot) +{ + ot->name = "Clear Baked Line Art"; + ot->description = "Clear all strokes in current Grease Pencil object"; + ot->idname = "OBJECT_OT_lineart_clear"; + + ot->poll = blender::ed::greasepencil::active_grease_pencil_poll; + ot->exec = lineart_gpencil_clear_strokes_exec; + + RNA_def_boolean(ot->srna, "clear_all", false, "Clear All", "Clear all line art modifier bakes"); +} + +void ED_operatortypes_grease_pencil_lineart() +{ + WM_operatortype_append(OBJECT_OT_lineart_bake_strokes); + WM_operatortype_append(OBJECT_OT_lineart_clear); +} diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_ops.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_ops.cc index c21f657216c..fe44040e028 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_ops.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_ops.cc @@ -200,6 +200,7 @@ void ED_operatortypes_grease_pencil() ED_operatortypes_grease_pencil_primitives(); ED_operatortypes_grease_pencil_weight_paint(); ED_operatortypes_grease_pencil_interpolate(); + ED_operatortypes_grease_pencil_lineart(); ED_operatortypes_grease_pencil_trace(); } diff --git a/source/blender/editors/include/ED_grease_pencil.hh b/source/blender/editors/include/ED_grease_pencil.hh index 806b5d7c871..dc843297b9f 100644 --- a/source/blender/editors/include/ED_grease_pencil.hh +++ b/source/blender/editors/include/ED_grease_pencil.hh @@ -33,6 +33,7 @@ struct UndoType; struct ViewDepths; struct View3D; struct ViewContext; +struct GreasePencilLineartModifierData; namespace blender { namespace bke { enum class AttrDomain : int8_t; @@ -59,6 +60,7 @@ void ED_operatortypes_grease_pencil_material(); void ED_operatortypes_grease_pencil_primitives(); void ED_operatortypes_grease_pencil_weight_paint(); void ED_operatortypes_grease_pencil_interpolate(); +void ED_operatortypes_grease_pencil_lineart(); void ED_operatortypes_grease_pencil_trace(); void ED_operatormacros_grease_pencil(); void ED_keymap_grease_pencil(wmKeyConfig *keyconf); @@ -655,4 +657,23 @@ bke::CurvesGeometry trim_curve_segments(const bke::CurvesGeometry &src, bool keep_caps); }; // namespace cutter +/* Lineart */ + +/* Stores the maximum calculation range in the whole modifier stack for line art so the cache can + * cover everything that will be visible. */ +struct LineartLimitInfo { + int16_t edge_types; + uint8_t min_level; + uint8_t max_level; + uint8_t shadow_selection; + uint8_t silhouette_selection; +}; + +void get_lineart_modifier_limits(const Object &ob, LineartLimitInfo &info); +void set_lineart_modifier_limits(GreasePencilLineartModifierData &lmd, + const LineartLimitInfo &info, + const bool is_first_lineart); + +GreasePencilLineartModifierData *get_first_lineart_modifier(const Object &ob); + } // namespace blender::ed::greasepencil diff --git a/source/blender/editors/object/object_ops.cc b/source/blender/editors/object/object_ops.cc index 6442e568cbb..7dce20579ce 100644 --- a/source/blender/editors/object/object_ops.cc +++ b/source/blender/editors/object/object_ops.cc @@ -171,7 +171,7 @@ void operatortypes_object() WM_operatortype_append(GPENCIL_OT_time_segment_move); /* grease pencil line art */ - WM_operatortypes_lineart(); + WM_operatortypes_lineart_legacy(); /* Shader FX. */ WM_operatortype_append(OBJECT_OT_shaderfx_add); diff --git a/source/blender/gpencil_modifiers_legacy/MOD_gpencil_legacy_lineart.h b/source/blender/gpencil_modifiers_legacy/MOD_gpencil_legacy_lineart.h index 160ac5a33c4..b5ba12b254b 100644 --- a/source/blender/gpencil_modifiers_legacy/MOD_gpencil_legacy_lineart.h +++ b/source/blender/gpencil_modifiers_legacy/MOD_gpencil_legacy_lineart.h @@ -16,12 +16,12 @@ extern "C" { #endif -void OBJECT_OT_lineart_bake_strokes(struct wmOperatorType *ot); -void OBJECT_OT_lineart_bake_strokes_all(struct wmOperatorType *ot); -void OBJECT_OT_lineart_clear(struct wmOperatorType *ot); -void OBJECT_OT_lineart_clear_all(struct wmOperatorType *ot); +void OBJECT_OT_lineart_legacy_bake_strokes(struct wmOperatorType *ot); +void OBJECT_OT_lineart_legacy_bake_strokes_all(struct wmOperatorType *ot); +void OBJECT_OT_lineart_legacy_clear(struct wmOperatorType *ot); +void OBJECT_OT_lineart_legacy_clear_all(struct wmOperatorType *ot); -void WM_operatortypes_lineart(void); +void WM_operatortypes_lineart_legacy(void); struct LineartCache; diff --git a/source/blender/gpencil_modifiers_legacy/intern/MOD_gpencil_legacy_lineart.cc b/source/blender/gpencil_modifiers_legacy/intern/MOD_gpencil_legacy_lineart.cc index 2e1edf483c2..fef18c4236b 100644 --- a/source/blender/gpencil_modifiers_legacy/intern/MOD_gpencil_legacy_lineart.cc +++ b/source/blender/gpencil_modifiers_legacy/intern/MOD_gpencil_legacy_lineart.cc @@ -763,12 +763,12 @@ static void bake_panel_draw(const bContext * /*C*/, Panel *panel) uiLayout *col = uiLayoutColumn(layout, false); uiLayoutSetEnabled(col, !is_baked); - uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_bake_strokes"); - uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_bake_strokes_all"); + uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_legacy_bake_strokes"); + uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_legacy_bake_strokes_all"); col = uiLayoutColumn(layout, false); - uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_clear"); - uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_clear_all"); + uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_legacy_clear"); + uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_legacy_clear_all"); } static void composition_panel_draw(const bContext * /*C*/, Panel *panel) diff --git a/source/blender/gpencil_modifiers_legacy/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers_legacy/intern/lineart/MOD_lineart.h index 51e4e9791fc..c740ef4c341 100644 --- a/source/blender/gpencil_modifiers_legacy/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers_legacy/intern/lineart/MOD_lineart.h @@ -14,6 +14,8 @@ #include "BLI_math_vector.h" #include "BLI_threads.h" +#include "ED_grease_pencil.hh" + #include #include @@ -423,18 +425,8 @@ typedef struct LineartData { } LineartData; -/* Stores the maximum calculation range in the whole modifier stack for line art so the cache can - * cover everything that will be visible. */ -struct GreasePencilLineartLimitInfo { - int16_t edge_types; - uint8_t min_level; - uint8_t max_level; - uint8_t shadow_selection; - uint8_t silhouette_selection; -}; - typedef struct LineartCache { - GreasePencilLineartLimitInfo LimitInfo; + blender::ed::greasepencil::LineartLimitInfo LimitInfo; /** Separate memory pool for chain data and shadow, this goes to the cache, so when we free the * main pool, chains and shadows will still be available. */ LineartStaticMemPool chain_data_pool; diff --git a/source/blender/gpencil_modifiers_legacy/intern/lineart/lineart_ops.cc b/source/blender/gpencil_modifiers_legacy/intern/lineart/lineart_ops.cc index 8686419d0bb..b5ccd2a94ec 100644 --- a/source/blender/gpencil_modifiers_legacy/intern/lineart/lineart_ops.cc +++ b/source/blender/gpencil_modifiers_legacy/intern/lineart/lineart_ops.cc @@ -434,50 +434,50 @@ static int lineart_gpencil_clear_strokes_all_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot) +void OBJECT_OT_lineart_legacy_bake_strokes(wmOperatorType *ot) { ot->name = "Bake Line Art"; ot->description = "Bake Line Art for current Grease Pencil object"; - ot->idname = "OBJECT_OT_lineart_bake_strokes"; + ot->idname = "OBJECT_OT_lineart_legacy_bake_strokes"; ot->invoke = lineart_gpencil_bake_strokes_invoke; ot->exec = lineart_gpencil_bake_strokes_exec; ot->modal = lineart_gpencil_bake_strokes_common_modal; } -void OBJECT_OT_lineart_bake_strokes_all(wmOperatorType *ot) +void OBJECT_OT_lineart_legacy_bake_strokes_all(wmOperatorType *ot) { ot->name = "Bake Line Art (All)"; ot->description = "Bake all Grease Pencil objects that have a Line Art modifier"; - ot->idname = "OBJECT_OT_lineart_bake_strokes_all"; + ot->idname = "OBJECT_OT_lineart_legacy_bake_strokes_all"; ot->invoke = lineart_gpencil_bake_strokes_all_invoke; ot->exec = lineart_gpencil_bake_strokes_all_exec; ot->modal = lineart_gpencil_bake_strokes_common_modal; } -void OBJECT_OT_lineart_clear(wmOperatorType *ot) +void OBJECT_OT_lineart_legacy_clear(wmOperatorType *ot) { ot->name = "Clear Baked Line Art"; ot->description = "Clear all strokes in current Grease Pencil object"; - ot->idname = "OBJECT_OT_lineart_clear"; + ot->idname = "OBJECT_OT_lineart_legacy_clear"; ot->exec = lineart_gpencil_clear_strokes_exec; } -void OBJECT_OT_lineart_clear_all(wmOperatorType *ot) +void OBJECT_OT_lineart_legacy_clear_all(wmOperatorType *ot) { ot->name = "Clear Baked Line Art (All)"; ot->description = "Clear all strokes in all Grease Pencil objects that have a Line Art modifier"; - ot->idname = "OBJECT_OT_lineart_clear_all"; + ot->idname = "OBJECT_OT_lineart_legacy_clear_all"; ot->exec = lineart_gpencil_clear_strokes_all_exec; } -void WM_operatortypes_lineart() +void WM_operatortypes_lineart_legacy() { - WM_operatortype_append(OBJECT_OT_lineart_bake_strokes); - WM_operatortype_append(OBJECT_OT_lineart_bake_strokes_all); - WM_operatortype_append(OBJECT_OT_lineart_clear); - WM_operatortype_append(OBJECT_OT_lineart_clear_all); + WM_operatortype_append(OBJECT_OT_lineart_legacy_bake_strokes); + WM_operatortype_append(OBJECT_OT_lineart_legacy_bake_strokes_all); + WM_operatortype_append(OBJECT_OT_lineart_legacy_clear); + WM_operatortype_append(OBJECT_OT_lineart_legacy_clear_all); } diff --git a/source/blender/modifiers/intern/MOD_lineart.cc b/source/blender/modifiers/intern/MOD_lineart.cc index e788f5aec63..c0cacc6d68f 100644 --- a/source/blender/modifiers/intern/MOD_lineart.cc +++ b/source/blender/modifiers/intern/MOD_lineart.cc @@ -37,48 +37,10 @@ #include "DEG_depsgraph_query.hh" +#include "ED_grease_pencil.hh" + namespace blender { -static void get_lineart_modifier_limits(const Object &ob, GreasePencilLineartLimitInfo &info) -{ - bool is_first = true; - LISTBASE_FOREACH (const ModifierData *, md, &ob.modifiers) { - if (md->type == eModifierType_GreasePencilLineart) { - const auto *lmd = reinterpret_cast(md); - if (is_first || (lmd->flags & MOD_LINEART_USE_CACHE)) { - info.min_level = std::min(info.min_level, lmd->level_start); - info.max_level = std::max( - info.max_level, lmd->use_multiple_levels ? lmd->level_end : lmd->level_start); - info.edge_types |= lmd->edge_types; - info.shadow_selection = std::max(info.shadow_selection, lmd->shadow_selection); - info.silhouette_selection = std::max(info.silhouette_selection, lmd->silhouette_selection); - is_first = false; - } - } - } -} - -static void set_lineart_modifier_limits(GreasePencilLineartModifierData &lmd, - const GreasePencilLineartLimitInfo &info, - const bool is_first_lineart) -{ - BLI_assert(lmd.modifier.type == eModifierType_GreasePencilLineart); - if (is_first_lineart || lmd.flags & MOD_LINEART_USE_CACHE) { - lmd.level_start_override = info.min_level; - lmd.level_end_override = info.max_level; - lmd.edge_types_override = info.edge_types; - lmd.shadow_selection_override = info.shadow_selection; - lmd.shadow_use_silhouette_override = info.silhouette_selection; - } - else { - lmd.level_start_override = lmd.level_start; - lmd.level_end_override = lmd.level_end; - lmd.edge_types_override = lmd.edge_types; - lmd.shadow_selection_override = lmd.shadow_selection; - lmd.shadow_use_silhouette_override = lmd.silhouette_selection; - } -} - static bool is_first_lineart(const GreasePencilLineartModifierData &md) { if (md.modifier.type != eModifierType_GreasePencilLineart) { @@ -109,16 +71,6 @@ static bool is_last_line_art(const GreasePencilLineartModifierData &md) return true; } -static GreasePencilLineartModifierData *get_first_lineart_modifier(const Object &ob) -{ - LISTBASE_FOREACH (ModifierData *, i_md, &ob.modifiers) { - if (i_md->type == eModifierType_GreasePencilLineart) { - return reinterpret_cast(i_md); - } - } - return nullptr; -} - static void init_data(ModifierData *md) { GreasePencilLineartModifierData *gpmd = (GreasePencilLineartModifierData *)md; @@ -693,11 +645,13 @@ static void bake_panel_draw(const bContext * /*C*/, Panel *panel) uiLayout *col = uiLayoutColumn(layout, false); uiLayoutSetEnabled(col, !is_baked); uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_bake_strokes"); - uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_bake_strokes_all"); + uiItemBooleanO( + col, IFACE_("Bake All"), ICON_NONE, "OBJECT_OT_lineart_bake_strokes", "bake_all", true); col = uiLayoutColumn(layout, false); uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_clear"); - uiItemO(col, nullptr, ICON_NONE, "OBJECT_OT_lineart_clear_all"); + uiItemBooleanO( + col, IFACE_("Clear All"), ICON_NONE, "OBJECT_OT_lineart_clear", "clear_all", true); } static void composition_panel_draw(const bContext * /*C*/, Panel *panel) @@ -848,16 +802,18 @@ static void modify_geometry_set(ModifierData *md, GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write(); auto mmd = reinterpret_cast(md); - GreasePencilLineartModifierData *first_lineart = get_first_lineart_modifier(*ctx->object); + GreasePencilLineartModifierData *first_lineart = + blender::ed::greasepencil::get_first_lineart_modifier(*ctx->object); BLI_assert(first_lineart); bool is_first_lineart = (mmd == first_lineart); if (is_first_lineart) { mmd->shared_cache = MOD_lineart_init_cache(); - get_lineart_modifier_limits(*ctx->object, mmd->shared_cache->LimitInfo); + ed::greasepencil::get_lineart_modifier_limits(*ctx->object, mmd->shared_cache->LimitInfo); } - set_lineart_modifier_limits(*mmd, first_lineart->shared_cache->LimitInfo, is_first_lineart); + ed::greasepencil::set_lineart_modifier_limits( + *mmd, first_lineart->shared_cache->LimitInfo, is_first_lineart); generate_strokes(*md, *ctx, grease_pencil, *first_lineart);