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')
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt70
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h51
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c189
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h54
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c558
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c164
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c355
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c360
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c213
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c210
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c285
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c143
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c183
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c123
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c152
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c193
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c171
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c171
18 files changed, 3645 insertions, 0 deletions
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
new file mode 100644
index 00000000000..5ad91d4e01b
--- /dev/null
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -0,0 +1,70 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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) 2018, Blender Foundation
+# All rights reserved.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ ../blenkernel
+ ../blenlib
+ ../blenfont
+ ../depsgraph
+ ../makesdna
+ ../makesrna
+ ../bmesh
+ ../render/extern/include
+ ../../../intern/elbeem/extern
+ ../../../intern/guardedalloc
+ ../../../intern/eigen
+)
+
+set(INC_SYS
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/MOD_gpencil_util.h
+
+ intern/MOD_gpencil_util.c
+ intern/MOD_gpencilnoise.c
+ intern/MOD_gpencilsubdiv.c
+ intern/MOD_gpencilsimplify.c
+ intern/MOD_gpencilthick.c
+ intern/MOD_gpenciltint.c
+ intern/MOD_gpencilcolor.c
+ intern/MOD_gpencilinstance.c
+ intern/MOD_gpencilbuild.c
+ intern/MOD_gpencilopacity.c
+ intern/MOD_gpencillattice.c
+ intern/MOD_gpencilmirror.c
+ intern/MOD_gpencilsmooth.c
+ intern/MOD_gpencilhook.c
+ intern/MOD_gpenciloffset.c
+
+ MOD_gpencil_modifiertypes.h
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_gpencil_modifiers "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
new file mode 100644
index 00000000000..73386601d10
--- /dev/null
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -0,0 +1,51 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file MOD_gpencil_modifiertypes.h
+ * \ingroup modifiers
+ */
+
+#ifndef __MOD_GPENCIL_MODIFIERTYPES_H__
+#define __MOD_GPENCIL_MODIFIERTYPES_H__
+
+#include "BKE_gpencil_modifier.h"
+
+/* ****************** Type structures for all modifiers ****************** */
+
+extern GpencilModifierTypeInfo modifierType_Gpencil_None;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Noise;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Subdiv;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Simplify;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Thick;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Tint;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Color;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Instance;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Build;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Opacity;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Lattice;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Mirror;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Smooth;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Hook;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Offset;
+
+/* MOD_gpencil_util.c */
+void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
+
+#endif /* __MOD_GPENCIL_MODIFIERTYPES_H__ */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
new file mode 100644
index 00000000000..151218c06e4
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -0,0 +1,189 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
+#include "BLI_rand.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_lattice.h"
+#include "BKE_material.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_colortools.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_util.h"
+
+void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
+{
+#define INIT_GP_TYPE(typeName) (types[eGpencilModifierType_##typeName] = &modifierType_Gpencil_##typeName)
+ INIT_GP_TYPE(Noise);
+ INIT_GP_TYPE(Subdiv);
+ INIT_GP_TYPE(Simplify);
+ INIT_GP_TYPE(Thick);
+ INIT_GP_TYPE(Tint);
+ INIT_GP_TYPE(Color);
+ INIT_GP_TYPE(Instance);
+ INIT_GP_TYPE(Build);
+ INIT_GP_TYPE(Opacity);
+ INIT_GP_TYPE(Lattice);
+ INIT_GP_TYPE(Mirror);
+ INIT_GP_TYPE(Smooth);
+ INIT_GP_TYPE(Hook);
+ INIT_GP_TYPE(Offset);
+#undef INIT_GP_TYPE
+}
+
+/* verify if valid layer and pass index */
+bool is_stroke_affected_by_modifier(
+ Object *ob, char *mlayername, int mpassindex, int minpoints,
+ bGPDlayer *gpl, bGPDstroke *gps, bool inv1, bool inv2)
+{
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+
+ /* omit if filter by layer */
+ if (mlayername[0] != '\0') {
+ if (inv1 == false) {
+ if (!STREQ(mlayername, gpl->info)) {
+ return false;
+ }
+ }
+ else {
+ if (STREQ(mlayername, gpl->info)) {
+ return false;
+ }
+ }
+ }
+ /* verify pass */
+ if (mpassindex > 0) {
+ if (inv2 == false) {
+ if (gp_style->index != mpassindex) {
+ return false;
+ }
+ }
+ else {
+ if (gp_style->index == mpassindex) {
+ return false;
+ }
+ }
+ }
+ /* need to have a minimum number of points */
+ if ((minpoints > 0) && (gps->totpoints < minpoints)) {
+ return false;
+ }
+
+ return true;
+}
+
+/* verify if valid vertex group *and return weight */
+float get_modifier_point_weight(MDeformVert *dvert, int inverse, int vindex)
+{
+ float weight = 1.0f;
+
+ if (vindex >= 0) {
+ weight = BKE_gpencil_vgroup_use_index(dvert, vindex);
+ if ((weight >= 0.0f) && (inverse == 1)) {
+ return -1.0f;
+ }
+
+ if ((weight < 0.0f) && (inverse == 0)) {
+ return -1.0f;
+ }
+
+ /* if inverse, weight is always 1 */
+ if ((weight < 0.0f) && (inverse == 1)) {
+ return 1.0f;
+ }
+
+ }
+
+ return weight;
+}
+
+/* set material when apply modifiers (used in tint and color modifier) */
+void gpencil_apply_modifier_material(
+ Main *bmain, Object *ob, Material *mat,
+ GHash *gh_color, bGPDstroke *gps, bool crt_material)
+{
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+
+ /* look for color */
+ if (crt_material) {
+ Material *newmat = BLI_ghash_lookup(gh_color, mat->id.name);
+ if (newmat == NULL) {
+ BKE_object_material_slot_add(bmain, ob);
+ newmat = BKE_material_copy(bmain, mat);
+ newmat->preview = NULL;
+
+ assign_material(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+
+ copy_v4_v4(newmat->gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
+ copy_v4_v4(newmat->gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
+
+ BLI_ghash_insert(gh_color, mat->id.name, newmat);
+ DEG_id_tag_update(&newmat->id, DEG_TAG_COPY_ON_WRITE);
+ }
+ /* reasign color index */
+ int idx = BKE_gpencil_get_material_index(ob, newmat);
+ gps->mat_nr = idx - 1;
+ }
+ else {
+ /* reuse existing color (but update only first time) */
+ if (BLI_ghash_lookup(gh_color, mat->id.name) == NULL) {
+ copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
+ copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
+ BLI_ghash_insert(gh_color, mat->id.name, mat);
+ }
+ /* update previews (icon and thumbnail) */
+ if (mat->preview != NULL) {
+ mat->preview->flag[ICON_SIZE_ICON] |= PRV_CHANGED;
+ mat->preview->flag[ICON_SIZE_PREVIEW] |= PRV_CHANGED;
+ }
+ DEG_id_tag_update(&mat->id, DEG_TAG_COPY_ON_WRITE);
+ }
+}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
new file mode 100644
index 00000000000..1ca9febbdca
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -0,0 +1,54 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+ * \ingroup modifiers
+ */
+
+
+#ifndef __MOD_GPENCIL_UTIL_H__
+#define __MOD_GPENCIL_UTIL_H__
+
+struct Main;
+struct Object;
+struct bGPDlayer;
+struct bGPDstroke;
+struct MDeformVert;
+struct Material;
+struct GHash;
+
+bool is_stroke_affected_by_modifier(
+ struct Object *ob, char *mlayername, int mpassindex, int minpoints,
+ bGPDlayer *gpl, bGPDstroke *gps, bool inv1, bool inv2);
+
+float get_modifier_point_weight(struct MDeformVert *dvert, int inverse, int vindex);
+
+void gpencil_apply_modifier_material(
+ struct Main *bmain, struct Object *ob, struct Material *mat,
+ struct GHash *gh_color, struct bGPDstroke *gps, bool crt_material);
+
+#endif /* __MOD_GPENCIL_UTIL_H__ */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
new file mode 100644
index 00000000000..945afec002d
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -0,0 +1,558 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ BuildGpencilModifierData *gpmd = (BuildGpencilModifierData *)md;
+
+ /* We deliberately set this range to the half the default
+ * frame-range to have an immediate effect ot suggest use-cases
+ */
+ gpmd->start_frame = 1;
+ gpmd->end_frame = 125;
+
+ /* Init default length of each build effect - Nothing special */
+ gpmd->start_delay = 0.0f;
+ gpmd->length = 100.0f;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static bool dependsOnTime(GpencilModifierData *UNUSED(md))
+{
+ return true;
+}
+
+/* ******************************************** */
+/* Build Modifier - Stroke generation logic
+ *
+ * There are two modes for how the strokes are sequenced (at a macro-level):
+ * - Sequential Mode - Strokes appear/disappear one after the other. Only a single one changes at a time.
+ * - Concurrent Mode - Multiple strokes appear/disappear at once.
+ *
+ * Assumptions:
+ * - Stroke points are generally equally spaced. This implies that we can just add/remove points,
+ * without worrying about distances between them / adding extra interpolated points between
+ * an visible point and one about to be added/removed (or any similar tapering effects).
+
+ * - All strokes present are fully visible (i.e. we don't have to ignore any)
+ */
+
+/* Remove a particular stroke */
+static void clear_stroke(bGPDframe *gpf, bGPDstroke *gps)
+{
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+}
+
+/* Clear all strokes in frame */
+static void gpf_clear_all_strokes(bGPDframe *gpf)
+{
+ bGPDstroke *gps, *gps_next;
+ for (gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ clear_stroke(gpf, gps);
+ }
+ BLI_listbase_clear(&gpf->strokes);
+}
+
+/* Reduce the number of points in the stroke
+ *
+ * Note: This won't be called if all points are present/removed
+ * TODO: Allow blending of growing/shrinking tip (e.g. for more gradual transitions)
+ */
+static void reduce_stroke_points(bGPDstroke *gps, const int num_points, const eBuildGpencil_Transition transition)
+{
+ bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * num_points, __func__);
+ MDeformVert *new_dvert = MEM_callocN(sizeof(MDeformVert) * num_points, __func__);
+
+ /* Which end should points be removed from */
+ // TODO: free stroke weights
+ switch (transition) {
+ case GP_BUILD_TRANSITION_GROW: /* Show in forward order = Remove ungrown-points from end of stroke */
+ case GP_BUILD_TRANSITION_SHRINK: /* Hide in reverse order = Remove dead-points from end of stroke */
+ {
+ /* copy over point data */
+ memcpy(new_points, gps->points, sizeof(bGPDspoint) * num_points);
+ memcpy(new_dvert, gps->dvert, sizeof(MDeformVert) * num_points);
+
+ /* free unused point weights */
+ for (int i = num_points; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+
+ break;
+ }
+
+ /* Hide in forward order = Remove points from start of stroke */
+ case GP_BUILD_TRANSITION_FADE:
+ {
+ /* num_points is the number of points left after reducing.
+ * We need to know how many to remove
+ */
+ const int offset = gps->totpoints - num_points;
+
+ /* copy over point data */
+ memcpy(new_points, gps->points + offset, sizeof(bGPDspoint) * num_points);
+ memcpy(new_dvert, gps->dvert + offset, sizeof(MDeformVert) * num_points);
+
+ /* free unused weights */
+ for (int i = 0; i < offset; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown transition %d in %s()\n", (int)transition, __func__);
+ break;
+ }
+
+ /* replace stroke geometry */
+ MEM_SAFE_FREE(gps->points);
+ MEM_SAFE_FREE(gps->dvert);
+ gps->points = new_points;
+ gps->dvert = new_dvert;
+ gps->totpoints = num_points;
+
+ /* mark stroke as needing to have its geometry caches rebuilt */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ MEM_SAFE_FREE(gps->triangles);
+}
+
+/* --------------------------------------------- */
+
+/* Stroke Data Table Entry - This represents one stroke being generated */
+typedef struct tStrokeBuildDetails {
+ bGPDstroke *gps;
+
+ /* Indices - first/last indices for the stroke's points (overall) */
+ size_t start_idx, end_idx;
+
+ /* Number of points - Cache for more convenient access */
+ int totpoints;
+} tStrokeBuildDetails;
+
+
+/* Sequential - Show strokes one after the other */
+static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
+{
+ const size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
+ bGPDstroke *gps;
+ size_t i;
+
+ /* 1) Compute proportion of time each stroke should occupy */
+ /* NOTE: This assumes that the total number of points won't overflow! */
+ tStrokeBuildDetails *table = MEM_callocN(sizeof(tStrokeBuildDetails) * tot_strokes, __func__);
+ size_t totpoints = 0;
+
+ /* 1.1) First pass - Tally up points */
+ for (gps = gpf->strokes.first, i = 0; gps; gps = gps->next, i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ cell->gps = gps;
+ cell->totpoints = gps->totpoints;
+
+ totpoints += cell->totpoints;
+ }
+
+ /* 1.2) Second pass - Compute the overall indices for points */
+ for (i = 0; i < tot_strokes; i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ if (i == 0) {
+ cell->start_idx = 0;
+ }
+ else {
+ cell->start_idx = (cell - 1)->end_idx;
+ }
+ cell->end_idx = cell->start_idx + cell->totpoints - 1;
+ }
+
+
+ /* 2) Determine the global indices for points that should be visible */
+ size_t first_visible = 0;
+ size_t last_visible = 0;
+
+ switch (mmd->transition) {
+ /* Show in forward order
+ * - As fac increases, the number of visible points increases
+ */
+ case GP_BUILD_TRANSITION_GROW:
+ first_visible = 0; /* always visible */
+ last_visible = (size_t)roundf(totpoints * fac);
+ break;
+
+ /* Hide in reverse order
+ * - As fac increases, the number of points visible at the end decreases
+ */
+ case GP_BUILD_TRANSITION_SHRINK:
+ first_visible = 0; /* always visible (until last point removed) */
+ last_visible = (size_t)(totpoints * (1.0f - fac));
+ break;
+
+ /* Hide in forward order
+ * - As fac increases, the early points start getting hidden
+ */
+ case GP_BUILD_TRANSITION_FADE:
+ first_visible = (size_t)(totpoints * fac);
+ last_visible = totpoints; /* i.e. visible until the end, unless first overlaps this */
+ break;
+ }
+
+
+ /* 3) Go through all strokes, deciding which to keep, and/or how much of each to keep */
+ for (i = 0; i < tot_strokes; i++) {
+ tStrokeBuildDetails *cell = &table[i];
+
+ /* Determine what portion of the stroke is visible */
+ if ((cell->end_idx < first_visible) || (cell->start_idx > last_visible)) {
+ /* Not visible at all - Either ended before */
+ clear_stroke(gpf, cell->gps);
+ }
+ else {
+ /* Some proportion of stroke is visible */
+ /* XXX: Will the transition settings still be valid now? */
+ if ((first_visible <= cell->start_idx) && (last_visible >= cell->end_idx)) {
+ /* Do nothing - whole stroke is visible */
+ }
+ else if (first_visible > cell->start_idx) {
+ /* Starts partway through this stroke */
+ int num_points = cell->end_idx - first_visible;
+ reduce_stroke_points(cell->gps, num_points, mmd->transition);
+ }
+ else {
+ /* Ends partway through this stroke */
+ int num_points = last_visible - cell->start_idx;
+ reduce_stroke_points(cell->gps, num_points, mmd->transition);
+ }
+ }
+ }
+
+ /* Free table */
+ MEM_freeN(table);
+}
+
+/* --------------------------------------------- */
+
+/* Concurrent - Show multiple strokes at once */
+// TODO: Allow random offsets to start times
+// TODO: Allow varying speeds? Scaling of progress?
+static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
+{
+ bGPDstroke *gps, *gps_next;
+ int max_points = 0;
+
+ const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
+
+ /* 1) Determine the longest stroke, to figure out when short strokes should start */
+ /* FIXME: A *really* long stroke here could dwarf everything else, causing bad timings */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->totpoints > max_points) {
+ max_points = gps->totpoints;
+ }
+ }
+ if (max_points == 0) {
+ printf("ERROR: Strokes are all empty (GP Build Modifier: %s)\n", __func__);
+ return;
+ }
+
+ /* 2) For each stroke, determine how it should be handled */
+ for (gps = gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+
+ /* Relative Length of Stroke - Relative to the longest stroke,
+ * what proportion of the available time should this stroke use
+ */
+ const float relative_len = (float)gps->totpoints / (float)max_points;
+
+ /* Determine how many points should be left in the stroke */
+ int num_points = 0;
+
+ switch (mmd->time_alignment) {
+ case GP_BUILD_TIMEALIGN_START: /* all start on frame 1 */
+ {
+ /* Build effect occurs over when fac = 0, to fac = relative_len */
+ if (fac <= relative_len) {
+ /* Scale fac to fit relative_len */
+ /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
+ const float scaled_fac = fac / relative_len;
+
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
+ }
+ else {
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
+ }
+ }
+ else {
+ /* Build effect has ended */
+ if (reverse) {
+ num_points = 0;
+ }
+ else {
+ num_points = gps->totpoints;
+ }
+ }
+
+ break;
+ }
+ case GP_BUILD_TIMEALIGN_END: /* all end on same frame */
+ {
+ /* Build effect occurs over 1.0 - relative_len, to 1.0 (i.e. over the end of the range) */
+ const float start_fac = 1.0f - relative_len;
+
+ if (fac >= start_fac) {
+ /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */
+ const float scaled_fac = (fac - start_fac) / relative_len;
+
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
+ }
+ else {
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
+ }
+ }
+ else {
+ /* Build effect hasn't started */
+ if (reverse) {
+ num_points = gps->totpoints;
+ }
+ else {
+ num_points = 0;
+ }
+ }
+
+ break;
+ }
+
+ /* TODO... */
+ }
+
+ /* Modify the stroke geometry */
+ if (num_points <= 0) {
+ /* Nothing Left - Delete the stroke */
+ clear_stroke(gpf, gps);
+ }
+ else if (num_points < gps->totpoints) {
+ /* Remove some points */
+ reduce_stroke_points(gps, num_points, mmd->transition);
+ }
+ }
+}
+
+/* --------------------------------------------- */
+
+/* Entry-point for Build Modifier */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *UNUSED(ob), bGPDlayer *gpl, bGPDframe *gpf)
+{
+ BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
+ const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
+
+ const float ctime = DEG_get_ctime(depsgraph);
+ //printf("GP Build Modifier - %f\n", ctime);
+
+ /* Early exit if it's an empty frame */
+ if (gpf->strokes.first == NULL) {
+ return;
+ }
+
+ /* Omit layer if filter by layer */
+ if (mmd->layername[0] != '\0') {
+ if ((mmd->flag & GP_BUILD_INVERT_LAYER) == 0) {
+ if (!STREQ(mmd->layername, gpl->info)) {
+ return;
+ }
+ }
+ else {
+ if (STREQ(mmd->layername, gpl->info)) {
+ return;
+ }
+ }
+ }
+
+ /* Early exit if outside of the frame range for this modifier
+ * (e.g. to have one forward, and one backwards modifier)
+ */
+ if (mmd->flag & GP_BUILD_RESTRICT_TIME) {
+ if ((ctime < mmd->start_frame) || (ctime > mmd->end_frame)) {
+ return;
+ }
+ }
+
+ /* Compute start and end frames for the animation effect
+ * By default, the upper bound is given by the "maximum length" setting
+ */
+ float start_frame = gpf->framenum + mmd->start_delay;
+ float end_frame = gpf->framenum + mmd->length;
+
+ if (gpf->next) {
+ /* Use the next frame or upper bound as end frame, whichever is lower/closer */
+ end_frame = MIN2(end_frame, gpf->next->framenum);
+ }
+
+
+ /* Early exit if current frame is outside start/end bounds */
+ /* NOTE: If we're beyond the next/prev frames (if existent), then we wouldn't have this problem anyway... */
+ if (ctime < start_frame) {
+ /* Before Start - Animation hasn't started. Display initial state. */
+ if (reverse) {
+ /* 1) Reverse = Start with all, end with nothing.
+ * ==> Do nothing (everything already present)
+ */
+ }
+ else {
+ /* 2) Forward Order = Start with nothing, end with the full frame.
+ * ==> Free all strokes, and return an empty frame
+ */
+ gpf_clear_all_strokes(gpf);
+ }
+
+ /* Early exit */
+ return;
+ }
+ else if (ctime >= end_frame) {
+ /* Past End - Animation finished. Display final result. */
+ if (reverse) {
+ /* 1) Reverse = Start with all, end with nothing.
+ * ==> Free all strokes, and return an empty frame
+ */
+ gpf_clear_all_strokes(gpf);
+ }
+ else {
+ /* 2) Forward Order = Start with nothing, end with the full frame.
+ * ==> Do Nothing (everything already present)
+ */
+ }
+
+ /* Early exit */
+ return;
+ }
+
+
+ /* Determine how far along we are between the keyframes */
+ float fac = (ctime - start_frame) / (end_frame - start_frame);
+ //printf(" Progress on %d = %f (%f - %f)\n", gpf->framenum, fac, start_frame, end_frame);
+
+ /* Time management mode */
+ switch (mmd->mode) {
+ case GP_BUILD_MODE_SEQUENTIAL:
+ build_sequential(mmd, gpf, fac);
+ break;
+
+ case GP_BUILD_MODE_CONCURRENT:
+ build_concurrent(mmd, gpf, fac);
+ break;
+
+ default:
+ printf("Unsupported build mode (%d) for GP Build Modifier: '%s'\n", mmd->mode, mmd->modifier.name);
+ break;
+ }
+}
+
+/* ******************************************** */
+
+/* FIXME: Baking the Build Modifier is currently unsupported.
+ * Adding support for this is more complicated than for other
+ * modifiers, as to implement this, we'd have to add more frames,
+ * which would in turn break how the modifier functions.
+ */
+#if 0
+static void bakeModifier(
+ Main *bmain, const Depsgraph *UNUSED(depsgraph),
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+
+ }
+ }
+}
+#endif
+
+/* ******************************************** */
+
+GpencilModifierTypeInfo modifierType_Gpencil_Build = {
+ /* name */ "Build",
+ /* structName */ "BuildGpencilModifierData",
+ /* structSize */ sizeof(BuildGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ dependsOnTime,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
new file mode 100644
index 00000000000..0bbd26da670
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -0,0 +1,164 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_color.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ ARRAY_SET_ITEMS(gpmd->hsv, 1.0f, 1.0f, 1.0f);
+ gpmd->layername[0] = '\0';
+ gpmd->flag |= GP_COLOR_CREATE_COLORS;
+ gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* color correction strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+
+ ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
+ float hsv[3], factor[3];
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_COLOR_INVERT_LAYER, mmd->flag & GP_COLOR_INVERT_PASS))
+ {
+ return;
+ }
+
+ copy_v3_v3(factor, mmd->hsv);
+ add_v3_fl(factor, -1.0f);
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ rgb_to_hsv_v(gps->runtime.tmp_stroke_rgba, hsv);
+ add_v3_v3(hsv, factor);
+ CLAMP3(hsv, 0.0f, 1.0f);
+ hsv_to_rgb_v(hsv, gps->runtime.tmp_stroke_rgba);
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ rgb_to_hsv_v(gps->runtime.tmp_fill_rgba, hsv);
+ add_v3_v3(hsv, factor);
+ CLAMP3(hsv, 0.0f, 1.0f);
+ hsv_to_rgb_v(hsv, gps->runtime.tmp_fill_rgba);
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ GHash *gh_color = BLI_ghash_str_new("GP_Color modifier");
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ if (mat == NULL)
+ continue;
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+ /* skip stroke if it doesn't have color info */
+ if (ELEM(NULL, gp_style))
+ continue;
+
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+
+ gpencil_apply_modifier_material(
+ bmain, ob, mat, gh_color, gps,
+ (bool)(mmd->flag & GP_COLOR_CREATE_COLORS));
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Color = {
+ /* name */ "Hue/Saturation",
+ /* structName */ "ColorGpencilModifierData",
+ /* structSize */ sizeof(ColorGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
new file mode 100644
index 00000000000..46d452545e2
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -0,0 +1,355 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_modifier_types.h"
+#include "BLI_math.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+/* temp struct to hold data */
+struct GPHookData_cb {
+ struct CurveMapping *curfalloff;
+
+ char falloff_type;
+ float falloff;
+ float falloff_sq;
+ float fac_orig;
+
+ unsigned int use_falloff : 1;
+ unsigned int use_uniform : 1;
+
+ float cent[3];
+
+ float mat_uniform[3][3];
+ float mat[4][4];
+};
+
+static void initData(GpencilModifierData *md)
+{
+ HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->force = 0.5f;
+ gpmd->falloff_type = eGPHook_Falloff_Smooth;
+ gpmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curfalloff) {
+ curvemapping_initialize(gpmd->curfalloff);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ HookGpencilModifierData *gmd = (HookGpencilModifierData *)md;
+ HookGpencilModifierData *tgmd = (HookGpencilModifierData *)target;
+
+ if (tgmd->curfalloff != NULL) {
+ curvemapping_free(tgmd->curfalloff);
+ tgmd->curfalloff = NULL;
+ }
+
+ BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curfalloff = curvemapping_copy(gmd->curfalloff);
+}
+
+/* calculate factor of fallof */
+static float gp_hook_falloff(const struct GPHookData_cb *tData, const float len_sq)
+{
+ BLI_assert(tData->falloff_sq);
+ if (len_sq > tData->falloff_sq) {
+ return 0.0f;
+ }
+ else if (len_sq > 0.0f) {
+ float fac;
+
+ if (tData->falloff_type == eGPHook_Falloff_Const) {
+ fac = 1.0f;
+ goto finally;
+ }
+ else if (tData->falloff_type == eGPHook_Falloff_InvSquare) {
+ /* avoid sqrt below */
+ fac = 1.0f - (len_sq / tData->falloff_sq);
+ goto finally;
+ }
+
+ fac = 1.0f - (sqrtf(len_sq) / tData->falloff);
+
+ switch (tData->falloff_type) {
+ case eGPHook_Falloff_Curve:
+ fac = curvemapping_evaluateF(tData->curfalloff, 0, fac);
+ break;
+ case eGPHook_Falloff_Sharp:
+ fac = fac * fac;
+ break;
+ case eGPHook_Falloff_Smooth:
+ fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
+ break;
+ case eGPHook_Falloff_Root:
+ fac = sqrtf(fac);
+ break;
+ case eGPHook_Falloff_Linear:
+ /* pass */
+ break;
+ case eGPHook_Falloff_Sphere:
+ fac = sqrtf(2 * fac - fac * fac);
+ break;
+ default:
+ fac = fac;
+ break;
+ }
+
+ finally:
+ return fac * tData->fac_orig;
+ }
+ else {
+ return tData->fac_orig;
+ }
+}
+
+/* apply point deformation */
+static void gp_hook_co_apply(struct GPHookData_cb *tData, float weight, bGPDspoint *pt)
+{
+ float fac;
+
+ if (tData->use_falloff) {
+ float len_sq;
+
+ if (tData->use_uniform) {
+ float co_uniform[3];
+ mul_v3_m3v3(co_uniform, tData->mat_uniform, &pt->x);
+ len_sq = len_squared_v3v3(tData->cent, co_uniform);
+ }
+ else {
+ len_sq = len_squared_v3v3(tData->cent, &pt->x);
+ }
+
+ fac = gp_hook_falloff(tData, len_sq);
+ }
+ else {
+ fac = tData->fac_orig;
+ }
+
+ if (fac) {
+ float co_tmp[3];
+ mul_v3_m4v3(co_tmp, tData->mat, &pt->x);
+ interp_v3_v3v3(&pt->x, &pt->x, co_tmp, fac * weight);
+ }
+}
+
+/* deform stroke */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+ if (!mmd->object) {
+ return;
+ }
+
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+
+ bPoseChannel *pchan = BKE_pose_channel_find_name(mmd->object->pose, mmd->subtarget);
+ float dmat[4][4];
+ struct GPHookData_cb tData;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_HOOK_INVERT_LAYER, mmd->flag & GP_HOOK_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* init struct */
+ tData.curfalloff = mmd->curfalloff;
+ tData.falloff_type = mmd->falloff_type;
+ tData.falloff = (mmd->falloff_type == eHook_Falloff_None) ? 0.0f : mmd->falloff;
+ tData.falloff_sq = SQUARE(tData.falloff);
+ tData.fac_orig = mmd->force;
+ tData.use_falloff = (tData.falloff_sq != 0.0f);
+ tData.use_uniform = (mmd->flag & GP_HOOK_UNIFORM_SPACE) != 0;
+
+ if (tData.use_uniform) {
+ copy_m3_m4(tData.mat_uniform, mmd->parentinv);
+ mul_v3_m3v3(tData.cent, tData.mat_uniform, mmd->cent);
+ }
+ else {
+ unit_m3(tData.mat_uniform);
+ copy_v3_v3(tData.cent, mmd->cent);
+ }
+
+ /* get world-space matrix of target, corrected for the space the verts are in */
+ if (mmd->subtarget[0] && pchan) {
+ /* bone target if there's a matching pose-channel */
+ mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat);
+ }
+ else {
+ /* just object target */
+ copy_m4_m4(dmat, mmd->object->obmat);
+ }
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv);
+
+ /* loop points and apply deform */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_HOOK_INVERT_VGROUP) != 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+ gp_hook_co_apply(&tData, weight, pt);
+ }
+}
+
+/* FIXME: Ideally we be doing this on a copy of the main depsgraph
+ * (i.e. one where we don't have to worry about restoring state)
+ */
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply hook effects on this frame
+ * NOTE: this assumes that we don't want hook animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* compute hook effects on this frame */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ if (mmd->curfalloff) {
+ curvemapping_free(mmd->curfalloff);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ HookGpencilModifierData *lmd = (HookGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Hook Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
+ /* name */ "Hook",
+ /* structName */ "HookGpencilModifierData",
+ /* structSize */ sizeof(HookGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c
new file mode 100644
index 00000000000..a35174d882f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c
@@ -0,0 +1,360 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilinstance.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_layer.h"
+#include "BKE_collection.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ InstanceGpencilModifierData *gpmd = (InstanceGpencilModifierData *)md;
+ gpmd->count[0] = 1;
+ gpmd->count[1] = 1;
+ gpmd->count[2] = 1;
+ gpmd->offset[0] = 1.0f;
+ gpmd->offset[1] = 1.0f;
+ gpmd->offset[2] = 1.0f;
+ gpmd->shift[0] = 0.0f;
+ gpmd->shift[1] = 0.0f;
+ gpmd->shift[2] = 0.0f;
+ gpmd->scale[0] = 1.0f;
+ gpmd->scale[1] = 1.0f;
+ gpmd->scale[2] = 1.0f;
+ gpmd->rnd_rot = 0.5f;
+ gpmd->rnd_size = 0.5f;
+ gpmd->lock_axis |= GP_LOCKAXIS_X;
+ gpmd->flag |= GP_INSTANCE_MAKE_OBJECTS;
+
+ /* fill random values */
+ BLI_array_frand(gpmd->rnd, 20, 1);
+ gpmd->rnd[0] = 1;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* -------------------------------- */
+
+/* array modifier - generate geometry callback (for viewport/rendering) */
+/* TODO: How to skip this for the simplify options? --> !GP_SIMPLIFY_MODIF(ts, playing) */
+static void generate_geometry(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+ ListBase stroke_cache = {NULL, NULL};
+ bGPDstroke *gps;
+ int idx;
+
+ /* Check which strokes we can use once, and store those results in an array
+ * for quicker checking of what's valid (since string comparisons are expensive)
+ */
+ const int num_strokes = BLI_listbase_count(&gpf->strokes);
+ int num_valid = 0;
+
+ bool *valid_strokes = MEM_callocN(sizeof(bool) * num_strokes, __func__);
+
+ for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) {
+ /* Record whether this stroke can be used
+ * ATTENTION: The logic here is the inverse of what's used everywhere else!
+ */
+ if (is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_INSTANCE_INVERT_LAYER, mmd->flag & GP_INSTANCE_INVERT_PASS))
+ {
+ valid_strokes[idx] = true;
+ num_valid++;
+ }
+ }
+
+ /* Early exit if no strokes can be copied */
+ if (num_valid == 0) {
+ if (G.debug & G_DEBUG) {
+ printf("GP Array Mod - No strokes to be included\n");
+ }
+
+ MEM_SAFE_FREE(valid_strokes);
+ return;
+ }
+
+
+ /* Generate new instances of all existing strokes,
+ * keeping each instance together so they maintain
+ * the correct ordering relative to each other
+ */
+ for (int x = 0; x < mmd->count[0]; x++) {
+ for (int y = 0; y < mmd->count[1]; y++) {
+ for (int z = 0; z < mmd->count[2]; z++) {
+ /* original strokes are at index = 0,0,0 */
+ if ((x == 0) && (y == 0) && (z == 0)) {
+ continue;
+ }
+
+ /* Compute transforms for this instance */
+ const int elem_idx[3] = {x, y, z};
+ float mat[4][4];
+
+ BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat);
+
+ /* apply shift */
+ int sh = x;
+ if (mmd->lock_axis == GP_LOCKAXIS_Y) {
+ sh = y;
+ }
+ if (mmd->lock_axis == GP_LOCKAXIS_Z) {
+ sh = z;
+ }
+ madd_v3_v3fl(mat[3], mmd->shift, sh);
+
+ /* Duplicate original strokes to create this instance */
+ for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) {
+ /* check if stroke can be duplicated */
+ if (valid_strokes[idx]) {
+ /* Duplicate stroke */
+ bGPDstroke *gps_dst = MEM_dupallocN(gps);
+ gps_dst->points = MEM_dupallocN(gps->points);
+ gps_dst->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, gps_dst);
+
+ gps_dst->triangles = MEM_dupallocN(gps->triangles);
+
+ /* Move points */
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps_dst->points[i];
+ mul_m4_v3(mat, &pt->x);
+ }
+
+ /* Add new stroke to cache, to be added to the frame once
+ * all duplicates have been made
+ */
+ BLI_addtail(&stroke_cache, gps_dst);
+ }
+ }
+ }
+ }
+ }
+
+ /* merge newly created stroke instances back into the main stroke list */
+ BLI_movelisttolist(&gpf->strokes, &stroke_cache);
+
+ /* free temp data */
+ MEM_SAFE_FREE(valid_strokes);
+}
+
+/* bakeModifier - "Bake to Data" Mode */
+static void bakeModifierGP_strokes(
+ Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ generate_geometry(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+}
+
+/* -------------------------------- */
+
+/* helper to create a new object */
+static Object *array_instance_add_ob_copy(Main *bmain, Scene *scene, Object *from_ob)
+{
+ Object *ob;
+
+ ob = BKE_object_copy(bmain, from_ob);
+ BKE_collection_object_add_from(bmain, scene, from_ob, ob);
+
+ zero_v3(ob->loc);
+ zero_v3(ob->rot);
+
+ DEG_id_type_tag(bmain, ID_OB);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&scene->id, 0);
+
+ return ob;
+}
+
+/* bakeModifier - "Make Objects" Mode */
+static void bakeModifierGP_objects(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ /* reset random */
+ mmd->rnd[0] = 1;
+
+ /* generate instances as objects */
+ for (int x = 0; x < mmd->count[0]; x++) {
+ for (int y = 0; y < mmd->count[1]; y++) {
+ for (int z = 0; z < mmd->count[2]; z++) {
+ Object *newob;
+ GpencilModifierData *fmd;
+
+ const int elem_idx[3] = {x, y, z};
+ float mat[4][4], finalmat[4][4];
+ int sh;
+
+ /* original strokes are at index = 0,0,0 */
+ if ((x == 0) && (y == 0) && (z == 0)) {
+ continue;
+ }
+
+ /* compute transform for instance */
+ BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat);
+ mul_m4_m4m4(finalmat, ob->obmat, mat);
+
+ /* moves to new origin */
+ sh = x;
+ if (mmd->lock_axis == GP_LOCKAXIS_Y) {
+ sh = y;
+ }
+ if (mmd->lock_axis == GP_LOCKAXIS_Z) {
+ sh = z;
+ }
+ madd_v3_v3fl(finalmat[3], mmd->shift, sh);
+
+ /* Create a new object
+ *
+ * NOTE: Copies share the same original GP datablock
+ * Artists can later user make_single_user on these
+ * to make them unique (if necessary), without too
+ * much extra memory usage.
+ */
+ newob = array_instance_add_ob_copy(bmain, scene, ob);
+
+ /* remove array on destination object */
+ fmd = (GpencilModifierData *)BLI_findstring(&newob->greasepencil_modifiers, md->name, offsetof(GpencilModifierData, name));
+ if (fmd) {
+ BLI_remlink(&newob->greasepencil_modifiers, fmd);
+ BKE_gpencil_modifier_free(fmd);
+ }
+
+ /* copy transforms to destination object */
+ copy_m4_m4(newob->obmat, finalmat);
+
+ copy_v3_v3(newob->loc, finalmat[3]);
+ mat4_to_eul(newob->rot, finalmat);
+ mat4_to_size(newob->size, finalmat);
+ }
+ }
+ }
+}
+
+/* -------------------------------- */
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+
+ /* When the "make_objects" flag is set, this modifier is handled as part of the
+ * draw engine instead. The main benefit is that the instances won't suffer from
+ * z-ordering problems.
+ *
+ * FIXME: Ultimately, the draw-engine hack here shouldn't be necessary, but until
+ * we find a better fix to the z-ordering problems, it's better to have
+ * working functionality
+ */
+ if ((mmd->flag & GP_INSTANCE_MAKE_OBJECTS) == 0) {
+ generate_geometry(md, depsgraph, ob, gpl, gpf);
+ }
+}
+
+/* Generic "bakeModifier" callback */
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md;
+
+ /* Create new objects or add all to current datablock.
+ * Sometimes it's useful to have the option to do either of these...
+ */
+ if (mmd->flag & GP_INSTANCE_MAKE_OBJECTS) {
+ bakeModifierGP_objects(bmain, depsgraph, md, ob);
+ }
+ else {
+ bakeModifierGP_strokes(depsgraph, md, ob);
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Instance = {
+ /* name */ "Instance",
+ /* structName */ "InstanceGpencilModifierData",
+ /* structSize */ sizeof(InstanceGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ 0,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
new file mode 100644
index 00000000000..33bdb9c861d
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -0,0 +1,213 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_lattice.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->cache_data = NULL;
+ gpmd->strength = 1.0f;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_LATTICE_INVERT_LAYER, mmd->flag & GP_LATTICE_INVERT_PASS))
+ {
+ return;
+ }
+
+ if (mmd->cache_data == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_LATTICE_INVERT_VGROUP) != 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight);
+ }
+}
+
+/* FIXME: Ideally we be doing this on a copy of the main depsgraph
+ * (i.e. one where we don't have to worry about restoring state)
+ */
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ struct LatticeDeformData *ldata = NULL;
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL)
+ return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply lattice effects on this frame
+ * NOTE: this assumes that we don't want lattice animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* recalculate lattice data */
+ BKE_gpencil_lattice_init(ob);
+
+ /* compute lattice effects on this frame */
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+
+ /* free lingering data */
+ ldata = (struct LatticeDeformData *)mmd->cache_data;
+ if (ldata) {
+ end_latt_deform(ldata);
+ mmd->cache_data = NULL;
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ struct LatticeDeformData *ldata = (struct LatticeDeformData *)mmd->cache_data;
+ /* free deform data */
+ if (ldata) {
+ end_latt_deform(ldata);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ LatticeGpencilModifierData *lmd = (LatticeGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
+ /* name */ "Lattice",
+ /* structName */ "LatticeGpencilModifierData",
+ /* structSize */ sizeof(LatticeGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_Single | eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
new file mode 100644
index 00000000000..4c359be670f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -0,0 +1,210 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_modifier.h"
+#include "BKE_library_query.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+#include "BKE_layer.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->flag |= GP_MIRROR_AXIS_X;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis)
+{
+ int i;
+ bGPDspoint *pt;
+ float factor[3] = { 1.0f, 1.0f, 1.0f };
+ factor[axis] = -1.0f;
+
+ float clear[3] = { 0.0f, 0.0f, 0.0f };
+ clear[axis] = 1.0f;
+
+ float origin[3];
+ float mirror_origin[3];
+
+ copy_v3_v3(origin, ob->loc);
+ /* only works with current axis */
+ mul_v3_v3(origin, clear);
+ zero_v3(mirror_origin);
+
+ if (mmd->object) {
+ copy_v3_v3(mirror_origin, mmd->object->loc);
+ mul_v3_v3(mirror_origin, clear);
+ sub_v3_v3(origin, mirror_origin);
+ }
+ /* clear other axis */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, origin);
+ mul_v3_v3(&pt->x, factor);
+ add_v3_v3(&pt->x, mirror_origin);
+ }
+
+}
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+ bGPDstroke *gps, *gps_new = NULL;
+ int tot_strokes;
+ int i;
+
+ /* check each axis for mirroring */
+ for (int xi = 0; xi < 3; ++xi) {
+ if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {
+
+ /* count strokes to avoid infinite loop after adding new strokes to tail of listbase */
+ tot_strokes = BLI_listbase_count(&gpf->strokes);
+
+ for (i = 0, gps = gpf->strokes.first; i < tot_strokes; i++, gps = gps->next) {
+ if (is_stroke_affected_by_modifier(
+ ob, mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_MIRROR_INVERT_LAYER, mmd->flag & GP_MIRROR_INVERT_PASS))
+ {
+ gps_new = BKE_gpencil_stroke_duplicate(gps);
+ update_position(ob, mmd, gps_new, xi);
+ BLI_addtail(&gpf->strokes, gps_new);
+ }
+ }
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *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);
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* apply mirror effects on this frame */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* compute mirror effects on this frame */
+ generateStrokes(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static bool isDisabled(GpencilModifierData *UNUSED(md), int UNUSED(userRenderParams))
+{
+ //MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+
+ return false;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ MirrorGpencilModifierData *lmd = (MirrorGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Mirror Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+}
+
+static void foreachObjectLink(
+ GpencilModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
+ /* name */ "Mirror",
+ /* structName */ "MirrorGpencilModifierData",
+ /* structSize */ sizeof(MirrorGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ NULL,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
new file mode 100644
index 00000000000..be361498578
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -0,0 +1,285 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_rand.h"
+
+#include "PIL_time.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->flag |= GP_NOISE_MOD_LOCATION;
+ gpmd->flag |= GP_NOISE_FULL_STROKE;
+ gpmd->flag |= GP_NOISE_USE_RANDOM;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->step = 1;
+ gpmd->scene_frame = -999999;
+ gpmd->gp_frame = -999999;
+
+ gpmd->vrand1 = 1.0;
+ gpmd->vrand2 = 1.0;
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+
+ if (mmd->rng != NULL) {
+ BLI_rng_free(mmd->rng);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static bool dependsOnTime(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+ return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
+}
+
+/* aply noise effect based on stroke direction */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *depsgraph,
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+ bGPDspoint *pt0, *pt1;
+ MDeformVert *dvert;
+ float shift, vran, vdir;
+ float normal[3];
+ float vec1[3], vec2[3];
+#if 0
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+#endif
+ int sc_frame = 0;
+ int sc_diff = 0;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+
+ /* Random generator, only init once. */
+ if (mmd->rng == NULL) {
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= GET_UINT_FROM_POINTER(mmd);
+ mmd->rng = BLI_rng_new(rng_seed);
+ }
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_NOISE_INVERT_LAYER, mmd->flag & GP_NOISE_INVERT_PASS))
+ {
+ return;
+ }
+
+ sc_frame = (int)DEG_get_ctime(depsgraph);
+
+ zero_v3(vec2);
+
+ /* calculate stroke normal*/
+ BKE_gpencil_stroke_normal(gps, normal);
+
+ /* move points */
+ for (int i = 0; i < gps->totpoints; i++) {
+ if (((i == 0) || (i == gps->totpoints - 1)) && ((mmd->flag & GP_NOISE_MOVE_EXTREME) == 0)) {
+ continue;
+ }
+
+ /* last point is special */
+ if (i == gps->totpoints) {
+ dvert = &gps->dvert[i - 2];
+ pt0 = &gps->points[i - 2];
+ pt1 = &gps->points[i - 1];
+ }
+ else {
+ dvert = &gps->dvert[i - 1];
+ pt0 = &gps->points[i - 1];
+ pt1 = &gps->points[i];
+
+ }
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_NOISE_INVERT_VGROUP) != 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+ vran = len_v3(vec1);
+ /* vector orthogonal to normal */
+ cross_v3_v3v3(vec2, vec1, normal);
+ normalize_v3(vec2);
+ /* use random noise */
+ if (mmd->flag & GP_NOISE_USE_RANDOM) {
+ sc_diff = abs(mmd->scene_frame - sc_frame);
+ /* only recalc if the gp frame change or the number of scene frames is bigger than step */
+ if ((!gpl->actframe) || (mmd->gp_frame != gpl->actframe->framenum) ||
+ (sc_diff >= mmd->step))
+ {
+ vran = mmd->vrand1 = BLI_rng_get_float(mmd->rng);
+ vdir = mmd->vrand2 = BLI_rng_get_float(mmd->rng);
+ mmd->gp_frame = gpl->actframe->framenum;
+ mmd->scene_frame = sc_frame;
+ }
+ else {
+ vran = mmd->vrand1;
+ if (mmd->flag & GP_NOISE_FULL_STROKE) {
+ vdir = mmd->vrand2;
+ }
+ else {
+ int f = (mmd->vrand2 * 10.0f) + i;
+ vdir = f % 2;
+ }
+ }
+ }
+ else {
+ vran = 1.0f;
+ if (mmd->flag & GP_NOISE_FULL_STROKE) {
+ vdir = gps->totpoints % 2;
+ }
+ else {
+ vdir = i % 2;
+ }
+ mmd->gp_frame = -999999;
+ }
+
+ /* apply randomness to location of the point */
+ if (mmd->flag & GP_NOISE_MOD_LOCATION) {
+ /* factor is too sensitive, so need divide */
+ shift = ((vran * mmd->factor) / 1000.0f) * weight;
+ if (vdir > 0.5f) {
+ mul_v3_fl(vec2, shift);
+ }
+ else {
+ mul_v3_fl(vec2, shift * -1.0f);
+ }
+ add_v3_v3(&pt1->x, vec2);
+ }
+
+ /* apply randomness to thickness */
+ if (mmd->flag & GP_NOISE_MOD_THICKNESS) {
+ if (vdir > 0.5f) {
+ pt1->pressure -= pt1->pressure * vran * mmd->factor;
+ }
+ else {
+ pt1->pressure += pt1->pressure * vran * mmd->factor;
+ }
+ CLAMP_MIN(pt1->pressure, GPENCIL_STRENGTH_MIN);
+ }
+
+ /* apply randomness to color strength */
+ if (mmd->flag & GP_NOISE_MOD_STRENGTH) {
+ if (vdir > 0.5f) {
+ pt1->strength -= pt1->strength * vran * mmd->factor;
+ }
+ else {
+ pt1->strength += pt1->strength * vran * mmd->factor;
+ }
+ CLAMP_MIN(pt1->strength, GPENCIL_STRENGTH_MIN);
+ }
+ /* apply randomness to uv rotation */
+ if (mmd->flag & GP_NOISE_MOD_UV) {
+ if (vdir > 0.5f) {
+ pt1->uv_rot -= pt1->uv_rot * vran * mmd->factor;
+ }
+ else {
+ pt1->uv_rot += pt1->uv_rot * vran * mmd->factor;
+ }
+ CLAMP(pt1->uv_rot, -M_PI_2, M_PI_2);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
+ /* name */ "Noise",
+ /* structName */ "NoiseGpencilModifierData",
+ /* structSize */ sizeof(NoiseGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ dependsOnTime,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
new file mode 100644
index 00000000000..a31f889c48a
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -0,0 +1,143 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ ARRAY_SET_ITEMS(gpmd->loc, 0.0f, 0.0f, 0.0f);
+ ARRAY_SET_ITEMS(gpmd->rot, 0.0f, 0.0f, 0.0f);
+ ARRAY_SET_ITEMS(gpmd->scale, 0.0f, 0.0f, 0.0f);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* change stroke offsetness */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ OffsetGpencilModifierData *mmd = (OffsetGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+
+ float mat[4][4];
+ float loc[3], rot[3], scale[3];
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_OFFSET_INVERT_LAYER, mmd->flag & GP_OFFSET_INVERT_PASS))
+ {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ float weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_OFFSET_INVERT_VGROUP) != 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+ /* calculate matrix */
+ mul_v3_v3fl(loc, mmd->loc, weight);
+ mul_v3_v3fl(rot, mmd->rot, weight);
+ mul_v3_v3fl(scale, mmd->scale, weight);
+ add_v3_fl(scale, 1.0);
+ loc_eul_size_to_mat4(mat, loc, rot, scale);
+
+ mul_m4_v3(mat, &pt->x);
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
+ /* name */ "Offset",
+ /* structName */ "OffsetGpencilModifierData",
+ /* structSize */ sizeof(OffsetGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
new file mode 100644
index 00000000000..e0484e19959
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -0,0 +1,183 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_material.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->factor = 1.0f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->flag |= GP_OPACITY_CREATE_COLORS;
+ gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* opacity strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(
+ ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_OPACITY_INVERT_LAYER, mmd->flag & GP_OPACITY_INVERT_PASS))
+ {
+ return;
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ gps->runtime.tmp_stroke_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f) {
+ gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f);
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ gps->runtime.tmp_fill_rgba[3] *= mmd->factor;
+ /* if factor is > 1, then force opacity */
+ if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
+ gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f);
+ }
+
+ /* if opacity > 1.0, affect the strength of the stroke */
+ if (mmd->factor > 1.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ float weight = get_modifier_point_weight(dvert, ((mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0), vindex);
+ if (weight < 0) {
+ pt->strength += mmd->factor - 1.0f;
+ }
+ else {
+ pt->strength += (mmd->factor - 1.0f) * weight;
+ }
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ GHash *gh_color = BLI_ghash_str_new("GP_Opacity modifier");
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ if (mat == NULL)
+ continue;
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+ /* skip stroke if it doesn't have color info */
+ if (ELEM(NULL, gp_style))
+ continue;
+
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+
+ gpencil_apply_modifier_material(bmain, ob, mat, gh_color, gps,
+ (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS));
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
+ /* name */ "Opacity",
+ /* structName */ "OpacityGpencilModifierData",
+ /* structSize */ sizeof(OpacityGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
new file mode 100644
index 00000000000..a8d10c973ce
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -0,0 +1,123 @@
+/* ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_vec_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->step = 1;
+ gpmd->factor = 0.0f;
+ gpmd->layername[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SimplifyGpencilModifierData *mmd = (SimplifyGpencilModifierData *)md;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 4, gpl, gps,
+ mmd->flag & GP_SIMPLIFY_INVERT_LAYER, mmd->flag & GP_SIMPLIFY_INVERT_PASS))
+ {
+ return;
+ }
+
+ if (mmd->mode == GP_SIMPLIFY_FIXED) {
+ for (int i = 0; i < mmd->step; i++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
+ }
+ else {
+ /* simplify stroke using Ramer-Douglas-Peucker algorithm */
+ BKE_gpencil_simplify_stroke(gps, mmd->factor);
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
+ /* name */ "Simplify",
+ /* structName */ "SimplifyGpencilModifierData",
+ /* structSize */ sizeof(SimplifyGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
new file mode 100644
index 00000000000..b5f2f0349af
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -0,0 +1,152 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->flag |= GP_SMOOTH_MOD_LOCATION;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->step = 1;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* aply smooth effect based on stroke direction */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+ float weight = 1.0f;
+ float val;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_SMOOTH_INVERT_LAYER, mmd->flag & GP_SMOOTH_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* smooth stroke */
+ if (mmd->factor > 0.0f) {
+ for (int r = 0; r < mmd->step; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ // bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+
+ /* verify vertex group */
+ weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_SMOOTH_INVERT_VGROUP) != 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ val = mmd->factor * weight;
+ /* perform smoothing */
+ if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
+ BKE_gpencil_smooth_stroke(gps, i, val);
+ }
+ if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
+ BKE_gpencil_smooth_stroke_strength(gps, i, val);
+ }
+ if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0)) {
+ /* thickness need to repeat process several times */
+ for (int r2 = 0; r2 < r * 10; r2++) {
+ BKE_gpencil_smooth_stroke_thickness(gps, i, val);
+ }
+ }
+ if (mmd->flag & GP_SMOOTH_MOD_UV) {
+ BKE_gpencil_smooth_stroke_uv(gps, i, val);
+ }
+ }
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
+ /* name */ "Smooth",
+ /* structName */ "SmoothGpencilModifierData",
+ /* structSize */ sizeof(SmoothGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
new file mode 100644
index 00000000000..dba3e028904
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -0,0 +1,193 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->level = 1;
+ gpmd->layername[0] = '\0';
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* subdivide stroke to get more control points */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+ bGPDspoint *temp_points;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_SUBDIV_INVERT_LAYER, mmd->flag & GP_SUBDIV_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* loop as many times as levels */
+ for (int s = 0; s < mmd->level; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrys */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ MDeformVert *dvert = &gps->dvert[i];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+ MDeformVert *dvert_final = &gps->dvert[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+
+ dvert_final->totweight = 0;
+ dvert_final->dw = NULL;
+ i2 += 2;
+ }
+
+ MEM_SAFE_FREE(temp_points);
+
+ /* move points to smooth stroke (not simple flag )*/
+ if ((mmd->flag & GP_SUBDIV_SIMPLE) == 0) {
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
+
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
+
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
+ /* name */ "Subdivision",
+ /* structName */ "SubdivGpencilModifierData",
+ /* structSize */ sizeof(SubdivGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
new file mode 100644
index 00000000000..2c01fec1357
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->thickness = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->curve_thickness = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_thickness) {
+ curvemapping_initialize(gpmd->curve_thickness);
+ }
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+
+ if (gpmd->curve_thickness) {
+ curvemapping_free(gpmd->curve_thickness);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ ThickGpencilModifierData *gmd = (ThickGpencilModifierData *)md;
+ ThickGpencilModifierData *tgmd = (ThickGpencilModifierData *)target;
+
+ if (tgmd->curve_thickness != NULL) {
+ curvemapping_free(tgmd->curve_thickness);
+ tgmd->curve_thickness = NULL;
+ }
+
+ BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_thickness = curvemapping_copy(gmd->curve_thickness);
+}
+
+/* change stroke thickness */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ ThickGpencilModifierData *mmd = (ThickGpencilModifierData *)md;
+ int vindex = defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 3, gpl, gps,
+ mmd->flag & GP_THICK_INVERT_LAYER, mmd->flag & GP_THICK_INVERT_PASS))
+ {
+ return;
+ }
+
+ /* if normalize, set stroke thickness */
+ if (mmd->flag & GP_THICK_NORMALIZE) {
+ gps->thickness = mmd->thickness;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = &gps->dvert[i];
+ float curvef = 1.0f;
+ /* verify vertex group */
+ float weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_THICK_INVERT_VGROUP) != 0), vindex);
+ if (weight < 0) {
+ continue;
+ }
+
+ if (mmd->flag & GP_THICK_NORMALIZE) {
+ pt->pressure = 1.0f;
+ }
+ else {
+ if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) {
+ /* normalize value to evaluate curve */
+ float value = (float)i / (gps->totpoints - 1);
+ curvef = curvemapping_evaluateF(mmd->curve_thickness, 0, value);
+ }
+
+ pt->pressure += mmd->thickness * weight * curvef;
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+}
+
+static void bakeModifier(
+ struct Main *UNUSED(bmain), Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ deformStroke(md, depsgraph, ob, gpl, gps);
+ }
+ }
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
+ /* name */ "Thickness",
+ /* structName */ "ThickGpencilModifierData",
+ /* structSize */ sizeof(ThickGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
new file mode 100644
index 00000000000..8af9ff6eec8
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -0,0 +1,171 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+static void initData(GpencilModifierData *md)
+{
+ TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->factor = 0.5f;
+ gpmd->layername[0] = '\0';
+ ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f);
+ gpmd->flag |= GP_TINT_CREATE_COLORS;
+ gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_generic(md, target);
+}
+
+/* tint strokes */
+static void deformStroke(
+ GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
+ Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
+{
+ TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername, mmd->pass_index, 1, gpl, gps,
+ mmd->flag & GP_TINT_INVERT_LAYER, mmd->flag & GP_TINT_INVERT_PASS))
+ {
+ return;
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+ interp_v3_v3v3(gps->runtime.tmp_stroke_rgba, gps->runtime.tmp_stroke_rgba, mmd->rgb, mmd->factor);
+ /* if factor is > 1, the alpha must be changed to get full tint */
+ if (mmd->factor > 1.0f) {
+ gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP4(gps->runtime.tmp_stroke_rgba, 0.0f, 1.0f);
+ }
+
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ interp_v3_v3v3(gps->runtime.tmp_fill_rgba, gps->runtime.tmp_fill_rgba, mmd->rgb, mmd->factor);
+ /* if factor is > 1, the alpha must be changed to get full tint */
+ if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
+ gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ }
+ CLAMP4(gps->runtime.tmp_fill_rgba, 0.0f, 1.0f);
+ }
+
+ /* if factor > 1.0, affect the strength of the stroke */
+ if (mmd->factor > 1.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->strength += mmd->factor - 1.0f;
+ CLAMP(pt->strength, 0.0f, 1.0f);
+ }
+ }
+}
+
+static void bakeModifier(
+ Main *bmain, Depsgraph *depsgraph,
+ GpencilModifierData *md, Object *ob)
+{
+ TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
+
+ GHash *gh_color = BLI_ghash_str_new("GP_Tint modifier");
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ Material *mat = give_current_material(ob, gps->mat_nr + 1);
+ if (mat == NULL)
+ continue;
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+ /* skip stroke if it doesn't have color info */
+ if (ELEM(NULL, gp_style))
+ continue;
+
+ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
+
+ deformStroke(md, depsgraph, ob, gpl, gps);
+
+ gpencil_apply_modifier_material(bmain, ob, mat, gh_color, gps,
+ (bool)(mmd->flag & GP_TINT_CREATE_COLORS));
+ }
+ }
+ }
+ /* free hash buffers */
+ if (gh_color) {
+ BLI_ghash_free(gh_color, NULL, NULL);
+ gh_color = NULL;
+ }
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
+ /* name */ "Tint",
+ /* structName */ "TintGpencilModifierData",
+ /* structSize */ sizeof(TintGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};