Blender  V2.93
MOD_laplaciandeform.c
Go to the documentation of this file.
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) 2013 by the Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "BLI_utildefines.h"
25 
26 #include "BLI_math.h"
27 #include "BLI_string.h"
28 #include "BLI_utildefines_stack.h"
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLT_translation.h"
33 
34 #include "DNA_defaults.h"
35 #include "DNA_mesh_types.h"
36 #include "DNA_meshdata_types.h"
37 #include "DNA_screen_types.h"
38 
39 #include "BKE_context.h"
40 #include "BKE_deform.h"
41 #include "BKE_editmesh.h"
42 #include "BKE_lib_id.h"
43 #include "BKE_mesh.h"
44 #include "BKE_mesh_mapping.h"
45 #include "BKE_mesh_runtime.h"
46 #include "BKE_mesh_wrapper.h"
47 #include "BKE_particle.h"
48 #include "BKE_screen.h"
49 
50 #include "UI_interface.h"
51 #include "UI_resources.h"
52 
53 #include "BLO_read_write.h"
54 
55 #include "RNA_access.h"
56 
57 #include "MOD_ui_common.h"
58 #include "MOD_util.h"
59 
60 #include "eigen_capi.h"
61 
62 enum {
71 };
72 
73 typedef struct LaplacianSystem {
80  int repeat;
81  char anchor_grp_name[64]; /* Vertex Group name */
82  float (*co)[3]; /* Original vertex coordinates */
83  float (*no)[3]; /* Original vertex normal */
84  float (*delta)[3]; /* Differential Coordinates */
85  uint (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
86  int *index_anchors; /* Static vertex index list */
87  int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */
88  int *ringf_indices; /* Indices of faces per vertex */
89  int *ringv_indices; /* Indices of neighbors(vertex) per vertex */
90  LinearSolver *context; /* System for solve general implicit rotations */
91  MeshElemMap *ringf_map; /* Map of faces per vertex */
92  MeshElemMap *ringv_map; /* Map of vertex per vertex */
94 
96 {
97  LaplacianSystem *sys;
98  sys = MEM_callocN(sizeof(LaplacianSystem), "DeformCache");
99 
100  sys->is_matrix_computed = false;
101  sys->has_solution = false;
102  sys->total_verts = 0;
103  sys->total_edges = 0;
104  sys->total_anchors = 0;
105  sys->total_tris = 0;
106  sys->repeat = 1;
107  sys->anchor_grp_name[0] = '\0';
108 
109  return sys;
110 }
111 
112 static LaplacianSystem *initLaplacianSystem(int totalVerts,
113  int totalEdges,
114  int totalTris,
115  int totalAnchors,
116  const char defgrpName[64],
117  int iterations)
118 {
120 
121  sys->is_matrix_computed = false;
122  sys->has_solution = false;
123  sys->total_verts = totalVerts;
124  sys->total_edges = totalEdges;
125  sys->total_tris = totalTris;
126  sys->total_anchors = totalAnchors;
127  sys->repeat = iterations;
128  BLI_strncpy(sys->anchor_grp_name, defgrpName, sizeof(sys->anchor_grp_name));
129  sys->co = MEM_malloc_arrayN(totalVerts, sizeof(float[3]), "DeformCoordinates");
130  sys->no = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformNormals");
131  sys->delta = MEM_calloc_arrayN(totalVerts, sizeof(float[3]), "DeformDeltas");
132  sys->tris = MEM_malloc_arrayN(totalTris, sizeof(int[3]), "DeformFaces");
133  sys->index_anchors = MEM_malloc_arrayN((totalAnchors), sizeof(int), "DeformAnchors");
134  sys->unit_verts = MEM_calloc_arrayN(totalVerts, sizeof(int), "DeformUnitVerts");
135  return sys;
136 }
137 
139 {
140  MEM_SAFE_FREE(sys->co);
141  MEM_SAFE_FREE(sys->no);
142  MEM_SAFE_FREE(sys->delta);
143  MEM_SAFE_FREE(sys->tris);
148  MEM_SAFE_FREE(sys->ringf_map);
149  MEM_SAFE_FREE(sys->ringv_map);
150 
151  if (sys->context) {
153  }
154  MEM_SAFE_FREE(sys);
155 }
156 
157 static void createFaceRingMap(const int mvert_tot,
158  const MLoopTri *mlooptri,
159  const int mtri_tot,
160  const MLoop *mloop,
161  MeshElemMap **r_map,
162  int **r_indices)
163 {
164  int i, j, totalr = 0;
165  int *indices, *index_iter;
166  MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformRingMap");
167  const MLoopTri *mlt;
168 
169  for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
170 
171  for (j = 0; j < 3; j++) {
172  const uint v_index = mloop[mlt->tri[j]].v;
173  map[v_index].count++;
174  totalr++;
175  }
176  }
177  indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformRingIndex");
178  index_iter = indices;
179  for (i = 0; i < mvert_tot; i++) {
180  map[i].indices = index_iter;
181  index_iter += map[i].count;
182  map[i].count = 0;
183  }
184  for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
185  for (j = 0; j < 3; j++) {
186  const uint v_index = mloop[mlt->tri[j]].v;
187  map[v_index].indices[map[v_index].count] = i;
188  map[v_index].count++;
189  }
190  }
191  *r_map = map;
192  *r_indices = indices;
193 }
194 
195 static void createVertRingMap(const int mvert_tot,
196  const MEdge *medge,
197  const int medge_tot,
198  MeshElemMap **r_map,
199  int **r_indices)
200 {
201  MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformNeighborsMap");
202  int i, vid[2], totalr = 0;
203  int *indices, *index_iter;
204  const MEdge *me;
205 
206  for (i = 0, me = medge; i < medge_tot; i++, me++) {
207  vid[0] = me->v1;
208  vid[1] = me->v2;
209  map[vid[0]].count++;
210  map[vid[1]].count++;
211  totalr += 2;
212  }
213  indices = MEM_calloc_arrayN(totalr, sizeof(int), "DeformNeighborsIndex");
214  index_iter = indices;
215  for (i = 0; i < mvert_tot; i++) {
216  map[i].indices = index_iter;
217  index_iter += map[i].count;
218  map[i].count = 0;
219  }
220  for (i = 0, me = medge; i < medge_tot; i++, me++) {
221  vid[0] = me->v1;
222  vid[1] = me->v2;
223  map[vid[0]].indices[map[vid[0]].count] = vid[1];
224  map[vid[0]].count++;
225  map[vid[1]].indices[map[vid[1]].count] = vid[0];
226  map[vid[1]].count++;
227  }
228  *r_map = map;
229  *r_indices = indices;
230 }
231 
265 {
266  float no[3];
267  float w2, w3;
268  int i = 3, j, ti;
269  int idv[3];
270 
271  for (ti = 0; ti < sys->total_tris; ti++) {
272  const uint *vidt = sys->tris[ti];
273  const float *co[3];
274 
275  co[0] = sys->co[vidt[0]];
276  co[1] = sys->co[vidt[1]];
277  co[2] = sys->co[vidt[2]];
278 
279  normal_tri_v3(no, UNPACK3(co));
280  add_v3_v3(sys->no[vidt[0]], no);
281  add_v3_v3(sys->no[vidt[1]], no);
282  add_v3_v3(sys->no[vidt[2]], no);
283 
284  for (j = 0; j < 3; j++) {
285  const float *v1, *v2, *v3;
286 
287  idv[0] = vidt[j];
288  idv[1] = vidt[(j + 1) % i];
289  idv[2] = vidt[(j + 2) % i];
290 
291  v1 = sys->co[idv[0]];
292  v2 = sys->co[idv[1]];
293  v3 = sys->co[idv[2]];
294 
295  w2 = cotangent_tri_weight_v3(v3, v1, v2);
296  w3 = cotangent_tri_weight_v3(v2, v3, v1);
297 
298  sys->delta[idv[0]][0] += v1[0] * (w2 + w3);
299  sys->delta[idv[0]][1] += v1[1] * (w2 + w3);
300  sys->delta[idv[0]][2] += v1[2] * (w2 + w3);
301 
302  sys->delta[idv[0]][0] -= v2[0] * w2;
303  sys->delta[idv[0]][1] -= v2[1] * w2;
304  sys->delta[idv[0]][2] -= v2[2] * w2;
305 
306  sys->delta[idv[0]][0] -= v3[0] * w3;
307  sys->delta[idv[0]][1] -= v3[1] * w3;
308  sys->delta[idv[0]][2] -= v3[2] * w3;
309 
310  EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2);
311  EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3);
312  EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3);
313  }
314  }
315 }
316 
318 {
319  int vid, *vidn = NULL;
320  float minj, mjt, qj[3], vj[3];
321  int i, j, ln;
322 
323  for (i = 0; i < sys->total_verts; i++) {
324  normalize_v3(sys->no[i]);
325  vidn = sys->ringv_map[i].indices;
326  ln = sys->ringv_map[i].count;
327  minj = 1000000.0f;
328  for (j = 0; j < ln; j++) {
329  vid = vidn[j];
330  copy_v3_v3(qj, sys->co[vid]);
331  sub_v3_v3v3(vj, qj, sys->co[i]);
332  normalize_v3(vj);
333  mjt = fabsf(dot_v3v3(vj, sys->no[i]));
334  if (mjt < minj) {
335  minj = mjt;
336  sys->unit_verts[i] = vidn[j];
337  }
338  }
339  }
340 }
341 
343 {
344  float alpha, beta, gamma;
345  float pj[3], ni[3], di[3];
346  float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3];
347  int i, j, num_fni, k, fi;
348  int *fidn;
349 
350  for (i = 0; i < sys->total_verts; i++) {
351  copy_v3_v3(pi, sys->co[i]);
352  copy_v3_v3(ni, sys->no[i]);
353  k = sys->unit_verts[i];
354  copy_v3_v3(pj, sys->co[k]);
355  sub_v3_v3v3(uij, pj, pi);
356  mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
357  sub_v3_v3(uij, dun);
358  normalize_v3(uij);
359  cross_v3_v3v3(e2, ni, uij);
360  copy_v3_v3(di, sys->delta[i]);
361  alpha = dot_v3v3(ni, di);
362  beta = dot_v3v3(uij, di);
363  gamma = dot_v3v3(e2, di);
364 
365  pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i);
366  pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i);
367  pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i);
368  zero_v3(ni);
369  num_fni = sys->ringf_map[i].count;
370  for (fi = 0; fi < num_fni; fi++) {
371  const uint *vin;
372  fidn = sys->ringf_map[i].indices;
373  vin = sys->tris[fidn[fi]];
374  for (j = 0; j < 3; j++) {
375  vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]);
376  vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]);
377  vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]);
378  if (vin[j] == sys->unit_verts[i]) {
379  copy_v3_v3(pj, vn[j]);
380  }
381  }
382 
383  normal_tri_v3(fni, UNPACK3(vn));
384  add_v3_v3(ni, fni);
385  }
386 
387  normalize_v3(ni);
388  sub_v3_v3v3(uij, pj, pi);
389  mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
390  sub_v3_v3(uij, dun);
391  normalize_v3(uij);
392  cross_v3_v3v3(e2, ni, uij);
393  fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0];
394  fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1];
395  fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2];
396 
397  if (len_squared_v3(fni) > FLT_EPSILON) {
401  }
402  else {
403  EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
404  EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
405  EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
406  }
407  }
408 }
409 
410 static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
411 {
412  int vid, i, j, n, na;
413  n = sys->total_verts;
414  na = sys->total_anchors;
415 
416  if (!sys->is_matrix_computed) {
417  sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3);
418 
419  for (i = 0; i < n; i++) {
420  EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]);
421  EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]);
422  EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]);
423  }
424  for (i = 0; i < na; i++) {
425  vid = sys->index_anchors[i];
426  EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]);
427  EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]);
428  EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]);
429  }
430 
431  initLaplacianMatrix(sys);
433 
434  for (i = 0; i < n; i++) {
435  EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
436  EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
437  EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
438  }
439  for (i = 0; i < na; i++) {
440  vid = sys->index_anchors[i];
441  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
442  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
443  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
444  EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
445  }
446  if (EIG_linear_solver_solve(sys->context)) {
447  sys->has_solution = true;
448 
449  for (j = 1; j <= sys->repeat; j++) {
451 
452  for (i = 0; i < na; i++) {
453  vid = sys->index_anchors[i];
454  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
455  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
456  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
457  }
458 
459  if (!EIG_linear_solver_solve(sys->context)) {
460  sys->has_solution = false;
461  break;
462  }
463  }
464  if (sys->has_solution) {
465  for (vid = 0; vid < sys->total_verts; vid++) {
466  vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
467  vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
468  vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
469  }
470  }
471  else {
472  sys->has_solution = false;
473  }
474  }
475  else {
476  sys->has_solution = false;
477  }
478  sys->is_matrix_computed = true;
479  }
480  else if (sys->has_solution) {
481  for (i = 0; i < n; i++) {
482  EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
483  EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
484  EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
485  }
486  for (i = 0; i < na; i++) {
487  vid = sys->index_anchors[i];
488  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
489  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
490  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
491  EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
492  }
493 
494  if (EIG_linear_solver_solve(sys->context)) {
495  sys->has_solution = true;
496  for (j = 1; j <= sys->repeat; j++) {
498 
499  for (i = 0; i < na; i++) {
500  vid = sys->index_anchors[i];
501  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
502  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
503  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
504  }
505  if (!EIG_linear_solver_solve(sys->context)) {
506  sys->has_solution = false;
507  break;
508  }
509  }
510  if (sys->has_solution) {
511  for (vid = 0; vid < sys->total_verts; vid++) {
512  vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
513  vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
514  vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
515  }
516  }
517  else {
518  sys->has_solution = false;
519  }
520  }
521  else {
522  sys->has_solution = false;
523  }
524  }
525 }
526 
528 {
529  int defgrp_index;
530  MDeformVert *dvert = NULL;
531 
532  MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
533 
534  return (dvert != NULL);
535 }
536 
537 static void initSystem(
538  LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts)
539 {
540  int i;
541  int defgrp_index;
542  int total_anchors;
543  float wpaint;
544  MDeformVert *dvert = NULL;
545  MDeformVert *dv = NULL;
546  LaplacianSystem *sys;
547  const bool invert_vgroup = (lmd->flag & MOD_LAPLACIANDEFORM_INVERT_VGROUP) != 0;
548 
549  if (isValidVertexGroup(lmd, ob, mesh)) {
550  int *index_anchors = MEM_malloc_arrayN(numVerts, sizeof(int), __func__); /* over-alloc */
551  const MLoopTri *mlooptri;
552  const MLoop *mloop;
553 
554  STACK_DECLARE(index_anchors);
555 
556  STACK_INIT(index_anchors, numVerts);
557 
558  MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
559  BLI_assert(dvert != NULL);
560  dv = dvert;
561  for (i = 0; i < numVerts; i++) {
562  wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
563  BKE_defvert_find_weight(dv, defgrp_index);
564  dv++;
565  if (wpaint > 0.0f) {
566  STACK_PUSH(index_anchors, i);
567  }
568  }
569 
570  total_anchors = STACK_SIZE(index_anchors);
571  lmd->cache_system = initLaplacianSystem(numVerts,
572  mesh->totedge,
574  total_anchors,
575  lmd->anchor_grp_name,
576  lmd->repeat);
577  sys = (LaplacianSystem *)lmd->cache_system;
578  memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors);
579  memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts);
580  MEM_freeN(index_anchors);
581  lmd->vertexco = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "ModDeformCoordinates");
582  memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts);
583  lmd->total_verts = numVerts;
584 
588  mesh->mloop,
589  &sys->ringf_map,
590  &sys->ringf_indices);
593 
595  mloop = mesh->mloop;
596 
597  for (i = 0; i < sys->total_tris; i++) {
598  sys->tris[i][0] = mloop[mlooptri[i].tri[0]].v;
599  sys->tris[i][1] = mloop[mlooptri[i].tri[1]].v;
600  sys->tris[i][2] = mloop[mlooptri[i].tri[2]].v;
601  }
602  }
603 }
604 
606  Object *ob,
607  Mesh *mesh,
608  int numVerts)
609 {
610  int i;
611  int defgrp_index;
612  int total_anchors = 0;
613  float wpaint;
614  MDeformVert *dvert = NULL;
615  MDeformVert *dv = NULL;
617  const bool invert_vgroup = (lmd->flag & MOD_LAPLACIANDEFORM_INVERT_VGROUP) != 0;
618 
619  if (sys->total_verts != numVerts) {
621  }
622  if (sys->total_edges != mesh->totedge) {
624  }
625  if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) {
627  }
628  MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
629  if (!dvert) {
631  }
632  dv = dvert;
633  for (i = 0; i < numVerts; i++) {
634  wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
635  BKE_defvert_find_weight(dv, defgrp_index);
636  dv++;
637  if (wpaint > 0.0f) {
638  total_anchors++;
639  }
640  }
641  if (sys->total_anchors != total_anchors) {
643  }
644 
646 }
647 
649  LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int numVerts)
650 {
651  float(*filevertexCos)[3];
652  int sysdif;
653  LaplacianSystem *sys = NULL;
654  filevertexCos = NULL;
655  if (!(lmd->flag & MOD_LAPLACIANDEFORM_BIND)) {
656  if (lmd->cache_system) {
657  sys = lmd->cache_system;
659  lmd->cache_system = NULL;
660  }
661  lmd->total_verts = 0;
662  MEM_SAFE_FREE(lmd->vertexco);
663  return;
664  }
665  if (lmd->cache_system) {
666  sysdif = isSystemDifferent(lmd, ob, mesh, numVerts);
667  sys = lmd->cache_system;
668  if (sysdif) {
670  filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempModDeformCoordinates");
671  memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
672  MEM_SAFE_FREE(lmd->vertexco);
673  lmd->total_verts = 0;
675  lmd->cache_system = NULL;
676  initSystem(lmd, ob, mesh, filevertexCos, numVerts);
677  sys = lmd->cache_system; /* may have been reallocated */
678  MEM_SAFE_FREE(filevertexCos);
679  if (sys) {
680  laplacianDeformPreview(sys, vertexCos);
681  }
682  }
683  else {
684  if (sysdif == LAPDEFORM_SYSTEM_CHANGE_VERTEXES) {
686  ob, &lmd->modifier, "Vertices changed from %d to %d", lmd->total_verts, numVerts);
687  }
688  else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) {
690  ob, &lmd->modifier, "Edges changed from %d to %d", sys->total_edges, mesh->totedge);
691  }
692  else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) {
694  &lmd->modifier,
695  "Vertex group '%s' is not valid, or maybe empty",
696  sys->anchor_grp_name);
697  }
698  }
699  }
700  else {
701  sys->repeat = lmd->repeat;
702  laplacianDeformPreview(sys, vertexCos);
703  }
704  }
705  else {
706  if (!isValidVertexGroup(lmd, ob, mesh)) {
708  &lmd->modifier,
709  "Vertex group '%s' is not valid, or maybe empty",
710  lmd->anchor_grp_name);
712  }
713  else if (lmd->total_verts > 0 && lmd->total_verts == numVerts) {
714  filevertexCos = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "TempDeformCoordinates");
715  memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
716  MEM_SAFE_FREE(lmd->vertexco);
717  lmd->total_verts = 0;
718  initSystem(lmd, ob, mesh, filevertexCos, numVerts);
719  sys = lmd->cache_system;
720  MEM_SAFE_FREE(filevertexCos);
721  laplacianDeformPreview(sys, vertexCos);
722  }
723  else {
724  initSystem(lmd, ob, mesh, vertexCos, numVerts);
725  sys = lmd->cache_system;
726  laplacianDeformPreview(sys, vertexCos);
727  }
728  }
729  if (sys && sys->is_matrix_computed && !sys->has_solution) {
730  BKE_modifier_set_error(ob, &lmd->modifier, "The system did not find a solution");
731  }
732 }
733 
734 static void initData(ModifierData *md)
735 {
737 
738  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lmd, modifier));
739 
741 }
742 
743 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
744 {
747 
748  BKE_modifier_copydata_generic(md, target, flag);
749 
750  tlmd->vertexco = MEM_dupallocN(lmd->vertexco);
751  tlmd->cache_system = NULL;
752 }
753 
754 static bool isDisabled(const struct Scene *UNUSED(scene),
755  ModifierData *md,
756  bool UNUSED(useRenderParams))
757 {
759  if (lmd->anchor_grp_name[0]) {
760  return 0;
761  }
762  return 1;
763 }
764 
765 static void requiredDataMask(Object *UNUSED(ob),
766  ModifierData *md,
767  CustomData_MeshMasks *r_cddata_masks)
768 {
770 
771  if (lmd->anchor_grp_name[0] != '\0') {
772  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
773  }
774 }
775 
776 static void deformVerts(ModifierData *md,
777  const ModifierEvalContext *ctx,
778  Mesh *mesh,
779  float (*vertexCos)[3],
780  int numVerts)
781 {
782  Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
783 
785  (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);
786 
787  if (!ELEM(mesh_src, NULL, mesh)) {
788  BKE_id_free(NULL, mesh_src);
789  }
790 }
791 
792 static void deformVertsEM(ModifierData *md,
793  const ModifierEvalContext *ctx,
794  struct BMEditMesh *editData,
795  Mesh *mesh,
796  float (*vertexCos)[3],
797  int numVerts)
798 {
799  Mesh *mesh_src = MOD_deform_mesh_eval_get(
800  ctx->object, editData, mesh, NULL, numVerts, false, false);
801 
802  /* TODO(Campbell): use edit-mode data only (remove this line). */
803  if (mesh_src != NULL) {
805  }
806 
808  (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);
809 
810  if (!ELEM(mesh_src, NULL, mesh)) {
811  BKE_id_free(NULL, mesh_src);
812  }
813 }
814 
815 static void freeData(ModifierData *md)
816 {
819  if (sys) {
821  }
822  MEM_SAFE_FREE(lmd->vertexco);
823  lmd->total_verts = 0;
824 }
825 
826 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
827 {
828  uiLayout *row;
829  uiLayout *layout = panel->layout;
830 
831  PointerRNA ob_ptr;
833 
834  bool is_bind = RNA_boolean_get(ptr, "is_bind");
835  bool has_vertex_group = RNA_string_length(ptr, "vertex_group") != 0;
836 
837  uiLayoutSetPropSep(layout, true);
838 
839  uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
840 
841  modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
842 
843  uiItemS(layout);
844 
845  row = uiLayoutRow(layout, true);
846  uiLayoutSetEnabled(row, has_vertex_group);
847  uiItemO(row,
848  is_bind ? IFACE_("Unbind") : IFACE_("Bind"),
849  ICON_NONE,
850  "OBJECT_OT_laplaciandeform_bind");
851 
852  modifier_panel_end(layout, ptr);
853 }
854 
855 static void panelRegister(ARegionType *region_type)
856 {
858 }
859 
860 static void blendWrite(BlendWriter *writer, const ModifierData *md)
861 {
863 
864  BLO_write_float3_array(writer, lmd->total_verts, lmd->vertexco);
865 }
866 
867 static void blendRead(BlendDataReader *reader, ModifierData *md)
868 {
870 
871  BLO_read_float3_array(reader, lmd->total_verts, &lmd->vertexco);
872  lmd->cache_system = NULL;
873 }
874 
876  /* name */ "LaplacianDeform",
877  /* structName */ "LaplacianDeformModifierData",
878  /* structSize */ sizeof(LaplacianDeformModifierData),
879  /* srna */ &RNA_LaplacianDeformModifier,
880  /* type */ eModifierTypeType_OnlyDeform,
882  /* icon */ ICON_MOD_MESHDEFORM,
883  /* copyData */ copyData,
884 
885  /* deformVerts */ deformVerts,
886  /* deformMatrices */ NULL,
887  /* deformVertsEM */ deformVertsEM,
888  /* deformMatricesEM */ NULL,
889  /* modifyMesh */ NULL,
890  /* modifyHair */ NULL,
891  /* modifyGeometrySet */ NULL,
892  /* modifyVolume */ NULL,
893 
894  /* initData */ initData,
895  /* requiredDataMask */ requiredDataMask,
896  /* freeData */ freeData,
897  /* isDisabled */ isDisabled,
898  /* updateDepsgraph */ NULL,
899  /* dependsOnTime */ NULL,
900  /* dependsOnNormals */ NULL,
901  /* foreachIDLink */ NULL,
902  /* foreachTexLink */ NULL,
903  /* freeRuntimeData */ NULL,
904  /* panelRegister */ panelRegister,
905  /* blendWrite */ blendWrite,
906  /* blendRead */ blendRead,
907 };
typedef float(TangentPoint)[2]
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
void BKE_id_free(struct Main *bmain, void *idv)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh)
Definition: mesh_runtime.c:155
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.c:98
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:83
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:80
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, const int flag)
@ eModifierTypeType_OnlyDeform
Definition: BKE_modifier.h:58
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition: BLI_assert.h:58
float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:220
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:51
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define UNPACK3(a)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_INIT(stack, tot)
#define STACK_SIZE(stack)
void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition: readfile.c:5683
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr)
Definition: writefile.c:1393
#define IFACE_(msgid)
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
struct LaplacianDeformModifierData LaplacianDeformModifierData
@ MOD_LAPLACIANDEFORM_BIND
@ MOD_LAPLACIANDEFORM_INVERT_VGROUP
@ eModifierType_LaplacianDeform
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint vn
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, Mesh *mesh, float(*vertexCos)[3], int numVerts)
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
static void createVertRingMap(const int mvert_tot, const MEdge *medge, const int medge_tot, MeshElemMap **r_map, int **r_indices)
ModifierTypeInfo modifierType_LaplacianDeform
static void laplacianDeformPreview(LaplacianSystem *sys, float(*vertexCos)[3])
static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh)
static LaplacianSystem * newLaplacianSystem(void)
static void deleteLaplacianSystem(LaplacianSystem *sys)
static void initLaplacianMatrix(LaplacianSystem *sys)
static void createFaceRingMap(const int mvert_tot, const MLoopTri *mlooptri, const int mtri_tot, const MLoop *mloop, MeshElemMap **r_map, int **r_indices)
static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
@ LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP
@ LAPDEFORM_SYSTEM_IS_DIFFERENT
@ LAPDEFORM_SYSTEM_ONLY_CHANGE_MESH
@ LAPDEFORM_SYSTEM_CHANGE_EDGES
@ LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP
@ LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS
@ LAPDEFORM_SYSTEM_CHANGE_VERTEXES
@ LAPDEFORM_SYSTEM_NOT_CHANGE
static void blendWrite(BlendWriter *writer, const ModifierData *md)
static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, float(*vertexCos)[3], int numVerts)
static void blendRead(BlendDataReader *reader, ModifierData *md)
static LaplacianSystem * initLaplacianSystem(int totalVerts, int totalEdges, int totalTris, int totalAnchors, const char defgrpName[64], int iterations)
static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, int numVerts)
static void computeImplictRotations(LaplacianSystem *sys)
static void LaplacianDeformModifier_do(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float(*vertexCos)[3], int numVerts)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void initData(ModifierData *md)
static void panelRegister(ARegionType *region_type)
static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float(*vertexCos)[3], int numVerts)
static void rotateDifferentialCoordinates(LaplacianSystem *sys)
struct LaplacianSystem LaplacianSystem
static void freeData(ModifierData *md)
static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
Mesh * MOD_deform_mesh_eval_get(Object *ob, struct BMEditMesh *em, Mesh *mesh, const float(*vertexCos)[3], const int num_verts, const bool use_normals, const bool use_orco)
Definition: MOD_util.c:186
void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
Definition: MOD_util.c:254
StructRNA RNA_LaplacianDeformModifier
#define C
Definition: RandGen.cpp:39
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
Scene scene
static CCL_NAMESPACE_BEGIN const double alpha
static ushort indices[]
#define fabsf(x)
void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value)
void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value)
LinearSolver * EIG_linear_least_squares_solver_new(int num_rows, int num_columns, int num_rhs)
void EIG_linear_solver_delete(LinearSolver *solver)
double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index)
void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value)
bool EIG_linear_solver_solve(LinearSolver *solver)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
int RNA_string_length(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6539
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
MeshElemMap * ringv_map
MeshElemMap * ringf_map
LinearSolver * context
Definition: meshlaplacian.c:74
unsigned int v1
unsigned int v2
unsigned int tri[3]
unsigned int v
struct MEdge * medge
int totedge
int totvert
struct MLoop * mloop
struct Object * object
Definition: BKE_modifier.h:154
struct uiLayout * layout
ccl_device_inline float beta(float x, float y)
Definition: util_math.h:666
PointerRNA * ptr
Definition: wm_files.c:3157