Merge branch 'master' into blender2.8
This commit is contained in:
commit
43d0943141
|
@ -60,6 +60,7 @@ set(SRC
|
|||
editmesh_undo.c
|
||||
editmesh_utils.c
|
||||
mesh_data.c
|
||||
mesh_mirror.c
|
||||
mesh_ops.c
|
||||
meshtools.c
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
* \ingroup edmesh
|
||||
*/
|
||||
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
|
@ -41,7 +40,6 @@
|
|||
#include "BKE_global.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_editmesh.h"
|
||||
|
||||
#include "BIF_gl.h"
|
||||
|
||||
|
@ -609,261 +607,3 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
|
|||
paintvert_flush_flags(ob);
|
||||
}
|
||||
}
|
||||
|
||||
/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */
|
||||
/* note, this is not the best place for the function to be but moved
|
||||
* here for the purpose of syncing with bmesh */
|
||||
|
||||
typedef unsigned int MirrTopoHash_t;
|
||||
|
||||
typedef struct MirrTopoVert_t {
|
||||
MirrTopoHash_t hash;
|
||||
int v_index;
|
||||
} MirrTopoVert_t;
|
||||
|
||||
static int mirrtopo_hash_sort(const void *l1, const void *l2)
|
||||
{
|
||||
if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1;
|
||||
else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mirrtopo_vert_sort(const void *v1, const void *v2)
|
||||
{
|
||||
if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1;
|
||||
else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store)
|
||||
{
|
||||
const bool is_editmode = (me->edit_btmesh != NULL);
|
||||
int totvert;
|
||||
int totedge;
|
||||
|
||||
if (dm) {
|
||||
totvert = dm->getNumVerts(dm);
|
||||
totedge = dm->getNumEdges(dm);
|
||||
}
|
||||
else if (me->edit_btmesh) {
|
||||
totvert = me->edit_btmesh->bm->totvert;
|
||||
totedge = me->edit_btmesh->bm->totedge;
|
||||
}
|
||||
else {
|
||||
totvert = me->totvert;
|
||||
totedge = me->totedge;
|
||||
}
|
||||
|
||||
if ((mesh_topo_store->index_lookup == NULL) ||
|
||||
(mesh_topo_store->prev_is_editmode != is_editmode) ||
|
||||
(totvert != mesh_topo_store->prev_vert_tot) ||
|
||||
(totedge != mesh_topo_store->prev_edge_tot))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ED_mesh_mirrtopo_init(
|
||||
Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store,
|
||||
const bool skip_em_vert_array_init)
|
||||
{
|
||||
const bool is_editmode = (me->edit_btmesh != NULL);
|
||||
MEdge *medge = NULL, *med;
|
||||
BMEditMesh *em = dm ? NULL : me->edit_btmesh;
|
||||
|
||||
/* editmode*/
|
||||
BMEdge *eed;
|
||||
BMIter iter;
|
||||
|
||||
int a, last;
|
||||
int totvert, totedge;
|
||||
int tot_unique = -1, tot_unique_prev = -1;
|
||||
int tot_unique_edges = 0, tot_unique_edges_prev;
|
||||
|
||||
MirrTopoHash_t *topo_hash = NULL;
|
||||
MirrTopoHash_t *topo_hash_prev = NULL;
|
||||
MirrTopoVert_t *topo_pairs;
|
||||
MirrTopoHash_t topo_pass = 1;
|
||||
|
||||
intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */
|
||||
|
||||
/* reallocate if needed */
|
||||
ED_mesh_mirrtopo_free(mesh_topo_store);
|
||||
|
||||
mesh_topo_store->prev_is_editmode = is_editmode;
|
||||
|
||||
if (em) {
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
|
||||
|
||||
totvert = em->bm->totvert;
|
||||
}
|
||||
else {
|
||||
totvert = dm ? dm->getNumVerts(dm) : me->totvert;
|
||||
}
|
||||
|
||||
topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
|
||||
|
||||
/* Initialize the vert-edge-user counts used to detect unique topology */
|
||||
if (em) {
|
||||
totedge = me->edit_btmesh->bm->totedge;
|
||||
|
||||
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
|
||||
const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
|
||||
topo_hash[i1]++;
|
||||
topo_hash[i2]++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
totedge = dm ? dm->getNumEdges(dm) : me->totedge;
|
||||
medge = dm ? dm->getEdgeArray(dm) : me->medge;
|
||||
|
||||
for (a = 0, med = medge; a < totedge; a++, med++) {
|
||||
const unsigned int i1 = med->v1, i2 = med->v2;
|
||||
topo_hash[i1]++;
|
||||
topo_hash[i2]++;
|
||||
}
|
||||
}
|
||||
|
||||
topo_hash_prev = MEM_dupallocN(topo_hash);
|
||||
|
||||
tot_unique_prev = -1;
|
||||
tot_unique_edges_prev = -1;
|
||||
while (1) {
|
||||
/* use the number of edges per vert to give verts unique topology IDs */
|
||||
|
||||
tot_unique_edges = 0;
|
||||
|
||||
/* This can make really big numbers, wrapping around here is fine */
|
||||
if (em) {
|
||||
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
|
||||
const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
|
||||
topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
|
||||
topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
|
||||
tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (a = 0, med = medge; a < totedge; a++, med++) {
|
||||
const unsigned int i1 = med->v1, i2 = med->v2;
|
||||
topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
|
||||
topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
|
||||
tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
|
||||
}
|
||||
}
|
||||
memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
|
||||
|
||||
/* sort so we can count unique values */
|
||||
qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort);
|
||||
|
||||
tot_unique = 1; /* account for skiping the first value */
|
||||
for (a = 1; a < totvert; a++) {
|
||||
if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
|
||||
tot_unique++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
|
||||
/* Finish searching for unique values when 1 loop dosnt give a
|
||||
* higher number of unique values compared to the previous loop */
|
||||
break;
|
||||
}
|
||||
else {
|
||||
tot_unique_prev = tot_unique;
|
||||
tot_unique_edges_prev = tot_unique_edges;
|
||||
}
|
||||
/* Copy the hash calculated this iter, so we can use them next time */
|
||||
memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
|
||||
|
||||
topo_pass++;
|
||||
}
|
||||
|
||||
/* Hash/Index pairs are needed for sorting to find index pairs */
|
||||
topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
|
||||
|
||||
/* since we are looping through verts, initialize these values here too */
|
||||
index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup");
|
||||
|
||||
if (em) {
|
||||
if (skip_em_vert_array_init == false) {
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
}
|
||||
}
|
||||
|
||||
for (a = 0; a < totvert; a++) {
|
||||
topo_pairs[a].hash = topo_hash[a];
|
||||
topo_pairs[a].v_index = a;
|
||||
|
||||
/* initialize lookup */
|
||||
index_lookup[a] = -1;
|
||||
}
|
||||
|
||||
qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
|
||||
|
||||
last = 0;
|
||||
|
||||
/* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
|
||||
* but you cant ever access the last 'a' index of MirrTopoPairs */
|
||||
if (em) {
|
||||
BMVert **vtable = em->bm->vtable;
|
||||
for (a = 1; a <= totvert; a++) {
|
||||
/* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
|
||||
if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
|
||||
const int match_count = a - last;
|
||||
if (match_count == 2) {
|
||||
const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
|
||||
index_lookup[j] = (intptr_t)vtable[k];
|
||||
index_lookup[k] = (intptr_t)vtable[j];
|
||||
}
|
||||
else if (match_count == 1) {
|
||||
/* Center vertex. */
|
||||
const int j = topo_pairs[a - 1].v_index;
|
||||
index_lookup[j] = (intptr_t)vtable[j];
|
||||
}
|
||||
last = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* same as above, for mesh */
|
||||
for (a = 1; a <= totvert; a++) {
|
||||
if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
|
||||
const int match_count = a - last;
|
||||
if (match_count == 2) {
|
||||
const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
|
||||
index_lookup[j] = k;
|
||||
index_lookup[k] = j;
|
||||
}
|
||||
else if (match_count == 1) {
|
||||
/* Center vertex. */
|
||||
const int j = topo_pairs[a - 1].v_index;
|
||||
index_lookup[j] = j;
|
||||
}
|
||||
last = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(topo_pairs);
|
||||
topo_pairs = NULL;
|
||||
|
||||
MEM_freeN(topo_hash);
|
||||
MEM_freeN(topo_hash_prev);
|
||||
|
||||
mesh_topo_store->index_lookup = index_lookup;
|
||||
mesh_topo_store->prev_vert_tot = totvert;
|
||||
mesh_topo_store->prev_edge_tot = totedge;
|
||||
}
|
||||
|
||||
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
|
||||
{
|
||||
if (mesh_topo_store->index_lookup) {
|
||||
MEM_freeN(mesh_topo_store->index_lookup);
|
||||
}
|
||||
mesh_topo_store->index_lookup = NULL;
|
||||
mesh_topo_store->prev_vert_tot = -1;
|
||||
mesh_topo_store->prev_edge_tot = -1;
|
||||
}
|
||||
|
|
|
@ -65,9 +65,10 @@ typedef struct MakePrimitiveData {
|
|||
bool was_editmode;
|
||||
} MakePrimitiveData;
|
||||
|
||||
static Object *make_prim_init(bContext *C, const char *idname,
|
||||
const float loc[3], const float rot[3], const unsigned int layer,
|
||||
MakePrimitiveData *r_creation_data)
|
||||
static Object *make_prim_init(
|
||||
bContext *C, const char *idname,
|
||||
const float loc[3], const float rot[3], const unsigned int layer,
|
||||
MakePrimitiveData *r_creation_data)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
|
||||
|
|
|
@ -66,6 +66,10 @@
|
|||
#include "ED_util.h"
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Extrude Internal Utilities
|
||||
* \{ */
|
||||
|
||||
static void edbm_extrude_edge_exclude_mirror(
|
||||
Object *obedit, BMEditMesh *em,
|
||||
const char hflag,
|
||||
|
@ -154,7 +158,7 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch
|
|||
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
|
||||
|
||||
BMO_op_exec(em->bm, &bmop);
|
||||
|
||||
|
||||
BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) {
|
||||
BM_face_select_set(em->bm, f, true);
|
||||
|
||||
|
@ -254,7 +258,7 @@ static bool edbm_extrude_ex(
|
|||
BMOIter siter;
|
||||
BMOperator extop;
|
||||
BMElem *ele;
|
||||
|
||||
|
||||
/* needed to remove the faces left behind */
|
||||
if (htype & BM_FACE) {
|
||||
htype |= BM_EDGE;
|
||||
|
@ -276,7 +280,7 @@ static bool edbm_extrude_ex(
|
|||
BM_SELECT_HISTORY_RESTORE(bm);
|
||||
|
||||
BMO_op_exec(bm, &extop);
|
||||
|
||||
|
||||
BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) {
|
||||
BM_elem_select_set(bm, ele, true);
|
||||
}
|
||||
|
@ -286,14 +290,20 @@ static bool edbm_extrude_ex(
|
|||
return true;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Extrude Repeat Operator
|
||||
* \{ */
|
||||
|
||||
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
RegionView3D *rv3d = CTX_wm_region_view3d(C);
|
||||
|
||||
|
||||
const int steps = RNA_int_get(op->ptr, "steps");
|
||||
|
||||
|
||||
const float offs = RNA_float_get(op->ptr, "offset");
|
||||
float dvec[3], tmat[3][3], bmat[3][3];
|
||||
short a;
|
||||
|
@ -314,7 +324,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
|
|||
"translate vec=%v verts=%hv",
|
||||
dvec, BM_ELEM_SELECT);
|
||||
}
|
||||
|
||||
|
||||
EDBM_mesh_normals_update(em);
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
@ -328,19 +338,25 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
|
|||
ot->name = "Extrude Repeat Mesh";
|
||||
ot->description = "Extrude selected vertices, edges or faces repeatedly";
|
||||
ot->idname = "MESH_OT_extrude_repeat";
|
||||
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_extrude_repeat_exec;
|
||||
ot->poll = ED_operator_editmesh_view3d;
|
||||
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
|
||||
/* props */
|
||||
RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
|
||||
RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Extrude Operator
|
||||
* \{ */
|
||||
|
||||
/* generic extern called extruder */
|
||||
static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
|
||||
{
|
||||
|
@ -377,7 +393,7 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
|
|||
changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (changed) {
|
||||
return true;
|
||||
}
|
||||
|
@ -392,7 +408,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
|
||||
edbm_extrude_mesh(obedit, em, op);
|
||||
|
||||
/* This normally happens when pushing undo but modal operators
|
||||
|
@ -401,7 +417,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
|
|||
EDBM_mesh_normals_update(em);
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -411,27 +427,33 @@ void MESH_OT_extrude_region(wmOperatorType *ot)
|
|||
ot->name = "Extrude Region";
|
||||
ot->idname = "MESH_OT_extrude_region";
|
||||
ot->description = "Extrude region of faces";
|
||||
|
||||
|
||||
/* api callbacks */
|
||||
//ot->invoke = mesh_extrude_region_invoke;
|
||||
ot->exec = edbm_extrude_region_exec;
|
||||
ot->poll = ED_operator_editmesh;
|
||||
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Extrude Verts Operator
|
||||
* \{ */
|
||||
|
||||
static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
|
||||
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -441,11 +463,11 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
|
|||
ot->name = "Extrude Only Vertices";
|
||||
ot->idname = "MESH_OT_extrude_verts_indiv";
|
||||
ot->description = "Extrude individual vertices only";
|
||||
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_extrude_verts_exec;
|
||||
ot->poll = ED_operator_editmesh;
|
||||
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
|
@ -453,15 +475,21 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
|
|||
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Extrude Edges Operator
|
||||
* \{ */
|
||||
|
||||
static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT);
|
||||
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -471,11 +499,11 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
|
|||
ot->name = "Extrude Only Edges";
|
||||
ot->idname = "MESH_OT_extrude_edges_indiv";
|
||||
ot->description = "Extrude individual edges only";
|
||||
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_extrude_edges_exec;
|
||||
ot->poll = ED_operator_editmesh;
|
||||
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
|
@ -483,15 +511,21 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
|
|||
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Extrude Faces Operator
|
||||
* \{ */
|
||||
|
||||
static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT);
|
||||
|
||||
|
||||
EDBM_update_generic(em, true, true);
|
||||
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@ -501,18 +535,25 @@ void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
|
|||
ot->name = "Extrude Individual Faces";
|
||||
ot->idname = "MESH_OT_extrude_faces_indiv";
|
||||
ot->description = "Extrude individual faces only";
|
||||
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = edbm_extrude_faces_exec;
|
||||
ot->poll = ED_operator_editmesh;
|
||||
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
|
||||
}
|
||||
|
||||
/* *************** add-click-mesh (extrude) operator ************** */
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Dupli-Extrude Operator
|
||||
*
|
||||
* Add-click-mesh (extrude) operator.
|
||||
* \{ */
|
||||
|
||||
static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ViewContext vc;
|
||||
|
@ -533,7 +574,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
|
|||
|
||||
zero_v3(center);
|
||||
verts_len = 0;
|
||||
|
||||
|
||||
BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
|
||||
if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
|
||||
add_v3_v3(center, v1->co);
|
||||
|
@ -596,7 +637,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
|
|||
cross_v3_v3v3(nor, view_vec, cross);
|
||||
normalize_v3(nor);
|
||||
}
|
||||
|
||||
|
||||
/* center */
|
||||
copy_v3_v3(ofs, center);
|
||||
|
||||
|
@ -605,7 +646,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
|
|||
mul_m4_v3(vc.obedit->imat, ofs); // back in object space
|
||||
|
||||
sub_v3_v3(ofs, center);
|
||||
|
||||
|
||||
/* calculate rotation */
|
||||
unit_m3(mat);
|
||||
if (done) {
|
||||
|
@ -628,7 +669,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
|
|||
axis_angle_to_mat3(mat, axis, angle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rot_src) {
|
||||
EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3",
|
||||
BM_ELEM_SELECT, center, mat);
|
||||
|
@ -653,7 +694,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
|
|||
ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center);
|
||||
|
||||
mul_m4_v3(vc.obedit->imat, center); // back in object space
|
||||
|
||||
|
||||
EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center);
|
||||
BMO_op_exec(vc.em->bm, &bmop);
|
||||
|
||||
|
@ -685,17 +726,22 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
|
|||
ot->name = "Duplicate or Extrude to Cursor";
|
||||
ot->idname = "MESH_OT_dupli_extrude_cursor";
|
||||
ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
|
||||
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = edbm_dupli_extrude_cursor_invoke;
|
||||
ot->poll = ED_operator_editmesh_region_view3d;
|
||||
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Spin Operator
|
||||
* \{ */
|
||||
|
||||
static int edbm_spin_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
@ -815,8 +861,7 @@ void MESH_OT_spin(wmOperatorType *ot)
|
|||
#ifdef USE_MANIPULATOR
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
/** \name Spin Manipulator
|
||||
/** \name Screw Operator
|
||||
* \{ */
|
||||
|
||||
typedef struct ManipulatorSpinGroup {
|
||||
|
@ -1315,3 +1360,5 @@ void MESH_OT_screw(wmOperatorType *ot)
|
|||
RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f,
|
||||
"Axis", "Axis in global view space", -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -63,6 +63,10 @@
|
|||
|
||||
#include "mesh_intern.h" /* own include */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Path Select Struct & Properties
|
||||
* \{ */
|
||||
|
||||
struct PathSelectParams {
|
||||
bool track_active; /* ensure the active element is the last selected item (handy for picking) */
|
||||
bool use_topology_distance;
|
||||
|
@ -102,8 +106,11 @@ struct UserData {
|
|||
const struct PathSelectParams *op_params;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Vert Path */
|
||||
/** \name Vert Path
|
||||
* \{ */
|
||||
|
||||
/* callbacks */
|
||||
static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
|
||||
|
@ -205,10 +212,11 @@ static void mouse_mesh_shortest_path_vert(
|
|||
EDBM_update_generic(em, false, false);
|
||||
}
|
||||
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Edge Path */
|
||||
/** \name Edge Path
|
||||
* \{ */
|
||||
|
||||
/* callbacks */
|
||||
static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
|
||||
|
@ -427,10 +435,11 @@ static void mouse_mesh_shortest_path_edge(
|
|||
EDBM_update_generic(em, false, false);
|
||||
}
|
||||
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Face Path */
|
||||
/** \name Face Path
|
||||
* \{ */
|
||||
|
||||
/* callbacks */
|
||||
static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
|
||||
|
@ -477,7 +486,6 @@ static void mouse_mesh_shortest_path_face(
|
|||
facetag_filter_cb, &user_data);
|
||||
}
|
||||
|
||||
|
||||
if (f_act != f_dst) {
|
||||
if (path) {
|
||||
if (op_params->track_active) {
|
||||
|
@ -538,10 +546,11 @@ static void mouse_mesh_shortest_path_face(
|
|||
EDBM_update_generic(em, false, false);
|
||||
}
|
||||
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Main Operator for vert/edge/face tag */
|
||||
/** \name Main Operator for vert/edge/face tag
|
||||
* \{ */
|
||||
|
||||
static bool edbm_shortest_path_pick_ex(
|
||||
Scene *scene, Object *obedit, const struct PathSelectParams *op_params,
|
||||
|
@ -710,9 +719,11 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Select path between existing selection */
|
||||
/** \name Select Path Between Existing Selection
|
||||
* \{ */
|
||||
|
||||
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
|
@ -797,3 +808,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot)
|
|||
/* properties */
|
||||
path_select_properties(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -64,8 +64,14 @@
|
|||
|
||||
#include "mesh_intern.h" /* own include */
|
||||
|
||||
/* mesh backup implementation. This would greatly benefit from some sort of binary diffing
|
||||
* just as the undo stack would. So leaving this as an interface for further work */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Redo API
|
||||
* \{ */
|
||||
|
||||
/* Mesh backup implementation.
|
||||
* This would greatly benefit from some sort of binary diffing
|
||||
* just as the undo stack would.
|
||||
* So leaving this as an interface for further work */
|
||||
|
||||
BMBackup EDBM_redo_state_store(BMEditMesh *em)
|
||||
{
|
||||
|
@ -77,8 +83,9 @@ BMBackup EDBM_redo_state_store(BMEditMesh *em)
|
|||
void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
|
||||
{
|
||||
BMesh *tmpbm;
|
||||
if (!em || !backup.bmcopy)
|
||||
if (!em || !backup.bmcopy) {
|
||||
return;
|
||||
}
|
||||
|
||||
BM_mesh_data_free(em->bm);
|
||||
tmpbm = BM_mesh_copy(backup.bmcopy);
|
||||
|
@ -86,8 +93,9 @@ void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
|
|||
MEM_freeN(tmpbm);
|
||||
tmpbm = NULL;
|
||||
|
||||
if (recalctess)
|
||||
if (recalctess) {
|
||||
BKE_editmesh_tessface_calc(em);
|
||||
}
|
||||
}
|
||||
|
||||
void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
|
||||
|
@ -100,68 +108,21 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
|
|||
BM_mesh_data_free(backup->bmcopy);
|
||||
}
|
||||
|
||||
if (backup->bmcopy)
|
||||
if (backup->bmcopy) {
|
||||
MEM_freeN(backup->bmcopy);
|
||||
}
|
||||
backup->bmcopy = NULL;
|
||||
|
||||
if (recalctess && em)
|
||||
if (recalctess && em) {
|
||||
BKE_editmesh_tessface_calc(em);
|
||||
}
|
||||
|
||||
void EDBM_mesh_normals_update(BMEditMesh *em)
|
||||
{
|
||||
BM_mesh_normals_update(em->bm);
|
||||
}
|
||||
|
||||
void EDBM_mesh_clear(BMEditMesh *em)
|
||||
{
|
||||
/* clear bmesh */
|
||||
BM_mesh_clear(em->bm);
|
||||
|
||||
/* free derived meshes */
|
||||
BKE_editmesh_free_derivedmesh(em);
|
||||
|
||||
/* free tessellation data */
|
||||
em->tottri = 0;
|
||||
if (em->looptris) {
|
||||
MEM_freeN(em->looptris);
|
||||
em->looptris = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void EDBM_stats_update(BMEditMesh *em)
|
||||
{
|
||||
const char iter_types[3] = {BM_VERTS_OF_MESH,
|
||||
BM_EDGES_OF_MESH,
|
||||
BM_FACES_OF_MESH};
|
||||
/** \} */
|
||||
|
||||
BMIter iter;
|
||||
BMElem *ele;
|
||||
int *tots[3];
|
||||
int i;
|
||||
|
||||
tots[0] = &em->bm->totvertsel;
|
||||
tots[1] = &em->bm->totedgesel;
|
||||
tots[2] = &em->bm->totfacesel;
|
||||
|
||||
em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
|
||||
for ( ; ele; ele = BM_iter_step(&iter)) {
|
||||
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
||||
(*tots[i])++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em)
|
||||
{
|
||||
return ((em->derivedFinal != NULL) &&
|
||||
(em->derivedFinal->type == DM_TYPE_EDITBMESH) &&
|
||||
(em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL;
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name BMesh Operator (BMO) API Wrapper
|
||||
* \{ */
|
||||
|
||||
bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
|
||||
{
|
||||
|
@ -175,9 +136,10 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
|
|||
va_end(list);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!em->emcopy)
|
||||
|
||||
if (!em->emcopy) {
|
||||
em->emcopy = BKE_editmesh_copy(em);
|
||||
}
|
||||
em->emcopyusers++;
|
||||
|
||||
va_end(list);
|
||||
|
@ -185,12 +147,11 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* returns 0 on error, 1 on success. executes and finishes a bmesh operator */
|
||||
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
|
||||
{
|
||||
const char *errmsg;
|
||||
|
||||
|
||||
BMO_op_finish(em->bm, bmop);
|
||||
|
||||
if (BMO_error_get(em->bm, &errmsg, NULL)) {
|
||||
|
@ -245,8 +206,9 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!em->emcopy)
|
||||
if (!em->emcopy) {
|
||||
em->emcopy = BKE_editmesh_copy(em);
|
||||
}
|
||||
em->emcopyusers++;
|
||||
|
||||
BMO_op_exec(bm, &bmop);
|
||||
|
@ -255,9 +217,10 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
|
|||
return EDBM_op_finish(em, &bmop, op, true);
|
||||
}
|
||||
|
||||
bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op,
|
||||
const char *select_slot_out, const bool select_extend,
|
||||
const char *fmt, ...)
|
||||
bool EDBM_op_call_and_selectf(
|
||||
BMEditMesh *em, wmOperator *op,
|
||||
const char *select_slot_out, const bool select_extend,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
BMOpSlot *slot_select_out;
|
||||
BMesh *bm = em->bm;
|
||||
|
@ -273,8 +236,9 @@ bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!em->emcopy)
|
||||
if (!em->emcopy) {
|
||||
em->emcopy = BKE_editmesh_copy(em);
|
||||
}
|
||||
em->emcopyusers++;
|
||||
|
||||
BMO_op_exec(bm, &bmop);
|
||||
|
@ -306,8 +270,9 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!em->emcopy)
|
||||
if (!em->emcopy) {
|
||||
em->emcopy = BKE_editmesh_copy(em);
|
||||
}
|
||||
em->emcopyusers++;
|
||||
|
||||
BMO_op_exec(bm, &bmop);
|
||||
|
@ -316,20 +281,13 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
|
|||
return EDBM_op_finish(em, &bmop, NULL, false);
|
||||
}
|
||||
|
||||
void EDBM_selectmode_to_scene(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
/** \} */
|
||||
|
||||
if (!em)
|
||||
return;
|
||||
|
||||
scene->toolsettings->selectmode = em->selectmode;
|
||||
|
||||
/* Request redraw of header buttons (to show new select mode) */
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
|
||||
}
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Edit BMesh API
|
||||
*
|
||||
* Make/Clear/Free functions.
|
||||
* \{ */
|
||||
|
||||
void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
|
||||
{
|
||||
|
@ -413,6 +371,22 @@ void EDBM_mesh_load(Object *ob)
|
|||
#endif
|
||||
}
|
||||
|
||||
void EDBM_mesh_clear(BMEditMesh *em)
|
||||
{
|
||||
/* clear bmesh */
|
||||
BM_mesh_clear(em->bm);
|
||||
|
||||
/* free derived meshes */
|
||||
BKE_editmesh_free_derivedmesh(em);
|
||||
|
||||
/* free tessellation data */
|
||||
em->tottri = 0;
|
||||
if (em->looptris) {
|
||||
MEM_freeN(em->looptris);
|
||||
em->looptris = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should only be called on the active editmesh, otherwise call #BKE_editmesh_free
|
||||
*/
|
||||
|
@ -427,6 +401,28 @@ void EDBM_mesh_free(BMEditMesh *em)
|
|||
BKE_editmesh_free(em);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Selection Utilities
|
||||
* \{ */
|
||||
|
||||
void EDBM_selectmode_to_scene(bContext *C)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||
|
||||
if (!em) {
|
||||
return;
|
||||
}
|
||||
|
||||
scene->toolsettings->selectmode = em->selectmode;
|
||||
|
||||
/* Request redraw of header buttons (to show new select mode) */
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
|
||||
}
|
||||
|
||||
void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
|
||||
{
|
||||
BM_mesh_select_mode_flush_ex(em->bm, selectmode);
|
||||
|
@ -444,7 +440,6 @@ void EDBM_deselect_flush(BMEditMesh *em)
|
|||
BM_mesh_deselect_flush(em->bm);
|
||||
}
|
||||
|
||||
|
||||
void EDBM_select_flush(BMEditMesh *em)
|
||||
{
|
||||
/* function below doesnt use. just do this to keep the values in sync */
|
||||
|
@ -457,9 +452,10 @@ void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
|
|||
BMOperator bmop;
|
||||
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
|
||||
|
||||
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
||||
"region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
|
||||
BM_ELEM_SELECT, false, use_faces, use_face_step);
|
||||
BMO_op_initf(
|
||||
em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
||||
"region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
|
||||
BM_ELEM_SELECT, false, use_faces, use_face_step);
|
||||
BMO_op_exec(em->bm, &bmop);
|
||||
/* don't flush selection in edge/vertex mode */
|
||||
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
||||
|
@ -473,9 +469,10 @@ void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
|
|||
BMOperator bmop;
|
||||
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
|
||||
|
||||
BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
||||
"region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
|
||||
BM_ELEM_SELECT, true, use_faces, use_face_step);
|
||||
BMO_op_initf(
|
||||
em->bm, &bmop, BMO_FLAG_DEFAULTS,
|
||||
"region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
|
||||
BM_ELEM_SELECT, true, use_faces, use_face_step);
|
||||
BMO_op_exec(em->bm, &bmop);
|
||||
/* don't flush selection in edge/vertex mode */
|
||||
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
||||
|
@ -497,6 +494,12 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
|
|||
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name UV Vertex Map API
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Return a new UVVertMap from the editmesh
|
||||
*/
|
||||
|
@ -519,7 +522,7 @@ UvVertMap *BM_uv_vert_map_create(
|
|||
BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE);
|
||||
|
||||
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
|
||||
|
||||
|
||||
totfaces = bm->totface;
|
||||
totverts = bm->totvert;
|
||||
totuv = 0;
|
||||
|
@ -549,7 +552,7 @@ UvVertMap *BM_uv_vert_map_create(
|
|||
BKE_mesh_uv_vert_map_free(vmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
|
||||
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
float (*tf_uv)[2];
|
||||
|
@ -562,7 +565,7 @@ UvVertMap *BM_uv_vert_map_create(
|
|||
buf->tfindex = i;
|
||||
buf->f = a;
|
||||
buf->separate = 0;
|
||||
|
||||
|
||||
buf->next = vmap->vert[BM_elem_index_get(l->v)];
|
||||
vmap->vert[BM_elem_index_get(l->v)] = buf;
|
||||
buf++;
|
||||
|
@ -578,7 +581,7 @@ UvVertMap *BM_uv_vert_map_create(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* sort individual uvs for each vert */
|
||||
BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
|
||||
|
@ -592,22 +595,21 @@ UvVertMap *BM_uv_vert_map_create(
|
|||
newvlist = v;
|
||||
|
||||
efa = BM_face_at_index(bm, v->f);
|
||||
|
||||
|
||||
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
|
||||
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||
uv = luv->uv;
|
||||
|
||||
|
||||
lastv = NULL;
|
||||
iterv = vlist;
|
||||
|
||||
while (iterv) {
|
||||
next = iterv->next;
|
||||
efa = BM_face_at_index(bm, iterv->f);
|
||||
|
||||
l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
|
||||
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||
uv2 = luv->uv;
|
||||
|
||||
|
||||
sub_v2_v2v2(uvdiff, uv2, uv);
|
||||
|
||||
if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] &&
|
||||
|
@ -640,13 +642,11 @@ UvVertMap *BM_uv_vert_map_create(
|
|||
return vmap;
|
||||
}
|
||||
|
||||
|
||||
UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
|
||||
{
|
||||
return vmap->vert[v];
|
||||
}
|
||||
|
||||
|
||||
/* A specialized vert map used by stitch operator */
|
||||
UvElementMap *BM_uv_element_map_create(
|
||||
BMesh *bm,
|
||||
|
@ -904,23 +904,30 @@ void BM_uv_element_map_free(UvElementMap *element_map)
|
|||
|
||||
UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
|
||||
{
|
||||
UvElement *element;
|
||||
|
||||
element = map->vert[BM_elem_index_get(l->v)];
|
||||
|
||||
for (; element; element = element->next)
|
||||
if (element->l->f == efa)
|
||||
for (UvElement *element = map->vert[BM_elem_index_get(l->v)];
|
||||
element;
|
||||
element = element->next)
|
||||
{
|
||||
if (element->l->f == efa) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Data Layer Checks
|
||||
* \{ */
|
||||
|
||||
/* last_sel, use em->act_face otherwise get the last selected face in the editselections
|
||||
* at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */
|
||||
BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
|
||||
{
|
||||
BMFace *efa = NULL;
|
||||
|
||||
|
||||
if (!EDBM_uv_check(em)) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -948,6 +955,12 @@ bool EDBM_vert_color_check(BMEditMesh *em)
|
|||
return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mirror Cache API
|
||||
* \{ */
|
||||
|
||||
static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
|
||||
{
|
||||
intptr_t eve_i = index_lookup[index];
|
||||
|
@ -982,9 +995,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
|
|||
* \param maxdist Distance for close point test.
|
||||
* \param r_index Optional array to write into, as an alternative to a customdata layer (length of total verts).
|
||||
*/
|
||||
void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool use_self, const bool use_select,
|
||||
/* extra args */
|
||||
const bool use_topology, float maxdist, int *r_index)
|
||||
void EDBM_verts_mirror_cache_begin_ex(
|
||||
BMEditMesh *em, const int axis, const bool use_self, const bool use_select,
|
||||
/* extra args */
|
||||
const bool use_topology, float maxdist, int *r_index)
|
||||
{
|
||||
Mesh *me = (Mesh *)em->ob->data;
|
||||
BMesh *bm = em->bm;
|
||||
|
@ -1008,8 +1022,9 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
|
|||
em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id);
|
||||
}
|
||||
|
||||
cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT,
|
||||
em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
|
||||
cd_vmirr_offset = CustomData_get_n_offset(
|
||||
&bm->vdata, CD_PROP_INT,
|
||||
em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
|
||||
|
||||
bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY;
|
||||
}
|
||||
|
@ -1082,14 +1097,16 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
|
|||
}
|
||||
}
|
||||
|
||||
void EDBM_verts_mirror_cache_begin(BMEditMesh *em, const int axis,
|
||||
const bool use_self, const bool use_select,
|
||||
const bool use_topology)
|
||||
void EDBM_verts_mirror_cache_begin(
|
||||
BMEditMesh *em, const int axis,
|
||||
const bool use_self, const bool use_select,
|
||||
const bool use_topology)
|
||||
{
|
||||
EDBM_verts_mirror_cache_begin_ex(em, axis,
|
||||
use_self, use_select,
|
||||
/* extra args */
|
||||
use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
|
||||
EDBM_verts_mirror_cache_begin_ex(
|
||||
em, axis,
|
||||
use_self, use_select,
|
||||
/* extra args */
|
||||
use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
|
||||
}
|
||||
|
||||
BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
|
||||
|
@ -1177,6 +1194,11 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t
|
|||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Hide/Reveal API
|
||||
* \{ */
|
||||
|
||||
/* swap is 0 or 1, if 1 it hides not selected */
|
||||
void EDBM_mesh_hide(BMEditMesh *em, bool swap)
|
||||
|
@ -1211,17 +1233,18 @@ void EDBM_mesh_hide(BMEditMesh *em, bool swap)
|
|||
*/
|
||||
}
|
||||
|
||||
|
||||
void EDBM_mesh_reveal(BMEditMesh *em, bool select)
|
||||
{
|
||||
const char iter_types[3] = {BM_VERTS_OF_MESH,
|
||||
BM_EDGES_OF_MESH,
|
||||
BM_FACES_OF_MESH};
|
||||
const char iter_types[3] = {
|
||||
BM_VERTS_OF_MESH,
|
||||
BM_EDGES_OF_MESH,
|
||||
BM_FACES_OF_MESH,
|
||||
};
|
||||
|
||||
const bool sels[3] = {
|
||||
(em->selectmode & SCE_SELECT_VERTEX) != 0,
|
||||
(em->selectmode & SCE_SELECT_EDGE) != 0,
|
||||
(em->selectmode & SCE_SELECT_FACE) != 0,
|
||||
(em->selectmode & SCE_SELECT_VERTEX) != 0,
|
||||
(em->selectmode & SCE_SELECT_EDGE) != 0,
|
||||
(em->selectmode & SCE_SELECT_FACE) != 0,
|
||||
};
|
||||
int i;
|
||||
|
||||
|
@ -1261,6 +1284,46 @@ void EDBM_mesh_reveal(BMEditMesh *em, bool select)
|
|||
EDBM_mesh_normals_update(em);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Update API
|
||||
* \{ */
|
||||
|
||||
void EDBM_mesh_normals_update(BMEditMesh *em)
|
||||
{
|
||||
BM_mesh_normals_update(em->bm);
|
||||
}
|
||||
|
||||
void EDBM_stats_update(BMEditMesh *em)
|
||||
{
|
||||
const char iter_types[3] = {
|
||||
BM_VERTS_OF_MESH,
|
||||
BM_EDGES_OF_MESH,
|
||||
BM_FACES_OF_MESH,
|
||||
};
|
||||
|
||||
BMIter iter;
|
||||
BMElem *ele;
|
||||
int *tots[3];
|
||||
int i;
|
||||
|
||||
tots[0] = &em->bm->totvertsel;
|
||||
tots[1] = &em->bm->totedgesel;
|
||||
tots[2] = &em->bm->totfacesel;
|
||||
|
||||
em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
|
||||
for ( ; ele; ele = BM_iter_step(&iter)) {
|
||||
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
||||
(*tots[i])++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* so many tools call these that we better make it a generic function.
|
||||
*/
|
||||
void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive)
|
||||
|
@ -1296,15 +1359,41 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
|
|||
#endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Data Access
|
||||
* \{ */
|
||||
|
||||
DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em)
|
||||
{
|
||||
return ((em->derivedFinal != NULL) &&
|
||||
(em->derivedFinal->type == DM_TYPE_EDITBMESH) &&
|
||||
(em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Operator Helpers
|
||||
* \{ */
|
||||
|
||||
/* poll call for mesh operators requiring a view3d context */
|
||||
int EDBM_view3d_poll(bContext *C)
|
||||
{
|
||||
if (ED_operator_editmesh(C) && ED_operator_view3d_active(C))
|
||||
if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name BMesh Element API
|
||||
* \{ */
|
||||
|
||||
BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
|
||||
{
|
||||
BMElem *ele = NULL;
|
||||
|
@ -1369,22 +1458,19 @@ BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* BMBVH functions */
|
||||
// XXX
|
||||
#if 0 //BMESH_TODO: not implemented yet
|
||||
int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
|
||||
{
|
||||
/** \} */
|
||||
|
||||
}
|
||||
#endif
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name BMesh BVH API
|
||||
* \{ */
|
||||
|
||||
static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
|
||||
{
|
||||
BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL);
|
||||
|
||||
if (f && BM_edge_in_face(e, f))
|
||||
if (f && BM_edge_in_face(e, f)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
@ -1405,8 +1491,10 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e,
|
|||
float origin[3], invmat[4][4];
|
||||
float epsilon = 0.01f;
|
||||
float end[3];
|
||||
const float mval_f[2] = {ar->winx / 2.0f,
|
||||
ar->winy / 2.0f};
|
||||
const float mval_f[2] = {
|
||||
ar->winx / 2.0f,
|
||||
ar->winy / 2.0f,
|
||||
};
|
||||
|
||||
ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false);
|
||||
|
||||
|
@ -1442,12 +1530,17 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e,
|
|||
|
||||
/* do three samplings: left, middle, right */
|
||||
f = edge_ray_cast(tree, co1, dir1, NULL, e);
|
||||
if (f && !edge_ray_cast(tree, co2, dir2, NULL, e))
|
||||
if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) {
|
||||
return true;
|
||||
else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e))
|
||||
}
|
||||
else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) {
|
||||
return true;
|
||||
else if (!f)
|
||||
}
|
||||
else if (!f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contributor(s): Blender Foundation, Campbell Barton
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/editors/mesh/mesh_mirror.c
|
||||
* \ingroup edmesh
|
||||
*
|
||||
* Mirror calculation for edit-mode and object mode.
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_bitmap.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BKE_editmesh.h"
|
||||
|
||||
#include "ED_mesh.h"
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Spatial Mirror API
|
||||
* \{ */
|
||||
|
||||
#define KD_THRESH 0.00002f
|
||||
|
||||
static struct { void *tree; } MirrKdStore = {NULL};
|
||||
|
||||
/* mode is 's' start, or 'e' end, or 'u' use */
|
||||
/* if end, ob can be NULL */
|
||||
int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
|
||||
{
|
||||
if (mode == 'u') { /* use table */
|
||||
if (MirrKdStore.tree == NULL)
|
||||
ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
|
||||
|
||||
if (MirrKdStore.tree) {
|
||||
KDTreeNearest nearest;
|
||||
const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
|
||||
|
||||
if (i != -1) {
|
||||
if (nearest.dist < KD_THRESH) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else if (mode == 's') { /* start table */
|
||||
Mesh *me = ob->data;
|
||||
const bool use_em = (!dm && em && me->edit_btmesh == em);
|
||||
const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
|
||||
|
||||
if (MirrKdStore.tree) /* happens when entering this call without ending it */
|
||||
ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
|
||||
|
||||
MirrKdStore.tree = BLI_kdtree_new(totvert);
|
||||
|
||||
if (use_em) {
|
||||
BMVert *eve;
|
||||
BMIter iter;
|
||||
int i;
|
||||
|
||||
/* this needs to be valid for index lookups later (callers need) */
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
|
||||
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
|
||||
BLI_kdtree_insert(MirrKdStore.tree, i, eve->co);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < totvert; i++, mvert++) {
|
||||
BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_kdtree_balance(MirrKdStore.tree);
|
||||
}
|
||||
else if (mode == 'e') { /* end table */
|
||||
if (MirrKdStore.tree) {
|
||||
BLI_kdtree_free(MirrKdStore.tree);
|
||||
MirrKdStore.tree = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Topology Mirror API
|
||||
* \{ */
|
||||
|
||||
typedef unsigned int MirrTopoHash_t;
|
||||
|
||||
typedef struct MirrTopoVert_t {
|
||||
MirrTopoHash_t hash;
|
||||
int v_index;
|
||||
} MirrTopoVert_t;
|
||||
|
||||
static int mirrtopo_hash_sort(const void *l1, const void *l2)
|
||||
{
|
||||
if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1;
|
||||
else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mirrtopo_vert_sort(const void *v1, const void *v2)
|
||||
{
|
||||
if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1;
|
||||
else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store)
|
||||
{
|
||||
const bool is_editmode = (me->edit_btmesh != NULL);
|
||||
int totvert;
|
||||
int totedge;
|
||||
|
||||
if (dm) {
|
||||
totvert = dm->getNumVerts(dm);
|
||||
totedge = dm->getNumEdges(dm);
|
||||
}
|
||||
else if (me->edit_btmesh) {
|
||||
totvert = me->edit_btmesh->bm->totvert;
|
||||
totedge = me->edit_btmesh->bm->totedge;
|
||||
}
|
||||
else {
|
||||
totvert = me->totvert;
|
||||
totedge = me->totedge;
|
||||
}
|
||||
|
||||
if ((mesh_topo_store->index_lookup == NULL) ||
|
||||
(mesh_topo_store->prev_is_editmode != is_editmode) ||
|
||||
(totvert != mesh_topo_store->prev_vert_tot) ||
|
||||
(totedge != mesh_topo_store->prev_edge_tot))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ED_mesh_mirrtopo_init(
|
||||
Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store,
|
||||
const bool skip_em_vert_array_init)
|
||||
{
|
||||
const bool is_editmode = (me->edit_btmesh != NULL);
|
||||
MEdge *medge = NULL, *med;
|
||||
BMEditMesh *em = dm ? NULL : me->edit_btmesh;
|
||||
|
||||
/* editmode*/
|
||||
BMEdge *eed;
|
||||
BMIter iter;
|
||||
|
||||
int a, last;
|
||||
int totvert, totedge;
|
||||
int tot_unique = -1, tot_unique_prev = -1;
|
||||
int tot_unique_edges = 0, tot_unique_edges_prev;
|
||||
|
||||
MirrTopoHash_t *topo_hash = NULL;
|
||||
MirrTopoHash_t *topo_hash_prev = NULL;
|
||||
MirrTopoVert_t *topo_pairs;
|
||||
MirrTopoHash_t topo_pass = 1;
|
||||
|
||||
intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */
|
||||
|
||||
/* reallocate if needed */
|
||||
ED_mesh_mirrtopo_free(mesh_topo_store);
|
||||
|
||||
mesh_topo_store->prev_is_editmode = is_editmode;
|
||||
|
||||
if (em) {
|
||||
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
|
||||
|
||||
totvert = em->bm->totvert;
|
||||
}
|
||||
else {
|
||||
totvert = dm ? dm->getNumVerts(dm) : me->totvert;
|
||||
}
|
||||
|
||||
topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
|
||||
|
||||
/* Initialize the vert-edge-user counts used to detect unique topology */
|
||||
if (em) {
|
||||
totedge = me->edit_btmesh->bm->totedge;
|
||||
|
||||
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
|
||||
const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
|
||||
topo_hash[i1]++;
|
||||
topo_hash[i2]++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
totedge = dm ? dm->getNumEdges(dm) : me->totedge;
|
||||
medge = dm ? dm->getEdgeArray(dm) : me->medge;
|
||||
|
||||
for (a = 0, med = medge; a < totedge; a++, med++) {
|
||||
const unsigned int i1 = med->v1, i2 = med->v2;
|
||||
topo_hash[i1]++;
|
||||
topo_hash[i2]++;
|
||||
}
|
||||
}
|
||||
|
||||
topo_hash_prev = MEM_dupallocN(topo_hash);
|
||||
|
||||
tot_unique_prev = -1;
|
||||
tot_unique_edges_prev = -1;
|
||||
while (1) {
|
||||
/* use the number of edges per vert to give verts unique topology IDs */
|
||||
|
||||
tot_unique_edges = 0;
|
||||
|
||||
/* This can make really big numbers, wrapping around here is fine */
|
||||
if (em) {
|
||||
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
|
||||
const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2);
|
||||
topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
|
||||
topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
|
||||
tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (a = 0, med = medge; a < totedge; a++, med++) {
|
||||
const unsigned int i1 = med->v1, i2 = med->v2;
|
||||
topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
|
||||
topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
|
||||
tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
|
||||
}
|
||||
}
|
||||
memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
|
||||
|
||||
/* sort so we can count unique values */
|
||||
qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort);
|
||||
|
||||
tot_unique = 1; /* account for skiping the first value */
|
||||
for (a = 1; a < totvert; a++) {
|
||||
if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
|
||||
tot_unique++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
|
||||
/* Finish searching for unique values when 1 loop dosnt give a
|
||||
* higher number of unique values compared to the previous loop */
|
||||
break;
|
||||
}
|
||||
else {
|
||||
tot_unique_prev = tot_unique;
|
||||
tot_unique_edges_prev = tot_unique_edges;
|
||||
}
|
||||
/* Copy the hash calculated this iter, so we can use them next time */
|
||||
memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert);
|
||||
|
||||
topo_pass++;
|
||||
}
|
||||
|
||||
/* Hash/Index pairs are needed for sorting to find index pairs */
|
||||
topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs");
|
||||
|
||||
/* since we are looping through verts, initialize these values here too */
|
||||
index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup");
|
||||
|
||||
if (em) {
|
||||
if (skip_em_vert_array_init == false) {
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
}
|
||||
}
|
||||
|
||||
for (a = 0; a < totvert; a++) {
|
||||
topo_pairs[a].hash = topo_hash[a];
|
||||
topo_pairs[a].v_index = a;
|
||||
|
||||
/* initialize lookup */
|
||||
index_lookup[a] = -1;
|
||||
}
|
||||
|
||||
qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort);
|
||||
|
||||
last = 0;
|
||||
|
||||
/* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2,
|
||||
* but you cant ever access the last 'a' index of MirrTopoPairs */
|
||||
if (em) {
|
||||
BMVert **vtable = em->bm->vtable;
|
||||
for (a = 1; a <= totvert; a++) {
|
||||
/* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */
|
||||
if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
|
||||
const int match_count = a - last;
|
||||
if (match_count == 2) {
|
||||
const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
|
||||
index_lookup[j] = (intptr_t)vtable[k];
|
||||
index_lookup[k] = (intptr_t)vtable[j];
|
||||
}
|
||||
else if (match_count == 1) {
|
||||
/* Center vertex. */
|
||||
const int j = topo_pairs[a - 1].v_index;
|
||||
index_lookup[j] = (intptr_t)vtable[j];
|
||||
}
|
||||
last = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* same as above, for mesh */
|
||||
for (a = 1; a <= totvert; a++) {
|
||||
if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) {
|
||||
const int match_count = a - last;
|
||||
if (match_count == 2) {
|
||||
const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index;
|
||||
index_lookup[j] = k;
|
||||
index_lookup[k] = j;
|
||||
}
|
||||
else if (match_count == 1) {
|
||||
/* Center vertex. */
|
||||
const int j = topo_pairs[a - 1].v_index;
|
||||
index_lookup[j] = j;
|
||||
}
|
||||
last = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(topo_pairs);
|
||||
topo_pairs = NULL;
|
||||
|
||||
MEM_freeN(topo_hash);
|
||||
MEM_freeN(topo_hash_prev);
|
||||
|
||||
mesh_topo_store->index_lookup = index_lookup;
|
||||
mesh_topo_store->prev_vert_tot = totvert;
|
||||
mesh_topo_store->prev_edge_tot = totedge;
|
||||
}
|
||||
|
||||
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
|
||||
{
|
||||
if (mesh_topo_store->index_lookup) {
|
||||
MEM_freeN(mesh_topo_store->index_lookup);
|
||||
}
|
||||
mesh_topo_store->index_lookup = NULL;
|
||||
mesh_topo_store->prev_vert_tot = -1;
|
||||
mesh_topo_store->prev_edge_tot = -1;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -47,8 +47,6 @@
|
|||
#include "BLI_math.h"
|
||||
#include "BLI_blenlib.h"
|
||||
|
||||
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
|
@ -682,84 +680,6 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Mesh Mirror (Spatial) */
|
||||
|
||||
/** \name Mesh Spatial Mirror API
|
||||
* \{ */
|
||||
|
||||
#define KD_THRESH 0.00002f
|
||||
|
||||
static struct { void *tree; } MirrKdStore = {NULL};
|
||||
|
||||
/* mode is 's' start, or 'e' end, or 'u' use */
|
||||
/* if end, ob can be NULL */
|
||||
int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
|
||||
{
|
||||
if (mode == 'u') { /* use table */
|
||||
if (MirrKdStore.tree == NULL)
|
||||
ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
|
||||
|
||||
if (MirrKdStore.tree) {
|
||||
KDTreeNearest nearest;
|
||||
const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
|
||||
|
||||
if (i != -1) {
|
||||
if (nearest.dist < KD_THRESH) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else if (mode == 's') { /* start table */
|
||||
Mesh *me = ob->data;
|
||||
const bool use_em = (!dm && em && me->edit_btmesh == em);
|
||||
const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
|
||||
|
||||
if (MirrKdStore.tree) /* happens when entering this call without ending it */
|
||||
ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
|
||||
|
||||
MirrKdStore.tree = BLI_kdtree_new(totvert);
|
||||
|
||||
if (use_em) {
|
||||
BMVert *eve;
|
||||
BMIter iter;
|
||||
int i;
|
||||
|
||||
/* this needs to be valid for index lookups later (callers need) */
|
||||
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
|
||||
|
||||
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
|
||||
BLI_kdtree_insert(MirrKdStore.tree, i, eve->co);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < totvert; i++, mvert++) {
|
||||
BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_kdtree_balance(MirrKdStore.tree);
|
||||
}
|
||||
else if (mode == 'e') { /* end table */
|
||||
if (MirrKdStore.tree) {
|
||||
BLI_kdtree_free(MirrKdStore.tree);
|
||||
MirrKdStore.tree = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Mesh Mirror (Topology) */
|
||||
|
|
Loading…
Reference in New Issue