This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
YimingWu 6f7e632a6f Cleanup, LineArt: Sample -> Resample
Clear up what sample length does by renaming the option and variables.
2021-03-18 13:20:44 +01:00

441 lines
13 KiB
C

/*
* 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.
*
* The Original Code is Copyright (C) 2019 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup editors
*/
#include <stdlib.h>
#include "MEM_guardedalloc.h"
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
#include "BLI_utildefines.h"
#include "WM_api.h"
#include "WM_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "UI_resources.h"
#include "MOD_gpencil_lineart.h"
#include "MOD_lineart.h"
#include "lineart_intern.h"
static void clear_strokes(Object *ob, GpencilModifierData *md, int frame)
{
if (md->type != eGpencilModifierType_Lineart) {
return;
}
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
bGPdata *gpd = ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
if (!gpl) {
return;
}
bGPDframe *gpf = BKE_gpencil_layer_frame_find(gpl, frame);
if (!gpf) {
/* No greasepencil frame found. */
return;
}
BKE_gpencil_layer_frame_delete(gpl, gpf);
}
static bool bake_strokes(Object *ob, Depsgraph *dg, GpencilModifierData *md, int frame)
{
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
bGPdata *gpd = ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
if (!gpl) {
return false;
}
bool only_use_existing_gp_frames = false;
bGPDframe *gpf = (only_use_existing_gp_frames ?
BKE_gpencil_layer_frame_find(gpl, frame) :
BKE_gpencil_layer_frame_get(gpl, frame, GP_GETFRAME_ADD_NEW));
if (!gpf) {
/* No greasepencil frame created or found. */
return false;
}
MOD_lineart_compute_feature_lines(dg, lmd);
MOD_lineart_gpencil_generate(
lmd->render_buffer,
dg,
ob,
gpl,
gpf,
lmd->source_type,
lmd->source_type == LRT_SOURCE_OBJECT ? (void *)lmd->source_object :
(void *)lmd->source_collection,
lmd->level_start,
lmd->use_multiple_levels ? lmd->level_end : lmd->level_start,
lmd->target_material ? BKE_gpencil_object_material_index_get(ob, lmd->target_material) : 0,
lmd->edge_types,
lmd->transparency_flags,
lmd->transparency_mask,
lmd->thickness,
lmd->opacity,
lmd->resample_length,
lmd->source_vertex_group,
lmd->vgname,
lmd->flags);
MOD_lineart_destroy_render_data(lmd);
return true;
}
typedef struct LineartBakeJob {
wmWindowManager *wm;
void *owner;
short *stop, *do_update;
float *progress;
/* C or ob must have one != NULL. */
bContext *C;
LinkNode *objects;
Scene *scene;
Depsgraph *dg;
int frame;
int frame_begin;
int frame_end;
int frame_orig;
int frame_increment;
bool overwrite_frames;
} LineartBakeJob;
static bool lineart_gpencil_bake_single_target(LineartBakeJob *bj, Object *ob, int frame)
{
bool touched = false;
if (ob->type != OB_GPENCIL || G.is_break) {
return false;
}
if (bj->overwrite_frames) {
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
clear_strokes(ob, md, frame);
}
}
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (bake_strokes(ob, bj->dg, md, frame)) {
touched = true;
}
}
return touched;
}
static void lineart_gpencil_guard_modifiers(LineartBakeJob *bj)
{
for (LinkNode *l = bj->objects; l; l = l->next) {
Object *ob = l->link;
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (md->type == eGpencilModifierType_Lineart) {
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
lmd->flags |= LRT_GPENCIL_IS_BAKED;
}
}
}
}
static void lineart_gpencil_bake_startjob(void *customdata,
short *stop,
short *do_update,
float *progress)
{
LineartBakeJob *bj = (LineartBakeJob *)customdata;
bj->stop = stop;
bj->do_update = do_update;
bj->progress = progress;
lineart_gpencil_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);
for (LinkNode *l = bj->objects; l; l = l->next) {
Object *ob = l->link;
if (lineart_gpencil_bake_single_target(bj, ob, frame)) {
DEG_id_tag_update((struct 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_gpencil_bake_endjob(void *customdata)
{
LineartBakeJob *bj = customdata;
WM_set_locked_interface(CTX_wm_manager(bj->C), false);
WM_main_add_notifier(NC_SCENE | ND_FRAME, bj->scene);
for (LinkNode *l = bj->objects; l; l = l->next) {
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, (Object *)l->link);
}
BLI_linklist_free(bj->objects, NULL);
}
static int lineart_gpencil_bake_common(bContext *C,
wmOperator *op,
bool bake_all_targets,
bool do_background)
{
LineartBakeJob *bj = MEM_callocN(sizeof(LineartBakeJob), "LineartBakeJob");
if (!bake_all_targets) {
Object *ob = CTX_data_active_object(C);
if (!ob || ob->type != OB_GPENCIL) {
WM_report(RPT_ERROR, "No active object or active object isn't a GPencil object.");
return OPERATOR_FINISHED;
}
BLI_linklist_prepend(&bj->objects, ob);
}
else {
/* CTX_DATA_BEGIN is not available for interating in objects while using the Job system. */
CTX_DATA_BEGIN (C, Object *, ob, visible_objects) {
if (ob->type == OB_GPENCIL) {
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (md->type == eGpencilModifierType_Lineart) {
BLI_linklist_prepend(&bj->objects, ob);
}
}
}
}
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, MEM_freeN);
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_gpencil_bake_startjob, NULL, NULL, lineart_gpencil_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;
}
float pseduo_progress;
short pseduo_do_update;
lineart_gpencil_bake_startjob(bj, NULL, &pseduo_do_update, &pseduo_progress);
BLI_linklist_free(bj->objects, NULL);
MEM_freeN(bj);
return OPERATOR_FINISHED;
}
static int lineart_gpencil_bake_strokes_all_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
return lineart_gpencil_bake_common(C, op, true, true);
}
static int lineart_gpencil_bake_strokes_all_exec(bContext *C, wmOperator *op)
{
return lineart_gpencil_bake_common(C, op, true, false);
}
static int lineart_gpencil_bake_strokes_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
return lineart_gpencil_bake_common(C, op, false, true);
}
static int lineart_gpencil_bake_strokes_exec(bContext *C, wmOperator *op)
{
return lineart_gpencil_bake_common(C, op, false, false);
return OPERATOR_FINISHED;
}
static int lineart_gpencil_bake_strokes_commom_modal(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
Scene *scene = (Scene *)op->customdata;
/* no running blender, remove handler and pass through. */
if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_LINEART)) {
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
return OPERATOR_PASS_THROUGH;
}
static void lineart_gpencil_clear_strokes_exec_common(Object *ob)
{
if (ob->type != OB_GPENCIL) {
return;
}
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (md->type != eGpencilModifierType_Lineart) {
continue;
}
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md;
bGPdata *gpd = ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_get_by_name(gpd, lmd->target_layer, 1);
if (!gpl) {
continue;
}
BKE_gpencil_free_frames(gpl);
BKE_gpencil_frame_addnew(gpl, 0);
md->mode |= eGpencilModifierMode_Realtime | eGpencilModifierMode_Render;
lmd->flags &= (~LRT_GPENCIL_IS_BAKED);
}
DEG_id_tag_update((struct ID *)ob->data, ID_RECALC_GEOMETRY);
}
static int lineart_gpencil_clear_strokes_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
lineart_gpencil_clear_strokes_exec_common(ob);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, ob);
return OPERATOR_FINISHED;
}
static int lineart_gpencil_clear_strokes_all_exec(bContext *C, wmOperator *op)
{
CTX_DATA_BEGIN (C, Object *, ob, visible_objects) {
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.");
return OPERATOR_FINISHED;
}
/* Bake all line art modifiers on the current object. */
void OBJECT_OT_lineart_bake_strokes(wmOperatorType *ot)
{
ot->name = "Bake Line Art";
ot->description = "Bake Line Art for current GPencil object";
ot->idname = "OBJECT_OT_lineart_bake_strokes";
ot->invoke = lineart_gpencil_bake_strokes_invoke;
ot->exec = lineart_gpencil_bake_strokes_exec;
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
/* Bake all lineart objects in the scene. */
void OBJECT_OT_lineart_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->invoke = lineart_gpencil_bake_strokes_all_invoke;
ot->exec = lineart_gpencil_bake_strokes_all_exec;
ot->modal = lineart_gpencil_bake_strokes_commom_modal;
}
/* clear all line art modifiers on the current object. */
void OBJECT_OT_lineart_clear(wmOperatorType *ot)
{
ot->name = "Clear Baked Line Art";
ot->description = "Clear all strokes in current GPencil obejct";
ot->idname = "OBJECT_OT_lineart_clear";
ot->exec = lineart_gpencil_clear_strokes_exec;
}
/* clear all lineart objects in the scene. */
void OBJECT_OT_lineart_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->exec = lineart_gpencil_clear_strokes_all_exec;
}
void WM_operatortypes_lineart(void)
{
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);
}