Blender V5.0
ed_transverts.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "DNA_mesh_types.h"
10#include "MEM_guardedalloc.h"
11
12#include "DNA_armature_types.h"
13#include "DNA_curve_types.h"
14#include "DNA_curves_types.h"
15#include "DNA_lattice_types.h"
16#include "DNA_meta_types.h"
17#include "DNA_object_types.h"
19#include "DNA_scene_types.h"
20
21#include "BLI_listbase.h"
22#include "BLI_utildefines.h"
23
24#include "BKE_armature.hh"
25#include "BKE_context.hh"
26#include "BKE_curve.hh"
27#include "BKE_editmesh.hh"
28#include "BKE_lattice.hh"
29#include "BKE_mesh_iterators.hh"
30#include "BKE_mesh_types.hh"
31#include "BKE_object.hh"
32
33#include "DEG_depsgraph.hh"
35
36#include "ED_armature.hh"
37#include "ED_curves.hh"
38#include "ED_pointcloud.hh"
39
40#include "ANIM_armature.hh"
41
42#include "ED_transverts.hh" /* own include */
43
45{
46 /* NOTE: copied from `editobject.c`, now uses (almost) proper depsgraph. */
47
48 const int mode = tvs->mode;
50
51 DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_GEOMETRY);
52
53 if (obedit->type == OB_MESH) {
56 }
57 else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
58 Curve *cu = static_cast<Curve *>(obedit->data);
60 Nurb *nu = static_cast<Nurb *>(nurbs->first);
61
62 while (nu) {
63 /* keep handles' vectors unchanged */
64 if (nu->bezt && (mode & TM_SKIP_HANDLES)) {
65 int a = nu->pntsu;
66 TransVert *tv = tvs->transverts;
67 BezTriple *bezt = nu->bezt;
68
69 while (a--) {
70 if (bezt->hide == 0) {
71 bool skip_handle = false;
72 if (bezt->f2 & SELECT) {
73 skip_handle = (mode & TM_SKIP_HANDLES) != 0;
74 }
75
76 if ((bezt->f1 & SELECT) && !skip_handle) {
77 BLI_assert(tv->loc == bezt->vec[0]);
78 tv++;
79 }
80
81 if (bezt->f2 & SELECT) {
82 float v[3];
83
84 if (((bezt->f1 & SELECT) && !skip_handle) == 0) {
85 sub_v3_v3v3(v, tv->loc, tv->oldloc);
86 add_v3_v3(bezt->vec[0], v);
87 }
88
89 if (((bezt->f3 & SELECT) && !skip_handle) == 0) {
90 sub_v3_v3v3(v, tv->loc, tv->oldloc);
91 add_v3_v3(bezt->vec[2], v);
92 }
93
94 BLI_assert(tv->loc == bezt->vec[1]);
95 tv++;
96 }
97
98 if ((bezt->f3 & SELECT) && !skip_handle) {
99 BLI_assert(tv->loc == bezt->vec[2]);
100 tv++;
101 }
102 }
103
104 bezt++;
105 }
106 }
107
108 if (CU_IS_2D(cu)) {
110 }
111 BKE_nurb_handles_test(nu, NURB_HANDLE_TEST_EACH, false); /* test for bezier too */
112 nu = nu->next;
113 }
114 }
115 else if (obedit->type == OB_ARMATURE) {
116 bArmature *arm = static_cast<bArmature *>(obedit->data);
117 TransVert *tv = tvs->transverts;
118 int a = 0;
119
120 /* Ensure all bone tails are correctly adjusted */
121 LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
122 if (!blender::animrig::bone_is_visible(arm, ebo)) {
123 continue;
124 }
125 /* adjust tip if both ends selected */
126 if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
127 if (tv) {
128 float diffvec[3];
129
130 sub_v3_v3v3(diffvec, tv->loc, tv->oldloc);
131 add_v3_v3(ebo->tail, diffvec);
132
133 a++;
134 if (a < tvs->transverts_tot) {
135 tv++;
136 }
137 }
138 }
139 }
140
141 /* Ensure all bones are correctly adjusted */
142 LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
143 if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
144 /* If this bone has a parent tip that has been moved */
145 if (blender::animrig::bone_is_visible(arm, ebo->parent) &&
146 (ebo->parent->flag & BONE_TIPSEL))
147 {
148 copy_v3_v3(ebo->head, ebo->parent->tail);
149 }
150 /* If this bone has a parent tip that has NOT been moved */
151 else {
152 copy_v3_v3(ebo->parent->tail, ebo->head);
153 }
154 }
155 }
156 if (arm->flag & ARM_MIRROR_EDIT) {
158 }
159 }
160 else if (obedit->type == OB_LATTICE) {
161 Lattice *lt = static_cast<Lattice *>(obedit->data);
162
163 if (lt->editlatt->latt->flag & LT_OUTSIDE) {
165 }
166 }
167 else if (obedit->type == OB_CURVES) {
168 Curves *curves_id = static_cast<Curves *>(obedit->data);
169 blender::bke::CurvesGeometry &curves = curves_id->geometry.wrap();
170 curves.tag_positions_changed();
172 }
173 else if (obedit->type == OB_POINTCLOUD) {
174 PointCloud *pointcloud = static_cast<PointCloud *>(obedit->data);
175 pointcloud->tag_positions_changed();
176 }
177}
178
179static void set_mapped_co(void *vuserdata, int index, const float co[3], const float /*no*/[3])
180{
181 void **userdata = static_cast<void **>(vuserdata);
182 BMEditMesh *em = static_cast<BMEditMesh *>(userdata[0]);
183 TransVert *tv = static_cast<TransVert *>(userdata[1]);
184 BMVert *eve = BM_vert_at_index(em->bm, index);
185
186 if (BM_elem_index_get(eve) != TM_INDEX_SKIP) {
187 tv = &tv[BM_elem_index_get(eve)];
188
189 /* Be clever, get the closest vertex to the original,
190 * behaves most logically when the mirror modifier is used for eg #33051. */
191 if ((tv->flag & TX_VERT_USE_MAPLOC) == 0) {
192 /* first time */
193 copy_v3_v3(tv->maploc, co);
195 }
196 else {
197 /* find best location to use */
198 if (len_squared_v3v3(eve->co, co) < len_squared_v3v3(eve->co, tv->maploc)) {
199 copy_v3_v3(tv->maploc, co);
200 }
201 }
202 }
203}
204
206{
207 return ELEM(obedit->type,
210 OB_MESH,
211 OB_SURF,
213 OB_MBALL,
214 OB_CURVES,
216}
217
218void ED_transverts_create_from_obedit(TransVertStore *tvs, const Object *obedit, const int mode)
219{
220 using namespace blender;
222
223 Nurb *nu;
224 BezTriple *bezt;
225 BPoint *bp;
226 TransVert *tv = nullptr;
227 MetaElem *ml;
228 BMVert *eve;
229 int a;
230
231 tvs->transverts_tot = 0;
232
233 if (obedit->type == OB_MESH) {
234 const Object *object_orig = DEG_get_original(obedit);
235 const Mesh &mesh = *static_cast<Mesh *>(object_orig->data);
236 BMEditMesh *em = mesh.runtime->edit_mesh.get();
237 BMesh *bm = em->bm;
238 BMIter iter;
239 void *userdata[2] = {em, nullptr};
240 // int proptrans = 0; /*UNUSED*/
241
242 /* abuses vertex index all over, set, just set dirty here,
243 * perhaps this could use its own array instead? - campbell */
244
245 /* transform now requires awareness for select mode, so we tag the f1 flags in verts */
246 tvs->transverts_tot = 0;
247 if (em->selectmode & SCE_SELECT_VERTEX) {
248 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
250 BM_elem_index_set(eve, TM_INDEX_ON); /* set_dirty! */
251 tvs->transverts_tot++;
252 }
253 else {
254 BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
255 }
256 }
257 }
258 else if (em->selectmode & SCE_SELECT_EDGE) {
259 BMEdge *eed;
260
261 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
262 BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
263 }
264
265 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
267 BM_elem_index_set(eed->v1, TM_INDEX_ON); /* set_dirty! */
268 BM_elem_index_set(eed->v2, TM_INDEX_ON); /* set_dirty! */
269 }
270 }
271
272 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
273 if (BM_elem_index_get(eve) == TM_INDEX_ON) {
274 tvs->transverts_tot++;
275 }
276 }
277 }
278 else {
279 BMFace *efa;
280
281 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
282 BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
283 }
284
285 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
287 BMIter liter;
288 BMLoop *l;
289
290 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
291 BM_elem_index_set(l->v, TM_INDEX_ON); /* set_dirty! */
292 }
293 }
294 }
295
296 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
297 if (BM_elem_index_get(eve) == TM_INDEX_ON) {
298 tvs->transverts_tot++;
299 }
300 }
301 }
302 /* for any of the 3 loops above which all dirty the indices */
303 bm->elem_index_dirty |= BM_VERT;
304
305 /* and now make transverts */
306 if (tvs->transverts_tot) {
307 tv = tvs->transverts = MEM_calloc_arrayN<TransVert>(tvs->transverts_tot, __func__);
308
309 a = 0;
310 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
311 if (BM_elem_index_get(eve)) {
312 BM_elem_index_set(eve, a); /* set_dirty! */
313 copy_v3_v3(tv->oldloc, eve->co);
314 tv->loc = eve->co;
315 tv->flag = (BM_elem_index_get(eve) == TM_INDEX_ON) ? SELECT : 0;
316
317 if (mode & TM_CALC_NORMALS) {
319 copy_v3_v3(tv->normal, eve->no);
320 }
321
322 tv++;
323 a++;
324 }
325 else {
326 BM_elem_index_set(eve, TM_INDEX_SKIP); /* set_dirty! */
327 }
328 }
329 /* set dirty already, above */
330
331 userdata[1] = tvs->transverts;
332 }
333
334 if (mode & TM_CALC_MAPLOC) {
335 const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(obedit);
336 if (tvs->transverts && editmesh_eval_cage) {
339 editmesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
340 }
341 }
342 }
343 else if (obedit->type == OB_ARMATURE) {
344 bArmature *arm = static_cast<bArmature *>(obedit->data);
345 int totmalloc = BLI_listbase_count(arm->edbo);
346
347 totmalloc *= 2; /* probably overkill but bones can have 2 trans verts each */
348
349 tv = tvs->transverts = MEM_calloc_arrayN<TransVert>(totmalloc, __func__);
350
351 LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
352 if (blender::animrig::bone_is_visible(arm, ebo)) {
353 const bool tipsel = (ebo->flag & BONE_TIPSEL) != 0;
354 const bool rootsel = (ebo->flag & BONE_ROOTSEL) != 0;
355 const bool rootok = !(ebo->parent && (ebo->flag & BONE_CONNECTED) &&
356 (blender::animrig::bone_is_visible(arm, ebo->parent) &&
357 (ebo->parent->flag & BONE_TIPSEL)));
358
359 if ((tipsel && rootsel) || (rootsel)) {
360 /* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
361 * otherwise we get zero-length bones as tips will snap to the same
362 * location as heads.
363 */
364 if (rootok) {
365 copy_v3_v3(tv->oldloc, ebo->head);
366 tv->loc = ebo->head;
367 tv->flag = SELECT;
368 tv++;
369 tvs->transverts_tot++;
370 }
371
372 if ((mode & TM_ALL_JOINTS) && (tipsel)) {
373 copy_v3_v3(tv->oldloc, ebo->tail);
374 tv->loc = ebo->tail;
375 tv->flag = SELECT;
376 tv++;
377 tvs->transverts_tot++;
378 }
379 }
380 else if (tipsel) {
381 copy_v3_v3(tv->oldloc, ebo->tail);
382 tv->loc = ebo->tail;
383 tv->flag = SELECT;
384 tv++;
385 tvs->transverts_tot++;
386 }
387 }
388 }
389 }
390 else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
391 Curve *cu = static_cast<Curve *>(obedit->data);
392 int totmalloc = 0;
394
395 LISTBASE_FOREACH (Nurb *, nu, nurbs) {
396 if (nu->type == CU_BEZIER) {
397 totmalloc += 3 * nu->pntsu;
398 }
399 else {
400 totmalloc += nu->pntsu * nu->pntsv;
401 }
402 }
403 tv = tvs->transverts = MEM_calloc_arrayN<TransVert>(totmalloc, __func__);
404
405 nu = static_cast<Nurb *>(nurbs->first);
406 while (nu) {
407 if (nu->type == CU_BEZIER) {
408 a = nu->pntsu;
409 bezt = nu->bezt;
410 while (a--) {
411 if (bezt->hide == 0) {
412 bool skip_handle = false;
413 if (bezt->f2 & SELECT) {
414 skip_handle = (mode & TM_SKIP_HANDLES) != 0;
415 }
416
417 if ((bezt->f1 & SELECT) && !skip_handle) {
418 copy_v3_v3(tv->oldloc, bezt->vec[0]);
419 tv->loc = bezt->vec[0];
420 tv->flag = bezt->f1 & SELECT;
421
422 if (mode & TM_CALC_NORMALS) {
424 BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
425 }
426
427 tv++;
428 tvs->transverts_tot++;
429 }
430 if (bezt->f2 & SELECT) {
431 copy_v3_v3(tv->oldloc, bezt->vec[1]);
432 tv->loc = bezt->vec[1];
433 tv->flag = bezt->f2 & SELECT;
434
435 if (mode & TM_CALC_NORMALS) {
437 BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
438 }
439
440 tv++;
441 tvs->transverts_tot++;
442 }
443 if ((bezt->f3 & SELECT) && !skip_handle) {
444 copy_v3_v3(tv->oldloc, bezt->vec[2]);
445 tv->loc = bezt->vec[2];
446 tv->flag = bezt->f3 & SELECT;
447
448 if (mode & TM_CALC_NORMALS) {
450 BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
451 }
452
453 tv++;
454 tvs->transverts_tot++;
455 }
456 }
457 bezt++;
458 }
459 }
460 else {
461 a = nu->pntsu * nu->pntsv;
462 bp = nu->bp;
463 while (a--) {
464 if (bp->hide == 0) {
465 if (bp->f1 & SELECT) {
466 copy_v3_v3(tv->oldloc, bp->vec);
467 tv->loc = bp->vec;
468 tv->flag = bp->f1 & SELECT;
469 tv++;
470 tvs->transverts_tot++;
471 }
472 }
473 bp++;
474 }
475 }
476 nu = nu->next;
477 }
478 }
479 else if (obedit->type == OB_MBALL) {
480 MetaBall *mb = static_cast<MetaBall *>(obedit->data);
481 int totmalloc = BLI_listbase_count(mb->editelems);
482
483 tv = tvs->transverts = MEM_calloc_arrayN<TransVert>(totmalloc, __func__);
484
485 ml = static_cast<MetaElem *>(mb->editelems->first);
486 while (ml) {
487 if (ml->flag & SELECT) {
488 tv->loc = &ml->x;
489 copy_v3_v3(tv->oldloc, tv->loc);
490 tv->flag = SELECT;
491 tv++;
492 tvs->transverts_tot++;
493 }
494 ml = ml->next;
495 }
496 }
497 else if (obedit->type == OB_LATTICE) {
498 Lattice *lt = static_cast<Lattice *>(obedit->data);
499
500 bp = lt->editlatt->latt->def;
501
502 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
503
504 tv = tvs->transverts = MEM_calloc_arrayN<TransVert>(a, __func__);
505
506 while (a--) {
507 if (bp->f1 & SELECT) {
508 if (bp->hide == 0) {
509 copy_v3_v3(tv->oldloc, bp->vec);
510 tv->loc = bp->vec;
511 tv->flag = bp->f1 & SELECT;
512 tv++;
513 tvs->transverts_tot++;
514 }
515 }
516 bp++;
517 }
518 }
519 else if (obedit->type == OB_CURVES) {
520 Curves *curves_id = static_cast<Curves *>(obedit->data);
522 curves_id->geometry.wrap(), tvs, ((mode & TM_SKIP_HANDLES) != 0));
523 }
524 else if (obedit->type == OB_POINTCLOUD) {
525 PointCloud *pointcloud = static_cast<PointCloud *>(obedit->data);
526
527 IndexMaskMemory memory;
529 memory);
530 MutableSpan<float3> positions = pointcloud->positions_for_write();
531
532 tvs->transverts = MEM_calloc_arrayN<TransVert>(selection.size(), __func__);
533 tvs->transverts_tot = selection.size();
534
535 selection.foreach_index(GrainSize(1024), [&](const int64_t i, const int64_t pos) {
536 TransVert &tv = tvs->transverts[pos];
537 tv.loc = positions[i];
538 tv.flag = SELECT;
539 copy_v3_v3(tv.oldloc, tv.loc);
540 });
541 }
542
543 if (!tvs->transverts_tot && tvs->transverts) {
544 /* Prevent memory leak. happens for curves/lattices due to
545 * difficult condition of adding points to trans data. */
546 MEM_freeN(tvs->transverts);
547 tvs->transverts = nullptr;
548 }
549
550 tvs->mode = mode;
551}
552
554{
556 tvs->transverts_tot = 0;
557}
558
560{
561 Object *obedit = CTX_data_edit_object(C);
562 if (obedit) {
563 if (ED_transverts_check_obedit(obedit)) {
564 return true;
565 }
566 }
567 return false;
568}
Functions to deal with Armatures.
Object * CTX_data_edit_object(const bContext *C)
@ NURB_HANDLE_TEST_EACH
Definition BKE_curve.hh:61
void BKE_nurb_project_2d(Nurb *nu)
Definition curve.cc:684
#define CU_IS_2D(cu)
Definition BKE_curve.hh:89
void BKE_nurb_handles_test(Nurb *nu, eNurbHandleTest_Mode handle_mode, bool use_around_local)
Definition curve.cc:4084
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition curve.cc:419
void BKE_nurb_bezt_calc_plane(Nurb *nu, BezTriple *bezt, float r_plane[3])
Definition curve.cc:1022
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
void outside_lattice(Lattice *lt)
Definition lattice.cc:401
@ MESH_FOREACH_NOP
void BKE_mesh_foreach_mapped_vert(const Mesh *mesh, void(*func)(void *user_data, int index, const float co[3], const float no[3]), void *user_data, MeshForeachFlag flag)
General operations, lookup, etc. for blender objects.
const Mesh * BKE_object_get_editmesh_eval_cage(const Object *object)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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 void add_v3_v3(float r[3], const float a[3])
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
bool DEG_is_evaluated(const T *id)
T * DEG_get_original(T *id)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ BONE_ROOTSEL
@ BONE_TIPSEL
@ BONE_CONNECTED
@ ARM_MIRROR_EDIT
@ CU_BEZIER
@ LT_OUTSIDE
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_ARMATURE
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES_LEGACY
@ OB_CURVES
@ SCE_SELECT_VERTEX
@ SCE_SELECT_EDGE
@ TM_INDEX_OFF
@ TM_INDEX_ON
@ TM_INDEX_SKIP
@ TX_VERT_USE_MAPLOC
@ TX_VERT_USE_NORMAL
@ TM_SKIP_HANDLES
@ TM_CALC_MAPLOC
@ TM_CALC_NORMALS
@ TM_ALL_JOINTS
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition RandGen.cpp:29
void ED_armature_edit_transform_mirror_update(Object *obedit)
@ BM_ELEM_HIDDEN
@ BM_ELEM_SELECT
#define BM_elem_index_get(ele)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
BMesh * bm
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
void BM_mesh_normals_update(BMesh *bm)
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
int64_t size() const
void foreach_index(Fn &&fn) const
#define SELECT
bool ED_transverts_check_obedit(const Object *obedit)
bool ED_transverts_poll(bContext *C)
static void set_mapped_co(void *vuserdata, int index, const float co[3], const float[3])
void ED_transverts_free(TransVertStore *tvs)
void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
void ED_transverts_create_from_obedit(TransVertStore *tvs, const Object *obedit, const int mode)
uint pos
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool bone_is_visible(const bArmature *armature, const Bone *bone)
void transverts_from_curves_positions_create(bke::CurvesGeometry &curves, TransVertStore *tvs, const bool skip_handles)
IndexMask retrieve_selected_points(const PointCloud &pointcloud, IndexMaskMemory &memory)
Definition selection.cc:279
BMVert * v1
BMVert * v2
short selectmode
float co[3]
float no[3]
uint8_t f1
float vec[4]
float vec[3][3]
CurvesGeometry geometry
struct Lattice * latt
Definition DNA_ID.h:414
struct EditLatt * editlatt
struct BPoint * def
void * first
MeshRuntimeHandle * runtime
ListBase * editelems
struct MetaElem * next
struct Nurb * next
short type
BezTriple * bezt
BPoint * bp
TransVert * transverts
float * loc
float maploc[3]
float oldloc[3]
float normal[3]
ListBase * edbo
i
Definition text_draw.cc:230