GPv3: LineArt: Baking operators

This patch implements all baking operators for LineArt for GPv3.
The old baking operators are renamed with `_legacy_` to
distinguishing both when calling the operator.

Pull Request: https://projects.blender.org/blender/blender/pulls/125079
This commit is contained in:
YimingWu
2024-07-26 15:48:52 +02:00
committed by Falk David
parent 1da83ab046
commit f9810ce99c
10 changed files with 595 additions and 89 deletions

View File

@@ -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

View File

@@ -0,0 +1,533 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edgreasepencil
*/
#include <algorithm>
#include <limits>
#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<const GreasePencilLineartModifierData *>(md);
if (is_first || (lmd->flags & MOD_LINEART_USE_CACHE)) {
info.min_level = std::min<int>(info.min_level, lmd->level_start);
info.max_level = std::max<int>(
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<GreasePencilLineartModifierData *>(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<Object *> 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<GreasePencilLineartModifierData *>(md);
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(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<GreasePencilLineartModifierData *>(md);
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(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<GreasePencilLineartModifierData *>(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<GreasePencilLineartModifierData *>(
md);
lmd->flags |= MOD_LINEART_IS_BAKED;
}
}
}
}
static void lineart_bake_startjob(void *customdata, wmJobWorkerStatus *worker_status)
{
LineartBakeJob *bj = static_cast<LineartBakeJob *>(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<ID *>(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<LineartBakeJob *>(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<LineartBakeJob *>(customdata);
MEM_delete(bj);
}
static int lineart_bake_common(bContext *C,
wmOperator *op,
bool bake_all_targets,
bool do_background)
{
LineartBakeJob *bj = MEM_new<LineartBakeJob>(__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<Scene *>(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<GreasePencilLineartModifierData *>(md);
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(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<ID *>(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);
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -14,6 +14,8 @@
#include "BLI_math_vector.h"
#include "BLI_threads.h"
#include "ED_grease_pencil.hh"
#include <algorithm>
#include <math.h>
@@ -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;

View File

@@ -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);
}

View File

@@ -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<const GreasePencilLineartModifierData *>(md);
if (is_first || (lmd->flags & MOD_LINEART_USE_CACHE)) {
info.min_level = std::min<int>(info.min_level, lmd->level_start);
info.max_level = std::max<int>(
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<GreasePencilLineartModifierData *>(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<GreasePencilLineartModifierData *>(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);