GP: Refactor drawing engine to single VBO
[blender.git] / source / blender / gpencil_modifiers / intern / MOD_gpencilhook.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software  Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2017, Blender Foundation
19  * This is a new part of Blender
20  *
21  * Contributor(s): Antonio Vazquez
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  */
26
27 /** \file blender/gpencil_modifiers/intern/MOD_gpencilhook.c
28  *  \ingroup modifiers
29  */
30
31 #include <stdio.h>
32
33 #include "DNA_meshdata_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_gpencil_modifier_types.h"
38 #include "DNA_modifier_types.h"
39 #include "BLI_math.h"
40
41 #include "BLI_utildefines.h"
42
43 #include "BKE_action.h"
44 #include "BKE_context.h"
45 #include "BKE_colortools.h"
46 #include "BKE_deform.h"
47 #include "BKE_gpencil.h"
48 #include "BKE_gpencil_modifier.h"
49 #include "BKE_modifier.h"
50 #include "BKE_library_query.h"
51 #include "BKE_scene.h"
52 #include "BKE_main.h"
53 #include "BKE_layer.h"
54
55 #include "MEM_guardedalloc.h"
56
57 #include "MOD_gpencil_util.h"
58 #include "MOD_gpencil_modifiertypes.h"
59
60 #include "DEG_depsgraph.h"
61 #include "DEG_depsgraph_build.h"
62 #include "DEG_depsgraph_query.h"
63
64 /* temp struct to hold data */
65 struct GPHookData_cb {
66         struct CurveMapping *curfalloff;
67
68         char  falloff_type;
69         float falloff;
70         float falloff_sq;
71         float fac_orig;
72
73         unsigned int use_falloff : 1;
74         unsigned int use_uniform : 1;
75
76         float cent[3];
77
78         float mat_uniform[3][3];
79         float mat[4][4];
80 };
81
82 static void initData(GpencilModifierData *md)
83 {
84         HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
85         gpmd->pass_index = 0;
86         gpmd->layername[0] = '\0';
87         gpmd->vgname[0] = '\0';
88         gpmd->object = NULL;
89         gpmd->force = 0.5f;
90         gpmd->falloff_type = eGPHook_Falloff_Smooth;
91         gpmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
92         if (gpmd->curfalloff) {
93                 curvemapping_initialize(gpmd->curfalloff);
94         }
95 }
96
97 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
98 {
99         HookGpencilModifierData *gmd = (HookGpencilModifierData *)md;
100         HookGpencilModifierData *tgmd = (HookGpencilModifierData *)target;
101
102         if (tgmd->curfalloff != NULL) {
103                 curvemapping_free(tgmd->curfalloff);
104                 tgmd->curfalloff = NULL;
105         }
106
107         BKE_gpencil_modifier_copyData_generic(md, target);
108
109         tgmd->curfalloff = curvemapping_copy(gmd->curfalloff);
110 }
111
112 /* calculate factor of fallof */
113 static float gp_hook_falloff(const struct GPHookData_cb *tData, const float len_sq)
114 {
115         BLI_assert(tData->falloff_sq);
116         if (len_sq > tData->falloff_sq) {
117                 return 0.0f;
118         }
119         else if (len_sq > 0.0f) {
120                 float fac;
121
122                 if (tData->falloff_type == eGPHook_Falloff_Const) {
123                         fac = 1.0f;
124                         goto finally;
125                 }
126                 else if (tData->falloff_type == eGPHook_Falloff_InvSquare) {
127                         /* avoid sqrt below */
128                         fac = 1.0f - (len_sq / tData->falloff_sq);
129                         goto finally;
130                 }
131
132                 fac = 1.0f - (sqrtf(len_sq) / tData->falloff);
133
134                 switch (tData->falloff_type) {
135                         case eGPHook_Falloff_Curve:
136                                 fac = curvemapping_evaluateF(tData->curfalloff, 0, fac);
137                                 break;
138                         case eGPHook_Falloff_Sharp:
139                                 fac = fac * fac;
140                                 break;
141                         case eGPHook_Falloff_Smooth:
142                                 fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
143                                 break;
144                         case eGPHook_Falloff_Root:
145                                 fac = sqrtf(fac);
146                                 break;
147                         case eGPHook_Falloff_Linear:
148                                 /* pass */
149                                 break;
150                         case eGPHook_Falloff_Sphere:
151                                 fac = sqrtf(2 * fac - fac * fac);
152                                 break;
153                         default:
154                                 break;
155                 }
156
157                 finally:
158                 return fac * tData->fac_orig;
159         }
160         else {
161                 return tData->fac_orig;
162         }
163 }
164
165 /* apply point deformation */
166 static void gp_hook_co_apply(struct GPHookData_cb *tData, float weight, bGPDspoint *pt)
167 {
168         float fac;
169
170         if (tData->use_falloff) {
171                 float len_sq;
172
173                 if (tData->use_uniform) {
174                         float co_uniform[3];
175                         mul_v3_m3v3(co_uniform, tData->mat_uniform, &pt->x);
176                         len_sq = len_squared_v3v3(tData->cent, co_uniform);
177                 }
178                 else {
179                         len_sq = len_squared_v3v3(tData->cent, &pt->x);
180                 }
181
182                 fac = gp_hook_falloff(tData, len_sq);
183         }
184         else {
185                 fac = tData->fac_orig;
186         }
187
188         if (fac) {
189                 float co_tmp[3];
190                 mul_v3_m4v3(co_tmp, tData->mat, &pt->x);
191                 interp_v3_v3v3(&pt->x, &pt->x, co_tmp, fac * weight);
192         }
193 }
194
195 /* deform stroke */
196 static void deformStroke(
197         GpencilModifierData *md, Depsgraph *UNUSED(depsgraph),
198         Object *ob, bGPDlayer *gpl, bGPDstroke *gps)
199 {
200         HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
201         if (!mmd->object) {
202                 return;
203         }
204
205         const int def_nr = defgroup_name_index(ob, mmd->vgname);
206
207         bPoseChannel *pchan = BKE_pose_channel_find_name(mmd->object->pose, mmd->subtarget);
208         float dmat[4][4];
209         struct GPHookData_cb tData;
210
211         if (!is_stroke_affected_by_modifier(
212                     ob,
213                     mmd->layername, mmd->pass_index, mmd->layer_pass, 3, gpl, gps,
214                     mmd->flag & GP_HOOK_INVERT_LAYER, mmd->flag & GP_HOOK_INVERT_PASS,
215                     mmd->flag & GP_HOOK_INVERT_LAYERPASS))
216         {
217                 return;
218         }
219
220         /* init struct */
221         tData.curfalloff = mmd->curfalloff;
222         tData.falloff_type = mmd->falloff_type;
223         tData.falloff = (mmd->falloff_type == eHook_Falloff_None) ? 0.0f : mmd->falloff;
224         tData.falloff_sq = SQUARE(tData.falloff);
225         tData.fac_orig = mmd->force;
226         tData.use_falloff = (tData.falloff_sq != 0.0f);
227         tData.use_uniform = (mmd->flag & GP_HOOK_UNIFORM_SPACE) != 0;
228
229         if (tData.use_uniform) {
230                 copy_m3_m4(tData.mat_uniform, mmd->parentinv);
231                 mul_v3_m3v3(tData.cent, tData.mat_uniform, mmd->cent);
232         }
233         else {
234                 unit_m3(tData.mat_uniform);
235                 copy_v3_v3(tData.cent, mmd->cent);
236         }
237
238         /* get world-space matrix of target, corrected for the space the verts are in */
239         if (mmd->subtarget[0] && pchan) {
240                 /* bone target if there's a matching pose-channel */
241                 mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat);
242         }
243         else {
244                 /* just object target */
245                 copy_m4_m4(dmat, mmd->object->obmat);
246         }
247         invert_m4_m4(ob->imat, ob->obmat);
248         mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv);
249
250         /* loop points and apply deform */
251         for (int i = 0; i < gps->totpoints; i++) {
252                 bGPDspoint *pt = &gps->points[i];
253                 MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
254
255                 /* verify vertex group */
256                 const float weight = get_modifier_point_weight(dvert, (mmd->flag & GP_HOOK_INVERT_VGROUP) != 0, def_nr);
257                 if (weight < 0.0f) {
258                         continue;
259                 }
260                 gp_hook_co_apply(&tData, weight, pt);
261         }
262 }
263
264 /* FIXME: Ideally we be doing this on a copy of the main depsgraph
265  * (i.e. one where we don't have to worry about restoring state)
266  */
267 static void bakeModifier(
268         Main *bmain, Depsgraph *depsgraph,
269         GpencilModifierData *md, Object *ob)
270 {
271         HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
272         Scene *scene = DEG_get_evaluated_scene(depsgraph);
273         bGPdata *gpd = ob->data;
274         int oldframe = (int)DEG_get_ctime(depsgraph);
275
276         if (mmd->object == NULL)
277                 return;
278
279         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
280                 for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
281                         /* apply hook effects on this frame
282                          * NOTE: this assumes that we don't want hook animation on non-keyframed frames
283                          */
284                         CFRA = gpf->framenum;
285                         BKE_scene_graph_update_for_newframe(depsgraph, bmain);
286
287                         /* compute hook effects on this frame */
288                         for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
289                                 deformStroke(md, depsgraph, ob, gpl, gps);
290                         }
291                 }
292         }
293
294         /* return frame state and DB to original state */
295         CFRA = oldframe;
296         BKE_scene_graph_update_for_newframe(depsgraph, bmain);
297 }
298
299 static void freeData(GpencilModifierData *md)
300 {
301         HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
302
303         if (mmd->curfalloff) {
304                 curvemapping_free(mmd->curfalloff);
305         }
306 }
307
308 static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
309 {
310         HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
311
312         return !mmd->object;
313 }
314
315 static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
316 {
317         HookGpencilModifierData *lmd = (HookGpencilModifierData *)md;
318         if (lmd->object != NULL) {
319                 DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Hook Modifier");
320                 DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
321         }
322         DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
323 }
324
325 static void foreachObjectLink(
326         GpencilModifierData *md, Object *ob,
327         ObjectWalkFunc walk, void *userData)
328 {
329         HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
330
331         walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
332 }
333
334 GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
335         /* name */              "Hook",
336         /* structName */        "HookGpencilModifierData",
337         /* structSize */        sizeof(HookGpencilModifierData),
338         /* type */              eGpencilModifierTypeType_Gpencil,
339         /* flags */             0,
340
341         /* copyData */          copyData,
342
343         /* deformStroke */      deformStroke,
344         /* generateStrokes */   NULL,
345         /* bakeModifier */      bakeModifier,
346         /* remapTime */         NULL,
347
348         /* initData */          initData,
349         /* freeData */          freeData,
350         /* isDisabled */        isDisabled,
351         /* updateDepsgraph */   updateDepsgraph,
352         /* dependsOnTime */     NULL,
353         /* foreachObjectLink */ foreachObjectLink,
354         /* foreachIDLink */     NULL,
355         /* foreachTexLink */    NULL,
356         /* getDuplicationFactor */ NULL,
357 };