Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c')
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
new file mode 100644
index 00000000000..9a0ee4d9d92
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c
@@ -0,0 +1,342 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_defaults.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_modifier.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_ui_common.h"
+#include "MOD_gpencil_util.h"
+
+static void initData(GpencilModifierData *md)
+{
+ OutlineGpencilModifierData *gpmd = (OutlineGpencilModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(OutlineGpencilModifierData), modifier);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+static void free_old_strokes(Depsgraph *depsgraph, Object *ob, bGPdata *gpd)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ /* Free old strokes. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+ if (gpf == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_TAG) {
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+ }
+ }
+ }
+}
+
+static void convert_stroke(GpencilModifierData *md,
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ float viewmat[4][4],
+ float diff_mat[4][4])
+{
+ OutlineGpencilModifierData *mmd = (OutlineGpencilModifierData *)md;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool keep = (mmd->flag & GP_OUTLINE_KEEP_SHAPE) != 0;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->material,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_OUTLINE_INVERT_LAYER,
+ mmd->flag & GP_OUTLINE_INVERT_PASS,
+ mmd->flag & GP_OUTLINE_INVERT_LAYERPASS,
+ mmd->flag & GP_OUTLINE_INVERT_MATERIAL)) {
+ return;
+ }
+
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ const bool is_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
+ /* Only strokes type, no fill strokes. */
+ if (!is_stroke) {
+ return;
+ }
+
+ /* Duplicate the stroke to apply any layer thickness change. */
+ bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false);
+
+ /* Apply layer thickness change. */
+ gps_duplicate->thickness += gpl->line_change;
+ /* Apply object scale to thickness. */
+ gps_duplicate->thickness *= mat4_to_scale(ob->obmat);
+ CLAMP_MIN(gps_duplicate->thickness, 1.0f);
+
+ /* Stroke. */
+ const float ovr_thickness = keep ? mmd->thickness : 0.0f;
+ bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
+ viewmat, gpd, gpl, gps_duplicate, mmd->subdiv, diff_mat, ovr_thickness);
+ gps_perimeter->flag &= ~GP_STROKE_SELECT;
+ gps_perimeter->runtime.gps_orig = gps->runtime.gps_orig;
+
+ /* Assign material. */
+ if (mmd->outline_material) {
+ Material *ma = mmd->outline_material;
+ int mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob, ma->id.name + 2);
+ if (mat_idx > -1) {
+ gps_perimeter->mat_nr = mat_idx;
+ }
+ else {
+ gps_perimeter->mat_nr = gps->mat_nr;
+ }
+ }
+ else {
+ gps_perimeter->mat_nr = gps->mat_nr;
+ }
+
+ /* Sample stroke. */
+ if (mmd->sample_length > 0.0f) {
+ BKE_gpencil_stroke_sample(gpd, gps_perimeter, mmd->sample_length, false, 0);
+ }
+ /* Set stroke thickness. */
+ gps_perimeter->thickness = mmd->thickness;
+
+ /* Set pressure constant. */
+ int orig_idx = -1;
+ float min_distance = FLT_MAX;
+ bGPDspoint *pt;
+ for (int i = 0; i < gps_perimeter->totpoints; i++) {
+ pt = &gps_perimeter->points[i];
+ pt->pressure = 1.0f;
+ pt->runtime.pt_orig = NULL;
+ /* If any target object is defined, find the nearest point. */
+ if (mmd->object) {
+ float wpt[3];
+ mul_v3_m4v3(wpt, diff_mat, &pt->x);
+ float dist = len_squared_v3v3(wpt, mmd->object->loc);
+ if (dist < min_distance) {
+ min_distance = dist;
+ orig_idx = i;
+ }
+ }
+ }
+
+ if (orig_idx > 0) {
+ BKE_gpencil_stroke_start_set(gps_perimeter, orig_idx);
+ BKE_gpencil_stroke_geometry_update(gpd, gps_perimeter);
+ }
+
+ /* Add perimeter stroke to frame. */
+ BLI_insertlinkafter(&gpf->strokes, gps, gps_perimeter);
+
+ /* Free Temp stroke. */
+ BKE_gpencil_free_stroke(gps_duplicate);
+
+ /* Tag original stroke to be removed. */
+ gps->flag |= GP_STROKE_TAG;
+}
+
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ /* Calc camera view matrix. */
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ /* Ensure the camera is the right one. */
+ BKE_scene_camera_switch_update(scene);
+
+ if (!scene->camera) {
+ return;
+ }
+ Object *cam_ob = scene->camera;
+ float viewmat[4][4];
+ invert_m4_m4(viewmat, cam_ob->obmat);
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+ if (gpf == NULL) {
+ continue;
+ }
+ /* Prepare transform matrix. */
+ float diff_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
+
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat);
+ }
+ }
+
+ /* Delete original strokes. */
+ free_old_strokes(depsgraph, ob, gpd);
+}
+
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ /* Calc camera view matrix. */
+ if (!scene->camera) {
+ return;
+ }
+ Object *cam_ob = scene->camera;
+ float viewmat[4][4];
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ scene->r.cfra = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+ /* Ensure the camera is the right one. */
+ BKE_scene_camera_switch_update(scene);
+ invert_m4_m4(viewmat, cam_ob->obmat);
+
+ /* Prepare transform matrix. */
+ float diff_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
+
+ /* Compute all strokes of this frame. */
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat);
+ }
+ }
+ }
+
+ /* Delete original strokes. */
+ free_old_strokes(depsgraph, ob, gpd);
+
+ /* Return frame state and DB to original state. */
+ scene->r.cfra = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+}
+
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ OutlineGpencilModifierData *mmd = (OutlineGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+ walk(userData, ob, (ID **)&mmd->outline_material, IDWALK_CB_USER);
+ walk(userData, ob, (ID **)&mmd->object, IDWALK_CB_NOP);
+}
+
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
+{
+ OutlineGpencilModifierData *lmd = (OutlineGpencilModifierData *)md;
+ if (ctx->scene->camera) {
+ DEG_add_object_relation(
+ ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Outline Modifier");
+ DEG_add_object_relation(
+ ctx->node, ctx->scene->camera, DEG_OB_COMP_PARAMETERS, "Outline Modifier");
+ }
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Outline Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Outline Modifier");
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "thickness", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_keep_shape", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "subdivision", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "sample_length", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "outline_material", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+
+ gpencil_modifier_panel_end(layout, ptr);
+}
+
+static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ gpencil_modifier_masking_panel_draw(panel, true, false);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ PanelType *panel_type = gpencil_modifier_panel_register(
+ region_type, eGpencilModifierType_Outline, panel_draw);
+ gpencil_modifier_subpanel_register(
+ region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Outline = {
+ /* name */ N_("Outline"),
+ /* structName */ "OutlineGpencilModifierData",
+ /* structSize */ sizeof(OutlineGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+ /* panelRegister */ panelRegister,
+};