Blender  V3.3
MOD_laplaciandeform.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2013 Blender Foundation. All rights reserved. */
3 
8 #include "BLI_utildefines.h"
9 
10 #include "BLI_math.h"
11 #include "BLI_string.h"
12 #include "BLI_utildefines_stack.h"
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "BLT_translation.h"
17 
18 #include "DNA_defaults.h"
19 #include "DNA_mesh_types.h"
20 #include "DNA_meshdata_types.h"
21 #include "DNA_screen_types.h"
22 
23 #include "BKE_context.h"
24 #include "BKE_deform.h"
25 #include "BKE_editmesh.h"
26 #include "BKE_lib_id.h"
27 #include "BKE_mesh.h"
28 #include "BKE_mesh_mapping.h"
29 #include "BKE_mesh_runtime.h"
30 #include "BKE_mesh_wrapper.h"
31 #include "BKE_particle.h"
32 #include "BKE_screen.h"
33 
34 #include "UI_interface.h"
35 #include "UI_resources.h"
36 
37 #include "BLO_read_write.h"
38 
39 #include "RNA_access.h"
40 #include "RNA_prototypes.h"
41 
42 #include "MOD_ui_common.h"
43 #include "MOD_util.h"
44 
45 #include "eigen_capi.h"
46 
47 enum {
56 };
57 
58 typedef struct LaplacianSystem {
61  int verts_num;
62  int edges_num;
63  int tris_num;
65  int repeat;
66  char anchor_grp_name[64]; /* Vertex Group name */
67  float (*co)[3]; /* Original vertex coordinates */
68  float (*no)[3]; /* Original vertex normal */
69  float (*delta)[3]; /* Differential Coordinates */
70  uint (*tris)[3]; /* Copy of MLoopTri (tessellation triangle) v1-v3 */
71  int *index_anchors; /* Static vertex index list */
72  int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */
73  int *ringf_indices; /* Indices of faces per vertex */
74  int *ringv_indices; /* Indices of neighbors(vertex) per vertex */
75  LinearSolver *context; /* System for solve general implicit rotations */
76  MeshElemMap *ringf_map; /* Map of faces per vertex */
77  MeshElemMap *ringv_map; /* Map of vertex per vertex */
79 
81 {
82  LaplacianSystem *sys;
83  sys = MEM_callocN(sizeof(LaplacianSystem), "DeformCache");
84 
85  sys->is_matrix_computed = false;
86  sys->has_solution = false;
87  sys->verts_num = 0;
88  sys->edges_num = 0;
89  sys->anchors_num = 0;
90  sys->tris_num = 0;
91  sys->repeat = 1;
92  sys->anchor_grp_name[0] = '\0';
93 
94  return sys;
95 }
96 
97 static LaplacianSystem *initLaplacianSystem(int verts_num,
98  int edges_num,
99  int tris_num,
100  int anchors_num,
101  const char defgrpName[64],
102  int iterations)
103 {
105 
106  sys->is_matrix_computed = false;
107  sys->has_solution = false;
108  sys->verts_num = verts_num;
109  sys->edges_num = edges_num;
110  sys->tris_num = tris_num;
111  sys->anchors_num = anchors_num;
112  sys->repeat = iterations;
113  BLI_strncpy(sys->anchor_grp_name, defgrpName, sizeof(sys->anchor_grp_name));
114  sys->co = MEM_malloc_arrayN(verts_num, sizeof(float[3]), "DeformCoordinates");
115  sys->no = MEM_calloc_arrayN(verts_num, sizeof(float[3]), "DeformNormals");
116  sys->delta = MEM_calloc_arrayN(verts_num, sizeof(float[3]), "DeformDeltas");
117  sys->tris = MEM_malloc_arrayN(tris_num, sizeof(int[3]), "DeformFaces");
118  sys->index_anchors = MEM_malloc_arrayN((anchors_num), sizeof(int), "DeformAnchors");
119  sys->unit_verts = MEM_calloc_arrayN(verts_num, sizeof(int), "DeformUnitVerts");
120  return sys;
121 }
122 
124 {
125  MEM_SAFE_FREE(sys->co);
126  MEM_SAFE_FREE(sys->no);
127  MEM_SAFE_FREE(sys->delta);
128  MEM_SAFE_FREE(sys->tris);
133  MEM_SAFE_FREE(sys->ringf_map);
134  MEM_SAFE_FREE(sys->ringv_map);
135 
136  if (sys->context) {
138  }
139  MEM_SAFE_FREE(sys);
140 }
141 
142 static void createFaceRingMap(const int mvert_tot,
143  const MLoopTri *mlooptri,
144  const int mtri_tot,
145  const MLoop *mloop,
146  MeshElemMap **r_map,
147  int **r_indices)
148 {
149  int i, j, indices_num = 0;
150  int *indices, *index_iter;
151  MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformRingMap");
152  const MLoopTri *mlt;
153 
154  for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
155 
156  for (j = 0; j < 3; j++) {
157  const uint v_index = mloop[mlt->tri[j]].v;
158  map[v_index].count++;
159  indices_num++;
160  }
161  }
162  indices = MEM_calloc_arrayN(indices_num, sizeof(int), "DeformRingIndex");
163  index_iter = indices;
164  for (i = 0; i < mvert_tot; i++) {
165  map[i].indices = index_iter;
166  index_iter += map[i].count;
167  map[i].count = 0;
168  }
169  for (i = 0, mlt = mlooptri; i < mtri_tot; i++, mlt++) {
170  for (j = 0; j < 3; j++) {
171  const uint v_index = mloop[mlt->tri[j]].v;
172  map[v_index].indices[map[v_index].count] = i;
173  map[v_index].count++;
174  }
175  }
176  *r_map = map;
177  *r_indices = indices;
178 }
179 
180 static void createVertRingMap(const int mvert_tot,
181  const MEdge *medge,
182  const int medge_tot,
183  MeshElemMap **r_map,
184  int **r_indices)
185 {
186  MeshElemMap *map = MEM_calloc_arrayN(mvert_tot, sizeof(MeshElemMap), "DeformNeighborsMap");
187  int i, vid[2], indices_num = 0;
188  int *indices, *index_iter;
189  const MEdge *me;
190 
191  for (i = 0, me = medge; i < medge_tot; i++, me++) {
192  vid[0] = me->v1;
193  vid[1] = me->v2;
194  map[vid[0]].count++;
195  map[vid[1]].count++;
196  indices_num += 2;
197  }
198  indices = MEM_calloc_arrayN(indices_num, sizeof(int), "DeformNeighborsIndex");
199  index_iter = indices;
200  for (i = 0; i < mvert_tot; i++) {
201  map[i].indices = index_iter;
202  index_iter += map[i].count;
203  map[i].count = 0;
204  }
205  for (i = 0, me = medge; i < medge_tot; i++, me++) {
206  vid[0] = me->v1;
207  vid[1] = me->v2;
208  map[vid[0]].indices[map[vid[0]].count] = vid[1];
209  map[vid[0]].count++;
210  map[vid[1]].indices[map[vid[1]].count] = vid[0];
211  map[vid[1]].count++;
212  }
213  *r_map = map;
214  *r_indices = indices;
215 }
216 
250 {
251  float no[3];
252  float w2, w3;
253  int i = 3, j, ti;
254  int idv[3];
255 
256  for (ti = 0; ti < sys->tris_num; ti++) {
257  const uint *vidt = sys->tris[ti];
258  const float *co[3];
259 
260  co[0] = sys->co[vidt[0]];
261  co[1] = sys->co[vidt[1]];
262  co[2] = sys->co[vidt[2]];
263 
264  normal_tri_v3(no, UNPACK3(co));
265  add_v3_v3(sys->no[vidt[0]], no);
266  add_v3_v3(sys->no[vidt[1]], no);
267  add_v3_v3(sys->no[vidt[2]], no);
268 
269  for (j = 0; j < 3; j++) {
270  const float *v1, *v2, *v3;
271 
272  idv[0] = vidt[j];
273  idv[1] = vidt[(j + 1) % i];
274  idv[2] = vidt[(j + 2) % i];
275 
276  v1 = sys->co[idv[0]];
277  v2 = sys->co[idv[1]];
278  v3 = sys->co[idv[2]];
279 
280  w2 = cotangent_tri_weight_v3(v3, v1, v2);
281  w3 = cotangent_tri_weight_v3(v2, v3, v1);
282 
283  sys->delta[idv[0]][0] += v1[0] * (w2 + w3);
284  sys->delta[idv[0]][1] += v1[1] * (w2 + w3);
285  sys->delta[idv[0]][2] += v1[2] * (w2 + w3);
286 
287  sys->delta[idv[0]][0] -= v2[0] * w2;
288  sys->delta[idv[0]][1] -= v2[1] * w2;
289  sys->delta[idv[0]][2] -= v2[2] * w2;
290 
291  sys->delta[idv[0]][0] -= v3[0] * w3;
292  sys->delta[idv[0]][1] -= v3[1] * w3;
293  sys->delta[idv[0]][2] -= v3[2] * w3;
294 
295  EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2);
296  EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3);
297  EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3);
298  }
299  }
300 }
301 
303 {
304  int vid, *vidn = NULL;
305  float minj, mjt, qj[3], vj[3];
306  int i, j, ln;
307 
308  for (i = 0; i < sys->verts_num; i++) {
309  normalize_v3(sys->no[i]);
310  vidn = sys->ringv_map[i].indices;
311  ln = sys->ringv_map[i].count;
312  minj = 1000000.0f;
313  for (j = 0; j < ln; j++) {
314  vid = vidn[j];
315  copy_v3_v3(qj, sys->co[vid]);
316  sub_v3_v3v3(vj, qj, sys->co[i]);
317  normalize_v3(vj);
318  mjt = fabsf(dot_v3v3(vj, sys->no[i]));
319  if (mjt < minj) {
320  minj = mjt;
321  sys->unit_verts[i] = vidn[j];
322  }
323  }
324  }
325 }
326 
328 {
329  float alpha, beta, gamma;
330  float pj[3], ni[3], di[3];
331  float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3];
332  int i, j, fidn_num, k, fi;
333  int *fidn;
334 
335  for (i = 0; i < sys->verts_num; i++) {
336  copy_v3_v3(pi, sys->co[i]);
337  copy_v3_v3(ni, sys->no[i]);
338  k = sys->unit_verts[i];
339  copy_v3_v3(pj, sys->co[k]);
340  sub_v3_v3v3(uij, pj, pi);
341  mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
342  sub_v3_v3(uij, dun);
343  normalize_v3(uij);
344  cross_v3_v3v3(e2, ni, uij);
345  copy_v3_v3(di, sys->delta[i]);
346  alpha = dot_v3v3(ni, di);
347  beta = dot_v3v3(uij, di);
348  gamma = dot_v3v3(e2, di);
349 
350  pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i);
351  pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i);
352  pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i);
353  zero_v3(ni);
354  fidn_num = sys->ringf_map[i].count;
355  for (fi = 0; fi < fidn_num; fi++) {
356  const uint *vin;
357  fidn = sys->ringf_map[i].indices;
358  vin = sys->tris[fidn[fi]];
359  for (j = 0; j < 3; j++) {
360  vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]);
361  vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]);
362  vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]);
363  if (vin[j] == sys->unit_verts[i]) {
364  copy_v3_v3(pj, vn[j]);
365  }
366  }
367 
368  normal_tri_v3(fni, UNPACK3(vn));
369  add_v3_v3(ni, fni);
370  }
371 
372  normalize_v3(ni);
373  sub_v3_v3v3(uij, pj, pi);
374  mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
375  sub_v3_v3(uij, dun);
376  normalize_v3(uij);
377  cross_v3_v3v3(e2, ni, uij);
378  fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0];
379  fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1];
380  fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2];
381 
382  if (len_squared_v3(fni) > FLT_EPSILON) {
386  }
387  else {
388  EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
389  EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
390  EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
391  }
392  }
393 }
394 
395 static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
396 {
397  int vid, i, j, n, na;
398  n = sys->verts_num;
399  na = sys->anchors_num;
400 
401  if (!sys->is_matrix_computed) {
402  sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3);
403 
404  for (i = 0; i < n; i++) {
405  EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]);
406  EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]);
407  EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]);
408  }
409  for (i = 0; i < na; i++) {
410  vid = sys->index_anchors[i];
411  EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]);
412  EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]);
413  EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]);
414  }
415 
416  initLaplacianMatrix(sys);
418 
419  for (i = 0; i < n; i++) {
420  EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
421  EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
422  EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
423  }
424  for (i = 0; i < na; i++) {
425  vid = sys->index_anchors[i];
426  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
427  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
428  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
429  EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
430  }
431  if (EIG_linear_solver_solve(sys->context)) {
432  sys->has_solution = true;
433 
434  for (j = 1; j <= sys->repeat; j++) {
436 
437  for (i = 0; i < na; i++) {
438  vid = sys->index_anchors[i];
439  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
440  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
441  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
442  }
443 
444  if (!EIG_linear_solver_solve(sys->context)) {
445  sys->has_solution = false;
446  break;
447  }
448  }
449  if (sys->has_solution) {
450  for (vid = 0; vid < sys->verts_num; vid++) {
451  vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
452  vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
453  vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
454  }
455  }
456  else {
457  sys->has_solution = false;
458  }
459  }
460  else {
461  sys->has_solution = false;
462  }
463  sys->is_matrix_computed = true;
464  }
465  else if (sys->has_solution) {
466  for (i = 0; i < n; i++) {
467  EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
468  EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
469  EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
470  }
471  for (i = 0; i < na; i++) {
472  vid = sys->index_anchors[i];
473  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
474  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
475  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
476  EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
477  }
478 
479  if (EIG_linear_solver_solve(sys->context)) {
480  sys->has_solution = true;
481  for (j = 1; j <= sys->repeat; j++) {
483 
484  for (i = 0; i < na; i++) {
485  vid = sys->index_anchors[i];
486  EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
487  EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
488  EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
489  }
490  if (!EIG_linear_solver_solve(sys->context)) {
491  sys->has_solution = false;
492  break;
493  }
494  }
495  if (sys->has_solution) {
496  for (vid = 0; vid < sys->verts_num; vid++) {
497  vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
498  vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
499  vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
500  }
501  }
502  else {
503  sys->has_solution = false;
504  }
505  }
506  else {
507  sys->has_solution = false;
508  }
509  }
510 }
511 
513 {
514  int defgrp_index;
515  MDeformVert *dvert = NULL;
516 
517  MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
518 
519  return (dvert != NULL);
520 }
521 
522 static void initSystem(
523  LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int verts_num)
524 {
525  int i;
526  int defgrp_index;
527  int anchors_num;
528  float wpaint;
529  MDeformVert *dvert = NULL;
530  MDeformVert *dv = NULL;
531  LaplacianSystem *sys;
532  const bool invert_vgroup = (lmd->flag & MOD_LAPLACIANDEFORM_INVERT_VGROUP) != 0;
533 
534  if (isValidVertexGroup(lmd, ob, mesh)) {
535  int *index_anchors = MEM_malloc_arrayN(verts_num, sizeof(int), __func__); /* over-alloc */
536  const MLoopTri *mlooptri;
537  const MLoop *mloop;
538 
539  STACK_DECLARE(index_anchors);
540 
541  STACK_INIT(index_anchors, verts_num);
542 
543  MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
544  BLI_assert(dvert != NULL);
545  dv = dvert;
546  for (i = 0; i < verts_num; i++) {
547  wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
548  BKE_defvert_find_weight(dv, defgrp_index);
549  dv++;
550  if (wpaint > 0.0f) {
551  STACK_PUSH(index_anchors, i);
552  }
553  }
554 
555  anchors_num = STACK_SIZE(index_anchors);
556  lmd->cache_system = initLaplacianSystem(verts_num,
557  mesh->totedge,
559  anchors_num,
560  lmd->anchor_grp_name,
561  lmd->repeat);
562  sys = (LaplacianSystem *)lmd->cache_system;
563  memcpy(sys->index_anchors, index_anchors, sizeof(int) * anchors_num);
564  memcpy(sys->co, vertexCos, sizeof(float[3]) * verts_num);
565  MEM_freeN(index_anchors);
566  lmd->vertexco = MEM_malloc_arrayN(verts_num, sizeof(float[3]), "ModDeformCoordinates");
567  memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * verts_num);
568  lmd->verts_num = verts_num;
569 
573  mesh->mloop,
574  &sys->ringf_map,
575  &sys->ringf_indices);
578 
580  mloop = mesh->mloop;
581 
582  for (i = 0; i < sys->tris_num; i++) {
583  sys->tris[i][0] = mloop[mlooptri[i].tri[0]].v;
584  sys->tris[i][1] = mloop[mlooptri[i].tri[1]].v;
585  sys->tris[i][2] = mloop[mlooptri[i].tri[2]].v;
586  }
587  }
588 }
589 
591  Object *ob,
592  Mesh *mesh,
593  int verts_num)
594 {
595  int i;
596  int defgrp_index;
597  int anchors_num = 0;
598  float wpaint;
599  MDeformVert *dvert = NULL;
600  MDeformVert *dv = NULL;
602  const bool invert_vgroup = (lmd->flag & MOD_LAPLACIANDEFORM_INVERT_VGROUP) != 0;
603 
604  if (sys->verts_num != verts_num) {
606  }
607  if (sys->edges_num != mesh->totedge) {
609  }
610  if (!STREQ(lmd->anchor_grp_name, sys->anchor_grp_name)) {
612  }
613  MOD_get_vgroup(ob, mesh, lmd->anchor_grp_name, &dvert, &defgrp_index);
614  if (!dvert) {
616  }
617  dv = dvert;
618  for (i = 0; i < verts_num; i++) {
619  wpaint = invert_vgroup ? 1.0f - BKE_defvert_find_weight(dv, defgrp_index) :
620  BKE_defvert_find_weight(dv, defgrp_index);
621  dv++;
622  if (wpaint > 0.0f) {
623  anchors_num++;
624  }
625  }
626  if (sys->anchors_num != anchors_num) {
628  }
629 
631 }
632 
634  LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float (*vertexCos)[3], int verts_num)
635 {
636  float(*filevertexCos)[3];
637  int sysdif;
638  LaplacianSystem *sys = NULL;
639  filevertexCos = NULL;
640  if (!(lmd->flag & MOD_LAPLACIANDEFORM_BIND)) {
641  if (lmd->cache_system) {
642  sys = lmd->cache_system;
644  lmd->cache_system = NULL;
645  }
646  lmd->verts_num = 0;
647  MEM_SAFE_FREE(lmd->vertexco);
648  return;
649  }
650  if (lmd->cache_system) {
651  sysdif = isSystemDifferent(lmd, ob, mesh, verts_num);
652  sys = lmd->cache_system;
653  if (sysdif) {
655  filevertexCos = MEM_malloc_arrayN(verts_num, sizeof(float[3]), "TempModDeformCoordinates");
656  memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * verts_num);
657  MEM_SAFE_FREE(lmd->vertexco);
658  lmd->verts_num = 0;
660  lmd->cache_system = NULL;
661  initSystem(lmd, ob, mesh, filevertexCos, verts_num);
662  sys = lmd->cache_system; /* may have been reallocated */
663  MEM_SAFE_FREE(filevertexCos);
664  if (sys) {
665  laplacianDeformPreview(sys, vertexCos);
666  }
667  }
668  else {
669  if (sysdif == LAPDEFORM_SYSTEM_CHANGE_VERTEXES) {
671  ob, &lmd->modifier, "Vertices changed from %d to %d", lmd->verts_num, verts_num);
672  }
673  else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) {
675  ob, &lmd->modifier, "Edges changed from %d to %d", sys->edges_num, mesh->totedge);
676  }
677  else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) {
679  &lmd->modifier,
680  "Vertex group '%s' is not valid, or maybe empty",
681  sys->anchor_grp_name);
682  }
683  }
684  }
685  else {
686  sys->repeat = lmd->repeat;
687  laplacianDeformPreview(sys, vertexCos);
688  }
689  }
690  else {
691  if (!isValidVertexGroup(lmd, ob, mesh)) {
693  &lmd->modifier,
694  "Vertex group '%s' is not valid, or maybe empty",
695  lmd->anchor_grp_name);
697  }
698  else if (lmd->verts_num > 0 && lmd->verts_num == verts_num) {
699  filevertexCos = MEM_malloc_arrayN(verts_num, sizeof(float[3]), "TempDeformCoordinates");
700  memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * verts_num);
701  MEM_SAFE_FREE(lmd->vertexco);
702  lmd->verts_num = 0;
703  initSystem(lmd, ob, mesh, filevertexCos, verts_num);
704  sys = lmd->cache_system;
705  MEM_SAFE_FREE(filevertexCos);
706  laplacianDeformPreview(sys, vertexCos);
707  }
708  else {
709  initSystem(lmd, ob, mesh, vertexCos, verts_num);
710  sys = lmd->cache_system;
711  laplacianDeformPreview(sys, vertexCos);
712  }
713  }
714  if (sys && sys->is_matrix_computed && !sys->has_solution) {
715  BKE_modifier_set_error(ob, &lmd->modifier, "The system did not find a solution");
716  }
717 }
718 
719 static void initData(ModifierData *md)
720 {
722 
723  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lmd, modifier));
724 
726 }
727 
728 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
729 {
732 
733  BKE_modifier_copydata_generic(md, target, flag);
734 
735  tlmd->vertexco = MEM_dupallocN(lmd->vertexco);
736  tlmd->cache_system = NULL;
737 }
738 
739 static bool isDisabled(const struct Scene *UNUSED(scene),
740  ModifierData *md,
741  bool UNUSED(useRenderParams))
742 {
744  if (lmd->anchor_grp_name[0]) {
745  return 0;
746  }
747  return 1;
748 }
749 
750 static void requiredDataMask(Object *UNUSED(ob),
751  ModifierData *md,
752  CustomData_MeshMasks *r_cddata_masks)
753 {
755 
756  if (lmd->anchor_grp_name[0] != '\0') {
757  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
758  }
759 }
760 
761 static void deformVerts(ModifierData *md,
762  const ModifierEvalContext *ctx,
763  Mesh *mesh,
764  float (*vertexCos)[3],
765  int verts_num)
766 {
767  Mesh *mesh_src = MOD_deform_mesh_eval_get(
768  ctx->object, NULL, mesh, NULL, verts_num, false, false);
769 
771  (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, verts_num);
772 
773  if (!ELEM(mesh_src, NULL, mesh)) {
774  BKE_id_free(NULL, mesh_src);
775  }
776 }
777 
778 static void deformVertsEM(ModifierData *md,
779  const ModifierEvalContext *ctx,
780  struct BMEditMesh *editData,
781  Mesh *mesh,
782  float (*vertexCos)[3],
783  int verts_num)
784 {
785  Mesh *mesh_src = MOD_deform_mesh_eval_get(
786  ctx->object, editData, mesh, NULL, verts_num, false, false);
787 
788  /* TODO(Campbell): use edit-mode data only (remove this line). */
789  if (mesh_src != NULL) {
791  }
792 
794  (LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, verts_num);
795 
796  if (!ELEM(mesh_src, NULL, mesh)) {
797  BKE_id_free(NULL, mesh_src);
798  }
799 }
800 
801 static void freeData(ModifierData *md)
802 {
805  if (sys) {
807  }
808  MEM_SAFE_FREE(lmd->vertexco);
809  lmd->verts_num = 0;
810 }
811 
812 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
813 {
814  uiLayout *row;
815  uiLayout *layout = panel->layout;
816 
817  PointerRNA ob_ptr;
819 
820  bool is_bind = RNA_boolean_get(ptr, "is_bind");
821  bool has_vertex_group = RNA_string_length(ptr, "vertex_group") != 0;
822 
823  uiLayoutSetPropSep(layout, true);
824 
825  uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
826 
827  modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
828 
829  uiItemS(layout);
830 
831  row = uiLayoutRow(layout, true);
832  uiLayoutSetEnabled(row, has_vertex_group);
833  uiItemO(row,
834  is_bind ? IFACE_("Unbind") : IFACE_("Bind"),
835  ICON_NONE,
836  "OBJECT_OT_laplaciandeform_bind");
837 
838  modifier_panel_end(layout, ptr);
839 }
840 
841 static void panelRegister(ARegionType *region_type)
842 {
844 }
845 
846 static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
847 {
849  const bool is_undo = BLO_write_is_undo(writer);
850 
851  if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
852  BLI_assert(!ID_IS_LINKED(id_owner));
853  const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
854  if (!is_local) {
855  /* Modifier coming from linked data cannot be bound from an override, so we can remove all
856  * binding data, can save a significant amount of memory. */
857  lmd.verts_num = 0;
858  lmd.vertexco = NULL;
859  }
860  }
861 
863 
864  if (lmd.vertexco != NULL) {
865  BLO_write_float3_array(writer, lmd.verts_num, lmd.vertexco);
866  }
867 }
868 
869 static void blendRead(BlendDataReader *reader, ModifierData *md)
870 {
872 
873  BLO_read_float3_array(reader, lmd->verts_num, &lmd->vertexco);
874  lmd->cache_system = NULL;
875 }
876 
878  /* name */ N_("LaplacianDeform"),
879  /* structName */ "LaplacianDeformModifierData",
880  /* structSize */ sizeof(LaplacianDeformModifierData),
881  /* srna */ &RNA_LaplacianDeformModifier,
882  /* type */ eModifierTypeType_OnlyDeform,
884  /* icon */ ICON_MOD_MESHDEFORM,
885  /* copyData */ copyData,
886 
887  /* deformVerts */ deformVerts,
888  /* deformMatrices */ NULL,
889  /* deformVertsEM */ deformVertsEM,
890  /* deformMatricesEM */ NULL,
891  /* modifyMesh */ NULL,
892  /* modifyGeometrySet */ 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, int defgroup)
Definition: deform.c:704
void BKE_id_free(struct Main *bmain, void *idv)
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.cc:94
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:69
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_OnlyDeform
Definition: BKE_modifier.h:44
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:46
float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:190
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:33
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, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned int uint
Definition: BLI_sys_types.h:67
#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_SIZE(stack)
#define STACK_INIT(stack, stack_num)
void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition: readfile.c:5201
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr)
Definition: writefile.c:1596
bool BLO_write_is_undo(BlendWriter *writer)
Definition: writefile.c:1608
#define BLO_write_struct_at_address(writer, struct_name, address, data_ptr)
#define IFACE_(msgid)
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ eModifierFlag_OverrideLibrary_Local
@ MOD_LAPLACIANDEFORM_BIND
@ MOD_LAPLACIANDEFORM_INVERT_VGROUP
struct LaplacianDeformModifierData LaplacianDeformModifierData
@ 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 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)
static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, float(*vertexCos)[3], int verts_num)
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 LaplacianSystem * initLaplacianSystem(int verts_num, int edges_num, int tris_num, int anchors_num, const char defgrpName[64], int iterations)
static int isSystemDifferent(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, int verts_num)
static void deleteLaplacianSystem(LaplacianSystem *sys)
static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, Mesh *mesh, float(*vertexCos)[3], int verts_num)
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))
static void blendRead(BlendDataReader *reader, ModifierData *md)
@ 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 computeImplictRotations(LaplacianSystem *sys)
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 verts_num)
static void rotateDifferentialCoordinates(LaplacianSystem *sys)
struct LaplacianSystem LaplacianSystem
static void LaplacianDeformModifier_do(LaplacianDeformModifierData *lmd, Object *ob, Mesh *mesh, float(*vertexCos)[3], int verts_num)
static void freeData(ModifierData *md)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const 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)
Definition: MOD_ui_common.c:91
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 verts_num, const bool use_normals, const bool use_orco)
Definition: MOD_util.c:167
void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
Definition: MOD_util.c:235
#define C
Definition: RandGen.cpp:25
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
ccl_gpu_kernel_postfix int ccl_global int * indices
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:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define fabsf(x)
Definition: metal/compat.h:219
SocketIndexByIdentifierMap * map
int RNA_string_length(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5144
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
Definition: DNA_ID.h:368
MeshElemMap * ringv_map
MeshElemMap * ringf_map
LinearSolver * context
Definition: meshlaplacian.c:60
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:141
struct uiLayout * layout
ccl_device_inline float beta(float x, float y)
Definition: util/math.h:775
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480