5446640b2ddcb1244e2fda7817714b414752e132
[blender-staging.git] / source / blender / blenkernel / intern / lattice.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup bke
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <math.h>
27 #include <stdlib.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_utildefines.h"
32 #include "BLI_listbase.h"
33 #include "BLI_bitmap.h"
34 #include "BLI_math.h"
35 #include "BLI_task.h"
36
37 #include "DNA_mesh_types.h"
38 #include "DNA_meshdata_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_lattice_types.h"
42 #include "DNA_curve_types.h"
43 #include "DNA_key_types.h"
44 #include "DNA_defaults.h"
45
46 #include "BKE_animsys.h"
47 #include "BKE_anim.h"
48 #include "BKE_curve.h"
49 #include "BKE_displist.h"
50 #include "BKE_key.h"
51 #include "BKE_lattice.h"
52 #include "BKE_lib_id.h"
53 #include "BKE_main.h"
54 #include "BKE_modifier.h"
55 #include "BKE_object.h"
56
57 #include "BKE_deform.h"
58
59 #include "DEG_depsgraph_query.h"
60
61 int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w)
62 {
63   const int totu = lt->pntsu;
64   const int totv = lt->pntsv;
65
66   return (w * (totu * totv) + (v * totu) + u);
67 }
68
69 void BKE_lattice_index_to_uvw(Lattice *lt, const int index, int *r_u, int *r_v, int *r_w)
70 {
71   const int totu = lt->pntsu;
72   const int totv = lt->pntsv;
73
74   *r_u = (index % totu);
75   *r_v = (index / totu) % totv;
76   *r_w = (index / (totu * totv));
77 }
78
79 int BKE_lattice_index_flip(
80     Lattice *lt, const int index, const bool flip_u, const bool flip_v, const bool flip_w)
81 {
82   int u, v, w;
83
84   BKE_lattice_index_to_uvw(lt, index, &u, &v, &w);
85
86   if (flip_u) {
87     u = (lt->pntsu - 1) - u;
88   }
89
90   if (flip_v) {
91     v = (lt->pntsv - 1) - v;
92   }
93
94   if (flip_w) {
95     w = (lt->pntsw - 1) - w;
96   }
97
98   return BKE_lattice_index_from_uvw(lt, u, v, w);
99 }
100
101 void BKE_lattice_bitmap_from_flag(
102     Lattice *lt, BLI_bitmap *bitmap, const short flag, const bool clear, const bool respecthide)
103 {
104   const unsigned int tot = lt->pntsu * lt->pntsv * lt->pntsw;
105   unsigned int i;
106   BPoint *bp;
107
108   bp = lt->def;
109   for (i = 0; i < tot; i++, bp++) {
110     if ((bp->f1 & flag) && (!respecthide || !bp->hide)) {
111       BLI_BITMAP_ENABLE(bitmap, i);
112     }
113     else {
114       if (clear) {
115         BLI_BITMAP_DISABLE(bitmap, i);
116       }
117     }
118   }
119 }
120
121 void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du)
122 {
123   if (res == 1) {
124     *r_fu = 0.0;
125     *r_du = 0.0;
126   }
127   else if (flag & LT_GRID) {
128     *r_fu = -0.5f * (res - 1);
129     *r_du = 1.0f;
130   }
131   else {
132     *r_fu = -1.0f;
133     *r_du = 2.0f / (res - 1);
134   }
135 }
136
137 void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
138 {
139   BPoint *bp;
140   int i, u, v, w;
141   float fu, fv, fw, uc, vc, wc, du = 0.0, dv = 0.0, dw = 0.0;
142   float *co, (*vert_coords)[3] = NULL;
143
144   /* vertex weight groups are just freed all for now */
145   if (lt->dvert) {
146     BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
147     lt->dvert = NULL;
148   }
149
150   while (uNew * vNew * wNew > 32000) {
151     if (uNew >= vNew && uNew >= wNew) {
152       uNew--;
153     }
154     else if (vNew >= uNew && vNew >= wNew) {
155       vNew--;
156     }
157     else {
158       wNew--;
159     }
160   }
161
162   vert_coords = MEM_mallocN(sizeof(*vert_coords) * uNew * vNew * wNew, "tmp_vcos");
163
164   calc_lat_fudu(lt->flag, uNew, &fu, &du);
165   calc_lat_fudu(lt->flag, vNew, &fv, &dv);
166   calc_lat_fudu(lt->flag, wNew, &fw, &dw);
167
168   /* If old size is different then resolution changed in interface,
169    * try to do clever reinit of points. Pretty simply idea, we just
170    * deform new verts by old lattice, but scaling them to match old
171    * size first.
172    */
173   if (ltOb) {
174     if (uNew != 1 && lt->pntsu != 1) {
175       fu = lt->fu;
176       du = (lt->pntsu - 1) * lt->du / (uNew - 1);
177     }
178
179     if (vNew != 1 && lt->pntsv != 1) {
180       fv = lt->fv;
181       dv = (lt->pntsv - 1) * lt->dv / (vNew - 1);
182     }
183
184     if (wNew != 1 && lt->pntsw != 1) {
185       fw = lt->fw;
186       dw = (lt->pntsw - 1) * lt->dw / (wNew - 1);
187     }
188   }
189
190   co = vert_coords[0];
191   for (w = 0, wc = fw; w < wNew; w++, wc += dw) {
192     for (v = 0, vc = fv; v < vNew; v++, vc += dv) {
193       for (u = 0, uc = fu; u < uNew; u++, co += 3, uc += du) {
194         co[0] = uc;
195         co[1] = vc;
196         co[2] = wc;
197       }
198     }
199   }
200
201   if (ltOb) {
202     float mat[4][4];
203     int typeu = lt->typeu, typev = lt->typev, typew = lt->typew;
204
205     /* works best if we force to linear type (endpoints match) */
206     lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
207
208     if (ltOb->runtime.curve_cache) {
209       /* prevent using deformed locations */
210       BKE_displist_free(&ltOb->runtime.curve_cache->disp);
211     }
212
213     copy_m4_m4(mat, ltOb->obmat);
214     unit_m4(ltOb->obmat);
215     lattice_deform_verts(ltOb, NULL, NULL, vert_coords, uNew * vNew * wNew, 0, NULL, 1.0f);
216     copy_m4_m4(ltOb->obmat, mat);
217
218     lt->typeu = typeu;
219     lt->typev = typev;
220     lt->typew = typew;
221   }
222
223   lt->fu = fu;
224   lt->fv = fv;
225   lt->fw = fw;
226   lt->du = du;
227   lt->dv = dv;
228   lt->dw = dw;
229
230   lt->pntsu = uNew;
231   lt->pntsv = vNew;
232   lt->pntsw = wNew;
233
234   lt->actbp = LT_ACTBP_NONE;
235   MEM_freeN(lt->def);
236   lt->def = MEM_callocN(lt->pntsu * lt->pntsv * lt->pntsw * sizeof(BPoint), "lattice bp");
237
238   bp = lt->def;
239
240   for (i = 0; i < lt->pntsu * lt->pntsv * lt->pntsw; i++, bp++) {
241     copy_v3_v3(bp->vec, vert_coords[i]);
242   }
243
244   MEM_freeN(vert_coords);
245 }
246
247 void BKE_lattice_init(Lattice *lt)
248 {
249   BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lt, id));
250
251   MEMCPY_STRUCT_AFTER(lt, DNA_struct_default_get(Lattice), id);
252
253   lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
254   BKE_lattice_resize(lt, 2, 2, 2, NULL);             /* creates a uniform lattice */
255 }
256
257 Lattice *BKE_lattice_add(Main *bmain, const char *name)
258 {
259   Lattice *lt;
260
261   lt = BKE_libblock_alloc(bmain, ID_LT, name, 0);
262
263   BKE_lattice_init(lt);
264
265   return lt;
266 }
267
268 /**
269  * Only copy internal data of Lattice ID from source
270  * to already allocated/initialized destination.
271  * You probably never want to use that directly,
272  * use #BKE_id_copy or #BKE_id_copy_ex for typical needs.
273  *
274  * WARNING! This function will not handle ID user count!
275  *
276  * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
277  */
278 void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src, const int flag)
279 {
280   lt_dst->def = MEM_dupallocN(lt_src->def);
281
282   if (lt_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
283     BKE_id_copy_ex(bmain, &lt_src->key->id, (ID **)&lt_dst->key, flag);
284     /* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
285     lt_dst->key->from = &lt_dst->id;
286   }
287
288   if (lt_src->dvert) {
289     int tot = lt_src->pntsu * lt_src->pntsv * lt_src->pntsw;
290     lt_dst->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
291     BKE_defvert_array_copy(lt_dst->dvert, lt_src->dvert, tot);
292   }
293
294   lt_dst->editlatt = NULL;
295 }
296
297 Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
298 {
299   Lattice *lt_copy;
300   BKE_id_copy(bmain, &lt->id, (ID **)&lt_copy);
301   return lt_copy;
302 }
303
304 /** Free (or release) any data used by this lattice (does not free the lattice itself). */
305 void BKE_lattice_free(Lattice *lt)
306 {
307   BKE_animdata_free(&lt->id, false);
308
309   BKE_lattice_batch_cache_free(lt);
310
311   MEM_SAFE_FREE(lt->def);
312   if (lt->dvert) {
313     BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
314     lt->dvert = NULL;
315   }
316   if (lt->editlatt) {
317     Lattice *editlt = lt->editlatt->latt;
318
319     if (editlt->def) {
320       MEM_freeN(editlt->def);
321     }
322     if (editlt->dvert) {
323       BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
324     }
325
326     MEM_freeN(editlt);
327     MEM_freeN(lt->editlatt);
328     lt->editlatt = NULL;
329   }
330 }
331
332 void BKE_lattice_make_local(Main *bmain, Lattice *lt, const bool lib_local)
333 {
334   BKE_id_make_local_generic(bmain, &lt->id, true, lib_local);
335 }
336
337 typedef struct LatticeDeformData {
338   Object *object;
339   float *latticedata;
340   float latmat[4][4];
341 } LatticeDeformData;
342
343 LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
344 {
345   /* we make an array with all differences */
346   Lattice *lt = oblatt->data;
347   BPoint *bp;
348   DispList *dl = oblatt->runtime.curve_cache ?
349                      BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) :
350                      NULL;
351   const float *co = dl ? dl->verts : NULL;
352   float *fp, imat[4][4];
353   float fu, fv, fw;
354   int u, v, w;
355   float *latticedata;
356   float latmat[4][4];
357   LatticeDeformData *lattice_deform_data;
358
359   if (lt->editlatt) {
360     lt = lt->editlatt->latt;
361   }
362   bp = lt->def;
363
364   fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw,
365                                  "latticedata");
366
367   /* for example with a particle system: (ob == NULL) */
368   if (ob == NULL) {
369     /* in deformspace, calc matrix  */
370     invert_m4_m4(latmat, oblatt->obmat);
371
372     /* back: put in deform array */
373     invert_m4_m4(imat, latmat);
374   }
375   else {
376     /* in deformspace, calc matrix */
377     invert_m4_m4(imat, oblatt->obmat);
378     mul_m4_m4m4(latmat, imat, ob->obmat);
379
380     /* back: put in deform array */
381     invert_m4_m4(imat, latmat);
382   }
383
384   for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
385     for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
386       for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
387         if (dl) {
388           fp[0] = co[0] - fu;
389           fp[1] = co[1] - fv;
390           fp[2] = co[2] - fw;
391         }
392         else {
393           fp[0] = bp->vec[0] - fu;
394           fp[1] = bp->vec[1] - fv;
395           fp[2] = bp->vec[2] - fw;
396         }
397
398         mul_mat3_m4_v3(imat, fp);
399       }
400     }
401   }
402
403   lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
404   lattice_deform_data->latticedata = latticedata;
405   lattice_deform_data->object = oblatt;
406   copy_m4_m4(lattice_deform_data->latmat, latmat);
407
408   return lattice_deform_data;
409 }
410
411 void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight)
412 {
413   Object *ob = lattice_deform_data->object;
414   Lattice *lt = ob->data;
415   float u, v, w, tu[4], tv[4], tw[4];
416   float vec[3];
417   int idx_w, idx_v, idx_u;
418   int ui, vi, wi, uu, vv, ww;
419
420   /* vgroup influence */
421   int defgrp_index = -1;
422   float co_prev[3], weight_blend = 0.0f;
423   MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
424   float *__restrict latticedata = lattice_deform_data->latticedata;
425
426   if (lt->editlatt) {
427     lt = lt->editlatt->latt;
428   }
429   if (latticedata == NULL) {
430     return;
431   }
432
433   if (lt->vgroup[0] && dvert) {
434     defgrp_index = defgroup_name_index(ob, lt->vgroup);
435     copy_v3_v3(co_prev, co);
436   }
437
438   /* co is in local coords, treat with latmat */
439   mul_v3_m4v3(vec, lattice_deform_data->latmat, co);
440
441   /* u v w coords */
442
443   if (lt->pntsu > 1) {
444     u = (vec[0] - lt->fu) / lt->du;
445     ui = (int)floor(u);
446     u -= ui;
447     key_curve_position_weights(u, tu, lt->typeu);
448   }
449   else {
450     tu[0] = tu[2] = tu[3] = 0.0;
451     tu[1] = 1.0;
452     ui = 0;
453   }
454
455   if (lt->pntsv > 1) {
456     v = (vec[1] - lt->fv) / lt->dv;
457     vi = (int)floor(v);
458     v -= vi;
459     key_curve_position_weights(v, tv, lt->typev);
460   }
461   else {
462     tv[0] = tv[2] = tv[3] = 0.0;
463     tv[1] = 1.0;
464     vi = 0;
465   }
466
467   if (lt->pntsw > 1) {
468     w = (vec[2] - lt->fw) / lt->dw;
469     wi = (int)floor(w);
470     w -= wi;
471     key_curve_position_weights(w, tw, lt->typew);
472   }
473   else {
474     tw[0] = tw[2] = tw[3] = 0.0;
475     tw[1] = 1.0;
476     wi = 0;
477   }
478
479   for (ww = wi - 1; ww <= wi + 2; ww++) {
480     w = tw[ww - wi + 1];
481
482     if (w != 0.0f) {
483       if (ww > 0) {
484         if (ww < lt->pntsw) {
485           idx_w = ww * lt->pntsu * lt->pntsv;
486         }
487         else {
488           idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
489         }
490       }
491       else {
492         idx_w = 0;
493       }
494
495       for (vv = vi - 1; vv <= vi + 2; vv++) {
496         v = w * tv[vv - vi + 1];
497
498         if (v != 0.0f) {
499           if (vv > 0) {
500             if (vv < lt->pntsv) {
501               idx_v = idx_w + vv * lt->pntsu;
502             }
503             else {
504               idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu;
505             }
506           }
507           else {
508             idx_v = idx_w;
509           }
510
511           for (uu = ui - 1; uu <= ui + 2; uu++) {
512             u = weight * v * tu[uu - ui + 1];
513
514             if (u != 0.0f) {
515               if (uu > 0) {
516                 if (uu < lt->pntsu) {
517                   idx_u = idx_v + uu;
518                 }
519                 else {
520                   idx_u = idx_v + (lt->pntsu - 1);
521                 }
522               }
523               else {
524                 idx_u = idx_v;
525               }
526
527               madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
528
529               if (defgrp_index != -1) {
530                 weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index));
531               }
532             }
533           }
534         }
535       }
536     }
537   }
538
539   if (defgrp_index != -1) {
540     interp_v3_v3v3(co, co_prev, co, weight_blend);
541   }
542 }
543
544 void end_latt_deform(LatticeDeformData *lattice_deform_data)
545 {
546   if (lattice_deform_data->latticedata) {
547     MEM_freeN(lattice_deform_data->latticedata);
548   }
549
550   MEM_freeN(lattice_deform_data);
551 }
552
553 /* calculations is in local space of deformed object
554  * so we store in latmat transform from path coord inside object
555  */
556 typedef struct {
557   float dmin[3], dmax[3];
558   float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
559   int no_rot_axis;
560 } CurveDeform;
561
562 static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
563 {
564   invert_m4_m4(ob->imat, ob->obmat);
565   mul_m4_m4m4(cd->objectspace, ob->imat, par->obmat);
566   invert_m4_m4(cd->curvespace, cd->objectspace);
567   copy_m3_m4(cd->objectspace3, cd->objectspace);
568   cd->no_rot_axis = 0;
569 }
570
571 /* this makes sure we can extend for non-cyclic.
572  *
573  * returns OK: 1/0
574  */
575 static bool where_on_path_deform(
576     Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius)
577 {
578   BevList *bl;
579   float ctime1;
580   int cycl = 0;
581
582   /* test for cyclic */
583   bl = ob->runtime.curve_cache->bev.first;
584   if (!bl->nr) {
585     return false;
586   }
587   if (bl->poly > -1) {
588     cycl = 1;
589   }
590
591   if (cycl == 0) {
592     ctime1 = CLAMPIS(ctime, 0.0f, 1.0f);
593   }
594   else {
595     ctime1 = ctime;
596   }
597
598   /* vec needs 4 items */
599   if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
600
601     if (cycl == 0) {
602       Path *path = ob->runtime.curve_cache->path;
603       float dvec[3];
604
605       if (ctime < 0.0f) {
606         sub_v3_v3v3(dvec, path->data[1].vec, path->data[0].vec);
607         mul_v3_fl(dvec, ctime * (float)path->len);
608         add_v3_v3(vec, dvec);
609         if (quat) {
610           copy_qt_qt(quat, path->data[0].quat);
611         }
612         if (radius) {
613           *radius = path->data[0].radius;
614         }
615       }
616       else if (ctime > 1.0f) {
617         sub_v3_v3v3(dvec, path->data[path->len - 1].vec, path->data[path->len - 2].vec);
618         mul_v3_fl(dvec, (ctime - 1.0f) * (float)path->len);
619         add_v3_v3(vec, dvec);
620         if (quat) {
621           copy_qt_qt(quat, path->data[path->len - 1].quat);
622         }
623         if (radius) {
624           *radius = path->data[path->len - 1].radius;
625         }
626         /* weight - not used but could be added */
627       }
628     }
629     return true;
630   }
631   return false;
632 }
633
634 /* for each point, rotate & translate to curve */
635 /* use path, since it has constant distances */
636 /* co: local coord, result local too */
637 /* returns quaternion for rotation, using cd->no_rot_axis */
638 /* axis is using another define!!! */
639 static bool calc_curve_deform(
640     Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4])
641 {
642   Curve *cu = par->data;
643   float fac, loc[4], dir[3], new_quat[4], radius;
644   short index;
645   const bool is_neg_axis = (axis > 2);
646
647   if (par->runtime.curve_cache == NULL) {
648     /* Happens with a cyclic dependencies. */
649     return false;
650   }
651
652   if (par->runtime.curve_cache->path == NULL) {
653     return false; /* happens on append, cyclic dependencies and empty curves */
654   }
655
656   /* options */
657   if (is_neg_axis) {
658     index = axis - 3;
659     if (cu->flag & CU_STRETCH) {
660       fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
661     }
662     else {
663       fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
664     }
665   }
666   else {
667     index = axis;
668     if (cu->flag & CU_STRETCH) {
669       fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
670     }
671     else {
672       if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
673         fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
674       }
675       else {
676         fac = 0.0f;
677       }
678     }
679   }
680
681   if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */
682     float quat[4], cent[3];
683
684     if (cd->no_rot_axis) { /* set by caller */
685
686       /* This is not exactly the same as 2.4x, since the axis is having rotation removed rather
687        * than changing the axis before calculating the tilt but serves much the same purpose. */
688       float dir_flat[3] = {0, 0, 0}, q[4];
689       copy_v3_v3(dir_flat, dir);
690       dir_flat[cd->no_rot_axis - 1] = 0.0f;
691
692       normalize_v3(dir);
693       normalize_v3(dir_flat);
694
695       rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */
696
697       mul_qt_qtqt(new_quat, q, new_quat);
698     }
699
700     /* Logic for 'cent' orientation *
701      *
702      * The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
703      *
704      * Use a curve modifier to stretch a cube out, color each side RGB,
705      * positive side light, negative dark.
706      * view with X up (default), from the angle that you can see 3 faces RGB colors (light),
707      * anti-clockwise
708      * Notice X,Y,Z Up all have light colors and each ordered CCW.
709      *
710      * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
711      *
712      * note: moved functions into quat_apply_track/vec_apply_track
713      * */
714     copy_qt_qt(quat, new_quat);
715     copy_v3_v3(cent, co);
716
717     /* zero the axis which is not used,
718      * the big block of text above now applies to these 3 lines */
719     quat_apply_track(
720         quat,
721         axis,
722         (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */
723     vec_apply_track(cent, axis);
724     cent[index] = 0.0f;
725
726     /* scale if enabled */
727     if (cu->flag & CU_PATH_RADIUS) {
728       mul_v3_fl(cent, radius);
729     }
730
731     /* local rotation */
732     normalize_qt(quat);
733     mul_qt_v3(quat, cent);
734
735     /* translation */
736     add_v3_v3v3(co, cent, loc);
737
738     if (r_quat) {
739       copy_qt_qt(r_quat, quat);
740     }
741
742     return true;
743   }
744   return false;
745 }
746
747 void curve_deform_verts(Object *cuOb,
748                         Object *target,
749                         float (*vert_coords)[3],
750                         int numVerts,
751                         MDeformVert *dvert,
752                         const int defgrp_index,
753                         short flag,
754                         short defaxis)
755 {
756   Curve *cu;
757   int a;
758   CurveDeform cd;
759   const bool is_neg_axis = (defaxis > 2);
760   const bool invert_vgroup = (flag & MOD_CURVE_INVERT_VGROUP) != 0;
761
762   if (cuOb->type != OB_CURVE) {
763     return;
764   }
765
766   cu = cuOb->data;
767
768   init_curve_deform(cuOb, target, &cd);
769
770   /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
771   if (is_neg_axis == false) {
772     cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
773     cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
774   }
775   else {
776     /* negative, these bounds give a good rest position */
777     cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
778     cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
779   }
780
781   if (dvert) {
782     MDeformVert *dvert_iter;
783     float vec[3];
784
785     if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
786       for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
787         const float weight = invert_vgroup ? 1.0f - defvert_find_weight(dvert_iter, defgrp_index) :
788                                              defvert_find_weight(dvert_iter, defgrp_index);
789
790         if (weight > 0.0f) {
791           mul_m4_v3(cd.curvespace, vert_coords[a]);
792           copy_v3_v3(vec, vert_coords[a]);
793           calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
794           interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight);
795           mul_m4_v3(cd.objectspace, vert_coords[a]);
796         }
797       }
798     }
799     else {
800       /* set mesh min/max bounds */
801       INIT_MINMAX(cd.dmin, cd.dmax);
802
803       for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
804         const float weight = invert_vgroup ? 1.0f - defvert_find_weight(dvert_iter, defgrp_index) :
805                                              defvert_find_weight(dvert_iter, defgrp_index);
806         if (weight > 0.0f) {
807           mul_m4_v3(cd.curvespace, vert_coords[a]);
808           minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
809         }
810       }
811
812       for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
813         const float weight = invert_vgroup ? 1.0f - defvert_find_weight(dvert_iter, defgrp_index) :
814                                              defvert_find_weight(dvert_iter, defgrp_index);
815
816         if (weight > 0.0f) {
817           /* already in 'cd.curvespace', prev for loop */
818           copy_v3_v3(vec, vert_coords[a]);
819           calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
820           interp_v3_v3v3(vert_coords[a], vert_coords[a], vec, weight);
821           mul_m4_v3(cd.objectspace, vert_coords[a]);
822         }
823       }
824     }
825   }
826   else {
827     if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
828       for (a = 0; a < numVerts; a++) {
829         mul_m4_v3(cd.curvespace, vert_coords[a]);
830         calc_curve_deform(cuOb, vert_coords[a], defaxis, &cd, NULL);
831         mul_m4_v3(cd.objectspace, vert_coords[a]);
832       }
833     }
834     else {
835       /* set mesh min max bounds */
836       INIT_MINMAX(cd.dmin, cd.dmax);
837
838       for (a = 0; a < numVerts; a++) {
839         mul_m4_v3(cd.curvespace, vert_coords[a]);
840         minmax_v3v3_v3(cd.dmin, cd.dmax, vert_coords[a]);
841       }
842
843       for (a = 0; a < numVerts; a++) {
844         /* already in 'cd.curvespace', prev for loop */
845         calc_curve_deform(cuOb, vert_coords[a], defaxis, &cd, NULL);
846         mul_m4_v3(cd.objectspace, vert_coords[a]);
847       }
848     }
849   }
850 }
851
852 /* input vec and orco = local coord in armature space */
853 /* orco is original not-animated or deformed reference point */
854 /* result written in vec and mat */
855 void curve_deform_vector(
856     Object *cuOb, Object *target, float orco[3], float vec[3], float mat[3][3], int no_rot_axis)
857 {
858   CurveDeform cd;
859   float quat[4];
860
861   if (cuOb->type != OB_CURVE) {
862     unit_m3(mat);
863     return;
864   }
865
866   init_curve_deform(cuOb, target, &cd);
867   cd.no_rot_axis = no_rot_axis; /* option to only rotate for XY, for example */
868
869   copy_v3_v3(cd.dmin, orco);
870   copy_v3_v3(cd.dmax, orco);
871
872   mul_m4_v3(cd.curvespace, vec);
873
874   if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) {
875     float qmat[3][3];
876
877     quat_to_mat3(qmat, quat);
878     mul_m3_m3m3(mat, qmat, cd.objectspace3);
879   }
880   else {
881     unit_m3(mat);
882   }
883
884   mul_m4_v3(cd.objectspace, vec);
885 }
886
887 typedef struct LatticeDeformUserdata {
888   LatticeDeformData *lattice_deform_data;
889   float (*vert_coords)[3];
890   MDeformVert *dvert;
891   int defgrp_index;
892   float fac;
893   bool invert_vgroup;
894 } LatticeDeformUserdata;
895
896 static void lattice_deform_vert_task(void *__restrict userdata,
897                                      const int index,
898                                      const TaskParallelTLS *__restrict UNUSED(tls))
899 {
900   const LatticeDeformUserdata *data = userdata;
901
902   if (data->dvert != NULL) {
903     const float weight = data->invert_vgroup ?
904                              1.0f - defvert_find_weight(data->dvert + index, data->defgrp_index) :
905                              defvert_find_weight(data->dvert + index, data->defgrp_index);
906     if (weight > 0.0f) {
907       calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], weight * data->fac);
908     }
909   }
910   else {
911     calc_latt_deform(data->lattice_deform_data, data->vert_coords[index], data->fac);
912   }
913 }
914
915 void lattice_deform_verts(Object *laOb,
916                           Object *target,
917                           Mesh *mesh,
918                           float (*vert_coords)[3],
919                           int numVerts,
920                           short flag,
921                           const char *vgroup,
922                           float fac)
923 {
924   LatticeDeformData *lattice_deform_data;
925   MDeformVert *dvert = NULL;
926   int defgrp_index = -1;
927
928   if (laOb->type != OB_LATTICE) {
929     return;
930   }
931
932   lattice_deform_data = init_latt_deform(laOb, target);
933
934   /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice).
935    * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
936    */
937   if (vgroup && vgroup[0] && target && ELEM(target->type, OB_MESH, OB_LATTICE)) {
938     defgrp_index = defgroup_name_index(target, vgroup);
939
940     if (defgrp_index != -1) {
941       /* if there's derived data without deformverts, don't use vgroups */
942       if (mesh) {
943         dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
944       }
945       else if (target->type == OB_LATTICE) {
946         dvert = ((Lattice *)target->data)->dvert;
947       }
948       else {
949         dvert = ((Mesh *)target->data)->dvert;
950       }
951     }
952   }
953
954   LatticeDeformUserdata data = {
955       .lattice_deform_data = lattice_deform_data,
956       .vert_coords = vert_coords,
957       .dvert = dvert,
958       .defgrp_index = defgrp_index,
959       .fac = fac,
960       .invert_vgroup = (flag & MOD_LATTICE_INVERT_VGROUP) != 0,
961   };
962
963   TaskParallelSettings settings;
964   BLI_parallel_range_settings_defaults(&settings);
965   settings.min_iter_per_thread = 32;
966   BLI_task_parallel_range(0, numVerts, &data, lattice_deform_vert_task, &settings);
967
968   end_latt_deform(lattice_deform_data);
969 }
970
971 bool object_deform_mball(Object *ob, ListBase *dispbase)
972 {
973   if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) {
974     DispList *dl;
975
976     for (dl = dispbase->first; dl; dl = dl->next) {
977       lattice_deform_verts(ob->parent, ob, NULL, (float(*)[3])dl->verts, dl->nr, 0, NULL, 1.0f);
978     }
979
980     return true;
981   }
982   else {
983     return false;
984   }
985 }
986
987 static BPoint *latt_bp(Lattice *lt, int u, int v, int w)
988 {
989   return &lt->def[BKE_lattice_index_from_uvw(lt, u, v, w)];
990 }
991
992 void outside_lattice(Lattice *lt)
993 {
994   BPoint *bp, *bp1, *bp2;
995   int u, v, w;
996   float fac1, du = 0.0, dv = 0.0, dw = 0.0;
997
998   if (lt->flag & LT_OUTSIDE) {
999     bp = lt->def;
1000
1001     if (lt->pntsu > 1) {
1002       du = 1.0f / ((float)lt->pntsu - 1);
1003     }
1004     if (lt->pntsv > 1) {
1005       dv = 1.0f / ((float)lt->pntsv - 1);
1006     }
1007     if (lt->pntsw > 1) {
1008       dw = 1.0f / ((float)lt->pntsw - 1);
1009     }
1010
1011     for (w = 0; w < lt->pntsw; w++) {
1012
1013       for (v = 0; v < lt->pntsv; v++) {
1014
1015         for (u = 0; u < lt->pntsu; u++, bp++) {
1016           if (u == 0 || v == 0 || w == 0 || u == lt->pntsu - 1 || v == lt->pntsv - 1 ||
1017               w == lt->pntsw - 1) {
1018             /* pass */
1019           }
1020           else {
1021             bp->hide = 1;
1022             bp->f1 &= ~SELECT;
1023
1024             /* u extrema */
1025             bp1 = latt_bp(lt, 0, v, w);
1026             bp2 = latt_bp(lt, lt->pntsu - 1, v, w);
1027
1028             fac1 = du * u;
1029             bp->vec[0] = (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
1030             bp->vec[1] = (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
1031             bp->vec[2] = (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
1032
1033             /* v extrema */
1034             bp1 = latt_bp(lt, u, 0, w);
1035             bp2 = latt_bp(lt, u, lt->pntsv - 1, w);
1036
1037             fac1 = dv * v;
1038             bp->vec[0] += (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
1039             bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
1040             bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
1041
1042             /* w extrema */
1043             bp1 = latt_bp(lt, u, v, 0);
1044             bp2 = latt_bp(lt, u, v, lt->pntsw - 1);
1045
1046             fac1 = dw * w;
1047             bp->vec[0] += (1.0f - fac1) * bp1->vec[0] + fac1 * bp2->vec[0];
1048             bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
1049             bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
1050
1051             mul_v3_fl(bp->vec, 1.0f / 3.0f);
1052           }
1053         }
1054       }
1055     }
1056   }
1057   else {
1058     bp = lt->def;
1059
1060     for (w = 0; w < lt->pntsw; w++) {
1061       for (v = 0; v < lt->pntsv; v++) {
1062         for (u = 0; u < lt->pntsu; u++, bp++) {
1063           bp->hide = 0;
1064         }
1065       }
1066     }
1067   }
1068 }
1069
1070 void BKE_lattice_vert_coords_get(const Lattice *lt, float (*vert_coords)[3])
1071 {
1072   const int vert_len = lt->pntsu * lt->pntsv * lt->pntsw;
1073   for (int i = 0; i < vert_len; i++) {
1074     copy_v3_v3(vert_coords[i], lt->def[i].vec);
1075   }
1076 }
1077
1078 float (*BKE_lattice_vert_coords_alloc(const Lattice *lt, int *r_vert_len))[3]
1079 {
1080   const int vert_len = *r_vert_len = lt->pntsu * lt->pntsv * lt->pntsw;
1081   float(*vert_coords)[3] = MEM_mallocN(sizeof(*vert_coords) * vert_len, __func__);
1082   BKE_lattice_vert_coords_get(lt, vert_coords);
1083   return vert_coords;
1084 }
1085
1086 void BKE_lattice_vert_coords_apply_with_mat4(struct Lattice *lt,
1087                                              const float (*vertexCos)[3],
1088                                              const float mat[4][4])
1089 {
1090   int i, numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
1091   for (i = 0; i < numVerts; i++) {
1092     mul_v3_m4v3(lt->def[i].vec, mat, vertexCos[i]);
1093   }
1094 }
1095
1096 void BKE_lattice_vert_coords_apply(Lattice *lt, const float (*vert_coords)[3])
1097 {
1098   const int vert_len = lt->pntsu * lt->pntsv * lt->pntsw;
1099   for (int i = 0; i < vert_len; i++) {
1100     copy_v3_v3(lt->def[i].vec, vert_coords[i]);
1101   }
1102 }
1103
1104 void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
1105 {
1106   Lattice *lt = ob->data;
1107   /* Get vertex coordinates from the original copy;
1108    * otherwise we get already-modified coordinates. */
1109   Object *ob_orig = DEG_get_original_object(ob);
1110   VirtualModifierData virtualModifierData;
1111   ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
1112   float(*vert_coords)[3] = NULL;
1113   int numVerts, editmode = (lt->editlatt != NULL);
1114   const ModifierEvalContext mectx = {depsgraph, ob, 0};
1115
1116   if (ob->runtime.curve_cache) {
1117     BKE_displist_free(&ob->runtime.curve_cache->disp);
1118   }
1119   else {
1120     ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
1121   }
1122
1123   for (; md; md = md->next) {
1124     const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
1125
1126     if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) {
1127       continue;
1128     }
1129     if (!(md->mode & eModifierMode_Realtime)) {
1130       continue;
1131     }
1132     if (editmode && !(md->mode & eModifierMode_Editmode)) {
1133       continue;
1134     }
1135     if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
1136       continue;
1137     }
1138     if (mti->type != eModifierTypeType_OnlyDeform) {
1139       continue;
1140     }
1141
1142     if (!vert_coords) {
1143       Lattice *lt_orig = ob_orig->data;
1144       if (lt_orig->editlatt) {
1145         lt_orig = lt_orig->editlatt->latt;
1146       }
1147       vert_coords = BKE_lattice_vert_coords_alloc(lt_orig, &numVerts);
1148     }
1149     mti->deformVerts(md, &mectx, NULL, vert_coords, numVerts);
1150   }
1151
1152   if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) {
1153     if (vert_coords) {
1154       BKE_lattice_vert_coords_apply(ob->data, vert_coords);
1155       MEM_freeN(vert_coords);
1156     }
1157   }
1158   else {
1159     /* Displist won't do anything; this is just for posterity's sake until we remove it. */
1160     if (!vert_coords) {
1161       Lattice *lt_orig = ob_orig->data;
1162       if (lt_orig->editlatt) {
1163         lt_orig = lt_orig->editlatt->latt;
1164       }
1165       vert_coords = BKE_lattice_vert_coords_alloc(lt_orig, &numVerts);
1166     }
1167
1168     DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
1169     dl->type = DL_VERTS;
1170     dl->parts = 1;
1171     dl->nr = numVerts;
1172     dl->verts = (float *)vert_coords;
1173
1174     BLI_addtail(&ob->runtime.curve_cache->disp, dl);
1175   }
1176 }
1177
1178 struct MDeformVert *BKE_lattice_deform_verts_get(struct Object *oblatt)
1179 {
1180   Lattice *lt = (Lattice *)oblatt->data;
1181   BLI_assert(oblatt->type == OB_LATTICE);
1182   if (lt->editlatt) {
1183     lt = lt->editlatt->latt;
1184   }
1185   return lt->dvert;
1186 }
1187
1188 struct BPoint *BKE_lattice_active_point_get(Lattice *lt)
1189 {
1190   BLI_assert(GS(lt->id.name) == ID_LT);
1191
1192   if (lt->editlatt) {
1193     lt = lt->editlatt->latt;
1194   }
1195
1196   BLI_assert(lt->actbp < lt->pntsu * lt->pntsv * lt->pntsw);
1197
1198   if ((lt->actbp != LT_ACTBP_NONE) && (lt->actbp < lt->pntsu * lt->pntsv * lt->pntsw)) {
1199     return &lt->def[lt->actbp];
1200   }
1201   else {
1202     return NULL;
1203   }
1204 }
1205
1206 void BKE_lattice_center_median(Lattice *lt, float cent[3])
1207 {
1208   int i, numVerts;
1209
1210   if (lt->editlatt) {
1211     lt = lt->editlatt->latt;
1212   }
1213   numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
1214
1215   zero_v3(cent);
1216
1217   for (i = 0; i < numVerts; i++) {
1218     add_v3_v3(cent, lt->def[i].vec);
1219   }
1220
1221   mul_v3_fl(cent, 1.0f / (float)numVerts);
1222 }
1223
1224 static void boundbox_lattice(Object *ob)
1225 {
1226   BoundBox *bb;
1227   Lattice *lt;
1228   float min[3], max[3];
1229
1230   if (ob->runtime.bb == NULL) {
1231     ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "Lattice boundbox");
1232   }
1233
1234   bb = ob->runtime.bb;
1235   lt = ob->data;
1236
1237   INIT_MINMAX(min, max);
1238   BKE_lattice_minmax_dl(ob, lt, min, max);
1239   BKE_boundbox_init_from_minmax(bb, min, max);
1240
1241   bb->flag &= ~BOUNDBOX_DIRTY;
1242 }
1243
1244 BoundBox *BKE_lattice_boundbox_get(Object *ob)
1245 {
1246   boundbox_lattice(ob);
1247
1248   return ob->runtime.bb;
1249 }
1250
1251 void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3])
1252 {
1253   DispList *dl = ob->runtime.curve_cache ?
1254                      BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) :
1255                      NULL;
1256
1257   if (!dl) {
1258     BKE_lattice_minmax(lt, min, max);
1259   }
1260   else {
1261     int i, numVerts;
1262
1263     if (lt->editlatt) {
1264       lt = lt->editlatt->latt;
1265     }
1266     numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
1267
1268     for (i = 0; i < numVerts; i++) {
1269       minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
1270     }
1271   }
1272 }
1273
1274 void BKE_lattice_minmax(Lattice *lt, float min[3], float max[3])
1275 {
1276   int i, numVerts;
1277
1278   if (lt->editlatt) {
1279     lt = lt->editlatt->latt;
1280   }
1281   numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
1282
1283   for (i = 0; i < numVerts; i++) {
1284     minmax_v3v3_v3(min, max, lt->def[i].vec);
1285   }
1286 }
1287
1288 void BKE_lattice_center_bounds(Lattice *lt, float cent[3])
1289 {
1290   float min[3], max[3];
1291
1292   INIT_MINMAX(min, max);
1293
1294   BKE_lattice_minmax(lt, min, max);
1295   mid_v3_v3v3(cent, min, max);
1296 }
1297
1298 void BKE_lattice_transform(Lattice *lt, float mat[4][4], bool do_keys)
1299 {
1300   BPoint *bp = lt->def;
1301   int i = lt->pntsu * lt->pntsv * lt->pntsw;
1302
1303   while (i--) {
1304     mul_m4_v3(mat, bp->vec);
1305     bp++;
1306   }
1307
1308   if (do_keys && lt->key) {
1309     KeyBlock *kb;
1310
1311     for (kb = lt->key->block.first; kb; kb = kb->next) {
1312       float *fp = kb->data;
1313       for (i = kb->totelem; i--; fp += 3) {
1314         mul_m4_v3(mat, fp);
1315       }
1316     }
1317   }
1318 }
1319
1320 void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
1321 {
1322   int i, numVerts;
1323
1324   numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
1325
1326   if (lt->def) {
1327     for (i = 0; i < numVerts; i++) {
1328       add_v3_v3(lt->def[i].vec, offset);
1329     }
1330   }
1331
1332   if (lt->editlatt) {
1333     for (i = 0; i < numVerts; i++) {
1334       add_v3_v3(lt->editlatt->latt->def[i].vec, offset);
1335     }
1336   }
1337
1338   if (do_keys && lt->key) {
1339     KeyBlock *kb;
1340
1341     for (kb = lt->key->block.first; kb; kb = kb->next) {
1342       float *fp = kb->data;
1343       for (i = kb->totelem; i--; fp += 3) {
1344         add_v3_v3(fp, offset);
1345       }
1346     }
1347   }
1348 }
1349
1350 bool BKE_lattice_is_any_selected(const Lattice *lt)
1351 {
1352   /* Intentionally don't handle 'lt->editlatt' (caller must do this). */
1353   const BPoint *bp = lt->def;
1354   int a = lt->pntsu * lt->pntsv * lt->pntsw;
1355   while (a--) {
1356     if (bp->hide == 0) {
1357       if (bp->f1 & SELECT) {
1358         return true;
1359       }
1360     }
1361     bp++;
1362   }
1363   return false;
1364 }
1365
1366 /* **** Depsgraph evaluation **** */
1367
1368 void BKE_lattice_eval_geometry(struct Depsgraph *UNUSED(depsgraph), Lattice *UNUSED(latt))
1369 {
1370 }
1371
1372 /* Draw Engine */
1373 void (*BKE_lattice_batch_cache_dirty_tag_cb)(Lattice *lt, int mode) = NULL;
1374 void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL;
1375
1376 void BKE_lattice_batch_cache_dirty_tag(Lattice *lt, int mode)
1377 {
1378   if (lt->batch_cache) {
1379     BKE_lattice_batch_cache_dirty_tag_cb(lt, mode);
1380   }
1381 }
1382 void BKE_lattice_batch_cache_free(Lattice *lt)
1383 {
1384   if (lt->batch_cache) {
1385     BKE_lattice_batch_cache_free_cb(lt);
1386   }
1387 }