2011-10-24 23:32:24 +00:00
|
|
|
/*
|
2009-03-02 02:21:18 +00:00
|
|
|
* ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2004 by Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): Joseph Eagar
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
Created a printf-style method of calling operators. I did this to cut down on duplicated
code, and also because calling operators was such a pain. The basic form of the format
is "opname %[code]", where each % matches to an argument.
The codes are fairly simple:
d - int
i - int
f - float
h[v/e/f] - all verts/edges/faces with a certain header flag.
f[v/e/f] - all verts/edges/faces with a certain flag.
For example:
EDBM_CallOpf(em, op, "dissolveverts %hv", BM_SELECT)
will call the dissolve verts operator.
The relevent functions are:
//calls a bmesh operator, doing necassary conversions and error reporting.
int EDBM_CallOpf(EditMesh *em, struct wmOperator *op, char *fmt, ...);
//execute an operator
int BMO_CallOpf(BMesh *bm, char *fmt, ...);
//initializes but doesn't execute an op.
int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...);
//vlist version of above.
int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist);
Note this system is dependant on getting the slot codes from the argument
order. I'd like to make it better, possibly pass in slot names, but that'd
mean actually giving the slots names (which I can do, but wanted to discuss with
Briggs and others what I have now first).
2009-03-02 04:08:24 +00:00
|
|
|
#include <stdarg.h>
|
2009-03-02 02:21:18 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <float.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "PIL_time.h"
|
|
|
|
|
|
|
|
#include "BLO_sys_types.h" // for intptr_t support
|
|
|
|
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_material_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "DNA_key_types.h"
|
|
|
|
|
|
|
|
#include "RNA_types.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
#include "RNA_access.h"
|
|
|
|
|
2011-05-09 04:06:48 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
#include "BLI_blenlib.h"
|
2009-11-23 14:41:22 +00:00
|
|
|
#include "BLI_math.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
#include "BLI_editVert.h"
|
|
|
|
#include "BLI_rand.h"
|
|
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "BLI_linklist.h"
|
|
|
|
#include "BLI_heap.h"
|
2009-09-17 23:05:33 +00:00
|
|
|
#include "BLI_array.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_customdata.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_library.h"
|
2009-11-06 12:59:58 +00:00
|
|
|
#include "BKE_key.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_object.h"
|
|
|
|
#include "BKE_bmesh.h"
|
|
|
|
#include "BKE_report.h"
|
2009-05-16 16:18:08 +00:00
|
|
|
#include "BKE_tessmesh.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
|
2010-03-11 05:30:01 +00:00
|
|
|
#include "bmesh.h"
|
|
|
|
|
2009-03-02 02:21:18 +00:00
|
|
|
#include "BIF_gl.h"
|
|
|
|
#include "BIF_glutil.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "ED_mesh.h"
|
|
|
|
#include "ED_view3d.h"
|
|
|
|
#include "ED_util.h"
|
|
|
|
#include "ED_screen.h"
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
|
|
|
|
2010-03-11 05:30:01 +00:00
|
|
|
#include "editbmesh_bvh.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
#include "mesh_intern.h"
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
void EDBM_RecalcNormals(BMEditMesh *em)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2009-05-18 14:55:34 +00:00
|
|
|
BM_Compute_Normals(em->bm);
|
|
|
|
}
|
|
|
|
|
2011-11-08 00:20:50 +00:00
|
|
|
void EDBM_ClearMesh(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
/*clear bmesh*/
|
|
|
|
BM_Clear_Mesh(em->bm);
|
|
|
|
|
|
|
|
/*free derived meshes*/
|
|
|
|
if (em->derivedCage) {
|
|
|
|
em->derivedCage->needsFree = 1;
|
|
|
|
em->derivedCage->release(em->derivedCage);
|
|
|
|
}
|
|
|
|
if (em->derivedFinal && em->derivedFinal != em->derivedCage) {
|
|
|
|
em->derivedFinal->needsFree = 1;
|
|
|
|
em->derivedFinal->release(em->derivedFinal);
|
|
|
|
}
|
|
|
|
|
|
|
|
em->derivedCage = em->derivedFinal = NULL;
|
|
|
|
|
|
|
|
/*free tesselation data*/
|
|
|
|
em->tottri = 0;
|
|
|
|
if (em->looptris)
|
|
|
|
MEM_freeN(em->looptris);
|
|
|
|
}
|
|
|
|
|
2009-05-18 14:55:34 +00:00
|
|
|
void EDBM_stats_update(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
BMIter iter;
|
|
|
|
BMHeader *ele;
|
2011-12-07 20:55:28 +00:00
|
|
|
const char itypes[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
|
2009-05-18 14:55:34 +00:00
|
|
|
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++) {
|
2011-12-07 20:55:28 +00:00
|
|
|
ele = BMIter_New(&iter, em->bm, itypes[i], NULL);
|
2009-05-18 14:55:34 +00:00
|
|
|
for ( ; ele; ele=BMIter_Step(&iter)) {
|
|
|
|
if (BM_TestHFlag(ele, BM_SELECT)) {
|
2011-11-16 17:09:41 +00:00
|
|
|
(*tots[i])++;
|
2009-05-18 14:55:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2011-02-27 06:19:40 +00:00
|
|
|
int EDBM_InitOpf(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
|
2009-05-28 04:41:02 +00:00
|
|
|
{
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
va_list list;
|
|
|
|
|
|
|
|
va_start(list, fmt);
|
|
|
|
|
|
|
|
if (!BMO_VInitOpf(bm, bmop, fmt, list)) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR,
|
|
|
|
"Parse error in EDBM_CallOpf");
|
|
|
|
va_end(list);
|
|
|
|
return 0;
|
|
|
|
}
|
2009-09-09 06:28:58 +00:00
|
|
|
|
|
|
|
if (!em->emcopy)
|
|
|
|
em->emcopy = BMEdit_Copy(em);
|
|
|
|
em->emcopyusers++;
|
2009-06-18 07:11:55 +00:00
|
|
|
|
2009-05-28 04:41:02 +00:00
|
|
|
va_end(list);
|
2009-11-06 12:59:58 +00:00
|
|
|
|
|
|
|
return 1;
|
2009-05-28 04:41:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*returns 0 on error, 1 on success. executes and finishes a bmesh operator*/
|
2011-11-07 09:02:10 +00:00
|
|
|
int EDBM_FinishOp(BMEditMesh *em, BMOperator *bmop, wmOperator *op, int report)
|
|
|
|
{
|
2011-05-07 02:48:14 +00:00
|
|
|
const char *errmsg;
|
2009-05-28 04:41:02 +00:00
|
|
|
|
|
|
|
BMO_Finish_Op(em->bm, bmop);
|
|
|
|
|
|
|
|
if (BMO_GetError(em->bm, &errmsg, NULL)) {
|
2009-06-18 07:11:55 +00:00
|
|
|
BMEditMesh *emcopy = em->emcopy;
|
2009-05-28 04:41:02 +00:00
|
|
|
|
|
|
|
if (report) BKE_report(op->reports, RPT_ERROR, errmsg);
|
2009-06-18 07:11:55 +00:00
|
|
|
|
|
|
|
BMEdit_Free(em);
|
|
|
|
*em = *emcopy;
|
2011-09-16 14:28:23 +00:00
|
|
|
BMEdit_RecalcTesselation(em);
|
2009-06-18 07:15:17 +00:00
|
|
|
|
|
|
|
MEM_freeN(emcopy);
|
2009-09-09 06:28:58 +00:00
|
|
|
em->emcopyusers = 0;
|
|
|
|
em->emcopy = NULL;
|
2009-05-28 04:41:02 +00:00
|
|
|
return 0;
|
2009-06-18 07:11:55 +00:00
|
|
|
} else {
|
2009-09-09 06:28:58 +00:00
|
|
|
em->emcopyusers--;
|
|
|
|
if (em->emcopyusers < 0) {
|
|
|
|
printf("warning: em->emcopyusers was less then zero.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (em->emcopyusers <= 0) {
|
|
|
|
BMEdit_Free(em->emcopy);
|
|
|
|
MEM_freeN(em->emcopy);
|
|
|
|
em->emcopy = NULL;
|
|
|
|
}
|
2009-05-28 04:41:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-02-27 06:19:40 +00:00
|
|
|
int EDBM_CallOpf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
|
Created a printf-style method of calling operators. I did this to cut down on duplicated
code, and also because calling operators was such a pain. The basic form of the format
is "opname %[code]", where each % matches to an argument.
The codes are fairly simple:
d - int
i - int
f - float
h[v/e/f] - all verts/edges/faces with a certain header flag.
f[v/e/f] - all verts/edges/faces with a certain flag.
For example:
EDBM_CallOpf(em, op, "dissolveverts %hv", BM_SELECT)
will call the dissolve verts operator.
The relevent functions are:
//calls a bmesh operator, doing necassary conversions and error reporting.
int EDBM_CallOpf(EditMesh *em, struct wmOperator *op, char *fmt, ...);
//execute an operator
int BMO_CallOpf(BMesh *bm, char *fmt, ...);
//initializes but doesn't execute an op.
int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...);
//vlist version of above.
int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist);
Note this system is dependant on getting the slot codes from the argument
order. I'd like to make it better, possibly pass in slot names, but that'd
mean actually giving the slots names (which I can do, but wanted to discuss with
Briggs and others what I have now first).
2009-03-02 04:08:24 +00:00
|
|
|
{
|
2009-05-19 00:33:54 +00:00
|
|
|
BMesh *bm = em->bm;
|
Created a printf-style method of calling operators. I did this to cut down on duplicated
code, and also because calling operators was such a pain. The basic form of the format
is "opname %[code]", where each % matches to an argument.
The codes are fairly simple:
d - int
i - int
f - float
h[v/e/f] - all verts/edges/faces with a certain header flag.
f[v/e/f] - all verts/edges/faces with a certain flag.
For example:
EDBM_CallOpf(em, op, "dissolveverts %hv", BM_SELECT)
will call the dissolve verts operator.
The relevent functions are:
//calls a bmesh operator, doing necassary conversions and error reporting.
int EDBM_CallOpf(EditMesh *em, struct wmOperator *op, char *fmt, ...);
//execute an operator
int BMO_CallOpf(BMesh *bm, char *fmt, ...);
//initializes but doesn't execute an op.
int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...);
//vlist version of above.
int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist);
Note this system is dependant on getting the slot codes from the argument
order. I'd like to make it better, possibly pass in slot names, but that'd
mean actually giving the slots names (which I can do, but wanted to discuss with
Briggs and others what I have now first).
2009-03-02 04:08:24 +00:00
|
|
|
BMOperator bmop;
|
|
|
|
va_list list;
|
|
|
|
|
|
|
|
va_start(list, fmt);
|
|
|
|
|
|
|
|
if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR,
|
|
|
|
"Parse error in EDBM_CallOpf");
|
|
|
|
va_end(list);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-09 06:28:58 +00:00
|
|
|
if (!em->emcopy)
|
|
|
|
em->emcopy = BMEdit_Copy(em);
|
|
|
|
em->emcopyusers++;
|
2009-06-18 07:11:55 +00:00
|
|
|
|
Created a printf-style method of calling operators. I did this to cut down on duplicated
code, and also because calling operators was such a pain. The basic form of the format
is "opname %[code]", where each % matches to an argument.
The codes are fairly simple:
d - int
i - int
f - float
h[v/e/f] - all verts/edges/faces with a certain header flag.
f[v/e/f] - all verts/edges/faces with a certain flag.
For example:
EDBM_CallOpf(em, op, "dissolveverts %hv", BM_SELECT)
will call the dissolve verts operator.
The relevent functions are:
//calls a bmesh operator, doing necassary conversions and error reporting.
int EDBM_CallOpf(EditMesh *em, struct wmOperator *op, char *fmt, ...);
//execute an operator
int BMO_CallOpf(BMesh *bm, char *fmt, ...);
//initializes but doesn't execute an op.
int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...);
//vlist version of above.
int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist);
Note this system is dependant on getting the slot codes from the argument
order. I'd like to make it better, possibly pass in slot names, but that'd
mean actually giving the slots names (which I can do, but wanted to discuss with
Briggs and others what I have now first).
2009-03-02 04:08:24 +00:00
|
|
|
BMO_Exec_Op(bm, &bmop);
|
|
|
|
|
|
|
|
va_end(list);
|
2009-06-18 07:11:55 +00:00
|
|
|
return EDBM_FinishOp(em, &bmop, op, 1);
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
}
|
|
|
|
|
2011-02-27 06:19:40 +00:00
|
|
|
int EDBM_CallAndSelectOpf(BMEditMesh *em, wmOperator *op, const char *selectslot, const char *fmt, ...)
|
2010-01-28 00:45:30 +00:00
|
|
|
{
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
BMOperator bmop;
|
|
|
|
va_list list;
|
|
|
|
|
|
|
|
va_start(list, fmt);
|
|
|
|
|
|
|
|
if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR,
|
|
|
|
"Parse error in EDBM_CallOpf");
|
|
|
|
va_end(list);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!em->emcopy)
|
|
|
|
em->emcopy = BMEdit_Copy(em);
|
|
|
|
em->emcopyusers++;
|
|
|
|
|
|
|
|
BMO_Exec_Op(bm, &bmop);
|
|
|
|
BMO_HeaderFlag_Buffer(em->bm, &bmop, selectslot, BM_SELECT, BM_ALL);
|
|
|
|
|
|
|
|
va_end(list);
|
|
|
|
return EDBM_FinishOp(em, &bmop, op, 1);
|
|
|
|
}
|
|
|
|
|
2011-02-27 06:19:40 +00:00
|
|
|
int EDBM_CallOpfSilent(BMEditMesh *em, const char *fmt, ...)
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
{
|
2009-05-19 00:33:54 +00:00
|
|
|
BMesh *bm = em->bm;
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
BMOperator bmop;
|
|
|
|
va_list list;
|
|
|
|
|
|
|
|
va_start(list, fmt);
|
|
|
|
|
|
|
|
if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
|
|
|
|
va_end(list);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-09 06:28:58 +00:00
|
|
|
if (!em->emcopy)
|
|
|
|
em->emcopy = BMEdit_Copy(em);
|
|
|
|
em->emcopyusers++;
|
2009-06-18 07:11:55 +00:00
|
|
|
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
BMO_Exec_Op(bm, &bmop);
|
|
|
|
|
|
|
|
va_end(list);
|
2009-06-18 07:11:55 +00:00
|
|
|
return EDBM_FinishOp(em, &bmop, NULL, 0);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2011-10-15 14:47:37 +00:00
|
|
|
void EDBM_selectmode_to_scene(bContext *C)
|
2010-03-09 04:32:40 +00:00
|
|
|
{
|
2011-10-15 14:47:37 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
2010-03-09 04:32:40 +00:00
|
|
|
BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
|
|
|
|
|
|
|
|
if (!em)
|
|
|
|
return;
|
|
|
|
|
|
|
|
scene->toolsettings->selectmode = em->selectmode;
|
2011-10-15 14:47:37 +00:00
|
|
|
|
|
|
|
/* Request redraw of header buttons (to show new select mode) */
|
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, scene);
|
2010-03-09 04:32:40 +00:00
|
|
|
}
|
|
|
|
|
2011-05-07 02:48:14 +00:00
|
|
|
void EDBM_MakeEditBMesh(ToolSettings *ts, Scene *UNUSED(scene), Object *ob)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
|
|
|
Mesh *me = ob->data;
|
|
|
|
BMesh *bm;
|
|
|
|
|
2009-05-26 04:17:47 +00:00
|
|
|
if (!me->mpoly && me->totface) {
|
2011-09-24 12:13:13 +00:00
|
|
|
fprintf(stderr, "%s: bmesh conversion issue! may lose lots of geometry! (bmesh internal error)\n", __func__);
|
2010-01-28 00:45:30 +00:00
|
|
|
|
|
|
|
/*BMESH_TODO need to write smarter code here*/
|
2011-09-12 02:23:30 +00:00
|
|
|
bm = BKE_mesh_to_bmesh(me, ob);
|
2009-05-26 04:17:47 +00:00
|
|
|
} else {
|
2011-09-12 02:23:30 +00:00
|
|
|
bm = BKE_mesh_to_bmesh(me, ob);
|
2009-05-26 04:17:47 +00:00
|
|
|
}
|
2009-05-16 16:18:08 +00:00
|
|
|
|
2011-10-30 02:15:32 +00:00
|
|
|
if (me->edit_btmesh) {
|
|
|
|
/* this happens when switching shape keys */
|
|
|
|
BMEdit_Free(me->edit_btmesh);
|
|
|
|
MEM_freeN(me->edit_btmesh);
|
|
|
|
}
|
|
|
|
|
2009-05-26 04:17:47 +00:00
|
|
|
me->edit_btmesh = BMEdit_Create(bm);
|
2011-10-28 08:09:34 +00:00
|
|
|
me->edit_btmesh->selectmode= me->edit_btmesh->bm->selectmode= ts->selectmode;
|
2009-11-02 06:33:16 +00:00
|
|
|
me->edit_btmesh->me = me;
|
|
|
|
me->edit_btmesh->ob = ob;
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EDBM_LoadEditBMesh(Scene *scene, Object *ob)
|
|
|
|
{
|
|
|
|
Mesh *me = ob->data;
|
2009-05-26 04:17:47 +00:00
|
|
|
BMesh *bm = me->edit_btmesh->bm;
|
|
|
|
|
2011-09-12 02:23:30 +00:00
|
|
|
BMO_CallOpf(bm, "object_load_bmesh scene=%p object=%p", scene, ob);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
void EDBM_FreeEditBMesh(BMEditMesh *tm)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2009-05-26 04:17:47 +00:00
|
|
|
BMEdit_Free(tm);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
void EDBM_init_index_arrays(BMEditMesh *tm, int forvert, int foredge, int forface)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2009-05-18 15:53:30 +00:00
|
|
|
EDBM_free_index_arrays(tm);
|
|
|
|
|
2009-05-16 16:18:08 +00:00
|
|
|
if (forvert) {
|
|
|
|
BMIter iter;
|
|
|
|
BMVert *ele;
|
|
|
|
int i=0;
|
|
|
|
|
|
|
|
tm->vert_index = MEM_mallocN(sizeof(void**)*tm->bm->totvert, "tm->vert_index");
|
|
|
|
|
|
|
|
ele = BMIter_New(&iter, tm->bm, BM_VERTS_OF_MESH, NULL);
|
|
|
|
for ( ; ele; ele=BMIter_Step(&iter)) {
|
|
|
|
tm->vert_index[i++] = ele;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foredge) {
|
|
|
|
BMIter iter;
|
2009-05-18 08:46:04 +00:00
|
|
|
BMEdge *ele;
|
2009-05-16 16:18:08 +00:00
|
|
|
int i=0;
|
|
|
|
|
|
|
|
tm->edge_index = MEM_mallocN(sizeof(void**)*tm->bm->totedge, "tm->edge_index");
|
|
|
|
|
|
|
|
ele = BMIter_New(&iter, tm->bm, BM_EDGES_OF_MESH, NULL);
|
|
|
|
for ( ; ele; ele=BMIter_Step(&iter)) {
|
|
|
|
tm->edge_index[i++] = ele;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (forface) {
|
|
|
|
BMIter iter;
|
2009-05-18 08:46:04 +00:00
|
|
|
BMFace *ele;
|
2009-05-16 16:18:08 +00:00
|
|
|
int i=0;
|
|
|
|
|
|
|
|
tm->face_index = MEM_mallocN(sizeof(void**)*tm->bm->totface, "tm->face_index");
|
|
|
|
|
|
|
|
ele = BMIter_New(&iter, tm->bm, BM_FACES_OF_MESH, NULL);
|
|
|
|
for ( ; ele; ele=BMIter_Step(&iter)) {
|
|
|
|
tm->face_index[i++] = ele;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
void EDBM_free_index_arrays(BMEditMesh *tm)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
|
|
|
if (tm->vert_index) {
|
|
|
|
MEM_freeN(tm->vert_index);
|
|
|
|
tm->vert_index = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tm->edge_index) {
|
|
|
|
MEM_freeN(tm->edge_index);
|
|
|
|
tm->edge_index = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tm->face_index) {
|
|
|
|
MEM_freeN(tm->face_index);
|
|
|
|
tm->face_index = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
BMVert *EDBM_get_vert_for_index(BMEditMesh *tm, int index)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2011-04-17 04:12:53 +00:00
|
|
|
return tm->vert_index && index < tm->bm->totvert ?tm->vert_index[index]:NULL;
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2011-04-17 04:12:53 +00:00
|
|
|
return tm->edge_index && index < tm->bm->totedge ?tm->edge_index[index]:NULL;
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
BMFace *EDBM_get_face_for_index(BMEditMesh *tm, int index)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2011-02-15 01:16:32 +00:00
|
|
|
return (tm->face_index && index<tm->bm->totface && index>=0) ? tm->face_index[index] : NULL;
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2009-08-05 02:34:54 +00:00
|
|
|
void EDBM_select_flush(BMEditMesh *em, int selectmode)
|
|
|
|
{
|
|
|
|
em->bm->selectmode = selectmode;
|
|
|
|
BM_SelectMode_Flush(em->bm);
|
|
|
|
em->bm->selectmode = em->selectmode;
|
|
|
|
}
|
|
|
|
|
2009-09-16 17:43:09 +00:00
|
|
|
/*BMESH_TODO*/
|
2011-05-07 02:48:14 +00:00
|
|
|
void EDBM_deselect_flush(BMEditMesh *UNUSED(em))
|
2009-09-16 17:43:09 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
void EDBM_selectmode_flush(BMEditMesh *em)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2009-05-18 10:29:37 +00:00
|
|
|
em->bm->selectmode = em->selectmode;
|
|
|
|
BM_SelectMode_Flush(em->bm);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
2009-08-06 05:06:55 +00:00
|
|
|
/*EDBM_select_[more/less] are api functions, I think the uv editor
|
|
|
|
uses them? though the select more/less ops themselves do not.*/
|
2011-05-11 02:14:43 +00:00
|
|
|
static void EDBM_select_more(BMEditMesh *em)
|
2009-08-06 05:06:55 +00:00
|
|
|
{
|
|
|
|
BMOperator bmop;
|
|
|
|
int usefaces = em->selectmode > SCE_SELECT_EDGE;
|
|
|
|
|
|
|
|
BMO_InitOpf(em->bm, &bmop,
|
|
|
|
"regionextend geom=%hvef constrict=%d usefaces=%d",
|
|
|
|
BM_SELECT, 0, usefaces);
|
|
|
|
BMO_Exec_Op(em->bm, &bmop);
|
Brought Extrude all the way back. The contextual menu works,
as does only edges and individual faces extrude (individual vert
extrude already did).
Note that I need to port this, after we all figure out how to handle
operators with variable transform follow-ons.
I also implemented the merge->collapse function, which is currently
accessable under ctrl->v, Bmesh Test Operator. I still need to
implement the other merge modes, and properly hook everything into
the merge menu tool, which I plan on doing soon (tomorrow hopefully).
The cool thing about the collapse tool, is not only does it handle (all)
UV layers, it handles vcols as well. To do this, I had to add a few math
functions to the customdata API, which seem to be working well.
2009-08-11 07:49:35 +00:00
|
|
|
BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
|
2009-08-06 05:06:55 +00:00
|
|
|
BMO_Finish_Op(em->bm, &bmop);
|
|
|
|
|
|
|
|
EDBM_selectmode_flush(em);
|
|
|
|
}
|
|
|
|
|
2011-05-11 02:14:43 +00:00
|
|
|
static void EDBM_select_less(BMEditMesh *em)
|
2009-08-06 05:06:55 +00:00
|
|
|
{
|
|
|
|
BMOperator bmop;
|
|
|
|
int usefaces = em->selectmode > SCE_SELECT_EDGE;
|
|
|
|
|
|
|
|
BMO_InitOpf(em->bm, &bmop,
|
|
|
|
"regionextend geom=%hvef constrict=%d usefaces=%d",
|
|
|
|
BM_SELECT, 0, usefaces);
|
|
|
|
BMO_Exec_Op(em->bm, &bmop);
|
Brought Extrude all the way back. The contextual menu works,
as does only edges and individual faces extrude (individual vert
extrude already did).
Note that I need to port this, after we all figure out how to handle
operators with variable transform follow-ons.
I also implemented the merge->collapse function, which is currently
accessable under ctrl->v, Bmesh Test Operator. I still need to
implement the other merge modes, and properly hook everything into
the merge menu tool, which I plan on doing soon (tomorrow hopefully).
The cool thing about the collapse tool, is not only does it handle (all)
UV layers, it handles vcols as well. To do this, I had to add a few math
functions to the customdata API, which seem to be working well.
2009-08-11 07:49:35 +00:00
|
|
|
BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
|
2009-08-06 05:06:55 +00:00
|
|
|
BMO_Finish_Op(em->bm, &bmop);
|
|
|
|
|
|
|
|
EDBM_selectmode_flush(em);
|
|
|
|
}
|
2009-05-16 16:18:08 +00:00
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2009-07-17 10:54:00 +00:00
|
|
|
BMEditSelection *ese_last = em->bm->selected.last;
|
2011-09-13 13:41:20 +00:00
|
|
|
BMFace *efa = BM_get_actFace(em->bm, 0);
|
2009-05-16 16:18:08 +00:00
|
|
|
|
|
|
|
ese->next = ese->prev = NULL;
|
|
|
|
|
|
|
|
if (ese_last) {
|
2011-11-01 14:36:23 +00:00
|
|
|
if (ese_last->htype == BM_FACE) { /* if there is an active face, use it over the last selected face */
|
2009-05-16 16:18:08 +00:00
|
|
|
if (efa) {
|
|
|
|
ese->data = (void *)efa;
|
|
|
|
} else {
|
|
|
|
ese->data = ese_last->data;
|
|
|
|
}
|
2011-11-01 14:36:23 +00:00
|
|
|
ese->htype = BM_FACE;
|
|
|
|
}
|
|
|
|
else {
|
2009-05-16 16:18:08 +00:00
|
|
|
ese->data = ese_last->data;
|
2011-11-01 14:36:23 +00:00
|
|
|
ese->htype = ese_last->htype;
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
2011-11-01 14:36:23 +00:00
|
|
|
}
|
|
|
|
else if (efa) { /* no */
|
|
|
|
ese->data= (void *)efa;
|
|
|
|
ese->htype= BM_FACE;
|
|
|
|
}
|
|
|
|
else {
|
2009-05-16 16:18:08 +00:00
|
|
|
ese->data = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-11-01 14:36:23 +00:00
|
|
|
void EDBM_clear_flag_all(BMEditMesh *em, const char hflag)
|
2009-05-18 08:46:04 +00:00
|
|
|
{
|
2011-11-01 14:36:23 +00:00
|
|
|
int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
|
2009-05-18 08:46:04 +00:00
|
|
|
BMIter iter;
|
|
|
|
BMHeader *ele;
|
2011-11-01 14:36:23 +00:00
|
|
|
int i;
|
2009-05-18 08:46:04 +00:00
|
|
|
|
2011-11-01 14:36:23 +00:00
|
|
|
if (hflag & BM_SELECT)
|
2009-09-04 01:28:06 +00:00
|
|
|
BM_clear_selection_history(em->bm);
|
|
|
|
|
2009-05-18 08:46:04 +00:00
|
|
|
for (i=0; i<3; i++) {
|
2011-11-01 14:36:23 +00:00
|
|
|
BM_ITER(ele, &iter, em->bm, types[i], NULL) {
|
|
|
|
if (hflag & BM_SELECT) BM_Select(em->bm, ele, 0);
|
|
|
|
BM_ClearHFlag(ele, hflag);
|
2009-05-18 08:46:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-01 14:36:23 +00:00
|
|
|
void EDBM_set_flag_all(BMEditMesh *em, const char hflag)
|
2009-05-18 10:29:37 +00:00
|
|
|
{
|
2011-12-07 20:55:28 +00:00
|
|
|
const char itypes[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
|
2009-05-18 10:29:37 +00:00
|
|
|
BMIter iter;
|
2009-05-28 04:41:02 +00:00
|
|
|
BMHeader *ele;
|
2011-11-01 14:36:23 +00:00
|
|
|
int i;
|
2009-05-16 16:18:08 +00:00
|
|
|
|
2009-05-28 04:41:02 +00:00
|
|
|
for (i=0; i<3; i++) {
|
2011-12-07 20:55:28 +00:00
|
|
|
ele= BMIter_New(&iter, em->bm, itypes[i], NULL);
|
2009-05-28 04:41:02 +00:00
|
|
|
for ( ; ele; ele=BMIter_Step(&iter)) {
|
2011-11-01 14:36:23 +00:00
|
|
|
if (hflag & BM_SELECT) {
|
2011-09-30 04:27:12 +00:00
|
|
|
BM_Select(em->bm, ele, 1);
|
|
|
|
}
|
2011-10-25 16:17:26 +00:00
|
|
|
else {
|
2011-11-01 14:36:23 +00:00
|
|
|
BM_SetHFlag(ele, hflag);
|
2011-10-25 16:17:26 +00:00
|
|
|
}
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-05-18 14:55:34 +00:00
|
|
|
|
|
|
|
/**************-------------- Undo ------------*****************/
|
|
|
|
|
|
|
|
/* for callbacks */
|
|
|
|
|
|
|
|
static void *getEditMesh(bContext *C)
|
|
|
|
{
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
if(obedit && obedit->type==OB_MESH) {
|
|
|
|
Mesh *me= obedit->data;
|
|
|
|
return me->edit_btmesh;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-09-10 06:08:52 +00:00
|
|
|
typedef struct undomesh {
|
|
|
|
Mesh me;
|
|
|
|
int selectmode;
|
2011-03-29 05:48:18 +00:00
|
|
|
char obname[64];
|
2009-09-10 06:08:52 +00:00
|
|
|
} undomesh;
|
|
|
|
|
2009-05-18 14:55:34 +00:00
|
|
|
/*undo simply makes copies of a bmesh*/
|
2009-11-02 16:01:24 +00:00
|
|
|
static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
|
2009-05-18 14:55:34 +00:00
|
|
|
{
|
2009-09-10 06:08:52 +00:00
|
|
|
BMEditMesh *em = emv;
|
2009-11-02 16:01:24 +00:00
|
|
|
Mesh *obme = obdata;
|
2011-03-29 05:48:18 +00:00
|
|
|
|
2009-09-10 06:08:52 +00:00
|
|
|
undomesh *me = MEM_callocN(sizeof(undomesh), "undo Mesh");
|
2011-03-29 05:48:18 +00:00
|
|
|
strcpy(me->obname, em->bm->ob->id.name+2);
|
2009-11-02 06:33:16 +00:00
|
|
|
|
|
|
|
/*make sure shape keys work*/
|
2009-11-02 16:01:24 +00:00
|
|
|
me->me.key = obme->key ? copy_key_nolib(obme->key) : NULL;
|
2009-09-10 06:08:52 +00:00
|
|
|
|
2011-12-11 05:05:37 +00:00
|
|
|
#ifdef BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND
|
|
|
|
|
2009-05-18 14:55:34 +00:00
|
|
|
/*we recalc the tesselation here, to avoid seeding calls to
|
2009-05-26 04:17:47 +00:00
|
|
|
BMEdit_RecalcTesselation throughout the code.*/
|
2009-09-10 06:08:52 +00:00
|
|
|
BMEdit_RecalcTesselation(em);
|
|
|
|
|
2011-12-11 05:05:37 +00:00
|
|
|
#endif
|
|
|
|
|
2011-09-12 02:23:30 +00:00
|
|
|
BMO_CallOpf(em->bm, "bmesh_to_mesh mesh=%p notesselation=%i", me, 1);
|
2009-09-10 06:08:52 +00:00
|
|
|
me->selectmode = em->selectmode;
|
2009-05-18 14:55:34 +00:00
|
|
|
|
2009-09-10 06:08:52 +00:00
|
|
|
return me;
|
2009-05-18 14:55:34 +00:00
|
|
|
}
|
|
|
|
|
2011-05-07 02:48:14 +00:00
|
|
|
static void undoMesh_to_editbtMesh(void *umv, void *emv, void *UNUSED(obdata))
|
2009-05-18 14:55:34 +00:00
|
|
|
{
|
2009-09-10 06:08:52 +00:00
|
|
|
BMEditMesh *em = emv, *em2;
|
2011-03-29 05:48:18 +00:00
|
|
|
Object *ob;
|
2009-09-10 06:08:52 +00:00
|
|
|
undomesh *me = umv;
|
|
|
|
BMesh *bm;
|
|
|
|
int allocsize[4] = {512, 512, 2048, 512};
|
2011-03-29 05:48:18 +00:00
|
|
|
|
2011-04-13 00:35:48 +00:00
|
|
|
ob = (Object*)find_id("OB", me->obname);
|
2011-03-29 05:48:18 +00:00
|
|
|
ob->shapenr = em->bm->shapenr;
|
2009-11-02 16:01:24 +00:00
|
|
|
|
2009-09-10 06:08:52 +00:00
|
|
|
BMEdit_Free(em);
|
|
|
|
|
2011-03-29 05:48:18 +00:00
|
|
|
bm = BM_Make_Mesh(ob, allocsize);
|
2011-09-12 02:23:30 +00:00
|
|
|
BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 0);
|
2009-05-18 14:55:34 +00:00
|
|
|
|
2009-09-10 06:08:52 +00:00
|
|
|
em2 = BMEdit_Create(bm);
|
|
|
|
*em = *em2;
|
|
|
|
|
|
|
|
em->selectmode = me->selectmode;
|
2009-05-18 14:55:34 +00:00
|
|
|
|
2009-09-10 06:08:52 +00:00
|
|
|
MEM_freeN(em2);
|
2009-05-18 14:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void free_undo(void *umv)
|
|
|
|
{
|
2011-05-12 18:33:10 +00:00
|
|
|
if (((Mesh*)umv)->key)
|
|
|
|
{
|
|
|
|
free_key(((Mesh*)umv)->key);
|
|
|
|
MEM_freeN(((Mesh*)umv)->key);
|
|
|
|
}
|
|
|
|
|
2009-09-10 06:08:52 +00:00
|
|
|
free_mesh(umv, 0);
|
|
|
|
MEM_freeN(umv);
|
2009-05-18 14:55:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* and this is all the undo system needs to know */
|
2011-02-27 06:19:40 +00:00
|
|
|
void undo_push_mesh(bContext *C, const char *name)
|
2009-05-18 14:55:34 +00:00
|
|
|
{
|
|
|
|
undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
|
|
|
|
}
|
2009-07-21 08:39:58 +00:00
|
|
|
|
|
|
|
/*write comment here*/
|
|
|
|
UvVertMap *EDBM_make_uv_vert_map(BMEditMesh *em, int selected, int do_face_idx_array, float *limit)
|
|
|
|
{
|
|
|
|
BMVert *ev;
|
|
|
|
BMFace *efa;
|
|
|
|
BMLoop *l;
|
|
|
|
BMIter iter, liter;
|
|
|
|
/* vars from original func */
|
|
|
|
UvVertMap *vmap;
|
|
|
|
UvMapVert *buf;
|
2011-09-07 06:49:20 +00:00
|
|
|
/* MTexPoly *tf; */ /* UNUSED */
|
2009-07-21 08:39:58 +00:00
|
|
|
MLoopUV *luv;
|
|
|
|
unsigned int a;
|
|
|
|
int totverts, i, totuv;
|
|
|
|
|
|
|
|
if (do_face_idx_array)
|
|
|
|
EDBM_init_index_arrays(em, 0, 0, 1);
|
2011-11-01 12:51:38 +00:00
|
|
|
|
2011-11-16 12:38:40 +00:00
|
|
|
BM_ElemIndex_Ensure(em->bm, BM_VERT);
|
2009-07-21 08:39:58 +00:00
|
|
|
|
2011-11-16 12:38:40 +00:00
|
|
|
totverts= em->bm->totvert;
|
2009-07-21 08:39:58 +00:00
|
|
|
totuv = 0;
|
|
|
|
|
|
|
|
/* generate UvMapVert array */
|
|
|
|
BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
|
|
|
|
if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT)))
|
|
|
|
totuv += efa->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(totuv==0) {
|
|
|
|
if (do_face_idx_array)
|
|
|
|
EDBM_free_index_arrays(em);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap");
|
|
|
|
if (!vmap) {
|
|
|
|
if (do_face_idx_array)
|
|
|
|
EDBM_free_index_arrays(em);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*");
|
|
|
|
buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
|
|
|
|
|
|
|
|
if (!vmap->vert || !vmap->buf) {
|
|
|
|
free_uv_vert_map(vmap);
|
|
|
|
if (do_face_idx_array)
|
|
|
|
EDBM_free_index_arrays(em);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
a = 0;
|
|
|
|
BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
|
|
|
|
if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT))) {
|
|
|
|
i = 0;
|
|
|
|
BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
|
|
|
|
buf->tfindex= i;
|
|
|
|
buf->f= a;
|
|
|
|
buf->separate = 0;
|
|
|
|
|
2011-05-13 10:49:26 +00:00
|
|
|
buf->next= vmap->vert[BM_GetIndex(l->v)];
|
|
|
|
vmap->vert[BM_GetIndex(l->v)]= buf;
|
2009-07-21 08:39:58 +00:00
|
|
|
|
|
|
|
buf++;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
a++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sort individual uvs for each vert */
|
|
|
|
a = 0;
|
|
|
|
BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
|
|
|
UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
|
|
|
|
UvMapVert *iterv, *v, *lastv, *next;
|
|
|
|
float *uv, *uv2, uvdiff[2];
|
|
|
|
|
|
|
|
while(vlist) {
|
|
|
|
v= vlist;
|
|
|
|
vlist= vlist->next;
|
|
|
|
v->next= newvlist;
|
|
|
|
newvlist= v;
|
|
|
|
|
|
|
|
efa = EDBM_get_face_for_index(em, v->f);
|
2011-09-07 06:49:20 +00:00
|
|
|
/* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
|
2009-07-21 08:39:58 +00:00
|
|
|
|
|
|
|
l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
|
|
|
|
luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
|
|
|
|
uv = luv->uv;
|
|
|
|
|
|
|
|
lastv= NULL;
|
|
|
|
iterv= vlist;
|
|
|
|
|
|
|
|
while(iterv) {
|
|
|
|
next= iterv->next;
|
|
|
|
efa = EDBM_get_face_for_index(em, iterv->f);
|
2011-09-07 06:49:20 +00:00
|
|
|
/* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
|
2009-07-21 08:39:58 +00:00
|
|
|
|
|
|
|
l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
|
|
|
|
luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
|
|
|
|
uv2 = luv->uv;
|
|
|
|
|
2009-11-23 14:41:22 +00:00
|
|
|
sub_v2_v2v2(uvdiff, uv2, uv);
|
2009-07-21 08:39:58 +00:00
|
|
|
|
|
|
|
if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) {
|
|
|
|
if(lastv) lastv->next= next;
|
|
|
|
else vlist= next;
|
|
|
|
iterv->next= newvlist;
|
|
|
|
newvlist= iterv;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lastv=iterv;
|
|
|
|
|
|
|
|
iterv= next;
|
|
|
|
}
|
|
|
|
|
|
|
|
newvlist->separate = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vmap->vert[a]= newvlist;
|
|
|
|
a++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_face_idx_array)
|
|
|
|
EDBM_free_index_arrays(em);
|
|
|
|
|
|
|
|
return vmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UvMapVert *EDBM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
|
|
|
|
{
|
|
|
|
return vmap->vert[v];
|
|
|
|
}
|
|
|
|
|
|
|
|
void EDBM_free_uv_vert_map(UvVertMap *vmap)
|
|
|
|
{
|
|
|
|
if (vmap) {
|
|
|
|
if (vmap->vert) MEM_freeN(vmap->vert);
|
|
|
|
if (vmap->buf) MEM_freeN(vmap->buf);
|
|
|
|
MEM_freeN(vmap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* last_sel, use em->act_face otherwise get the last selected face in the editselections
|
|
|
|
* at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
|
|
|
|
MTexPoly *EDBM_get_active_mtexpoly(BMEditMesh *em, BMFace **act_efa, int sloppy)
|
|
|
|
{
|
|
|
|
BMFace *efa = NULL;
|
|
|
|
|
|
|
|
if(!EDBM_texFaceCheck(em))
|
|
|
|
return NULL;
|
|
|
|
|
2011-09-13 13:41:20 +00:00
|
|
|
efa = BM_get_actFace(em->bm, sloppy);
|
2009-07-21 08:39:58 +00:00
|
|
|
|
|
|
|
if (efa) {
|
|
|
|
if (act_efa) *act_efa = efa;
|
|
|
|
return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (act_efa) *act_efa= NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* can we edit UV's for this mesh?*/
|
|
|
|
int EDBM_texFaceCheck(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
/* some of these checks could be a touch overkill */
|
2010-01-28 00:45:30 +00:00
|
|
|
return em && em->bm->totface && CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) &&
|
2011-02-23 08:12:27 +00:00
|
|
|
CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
|
2009-07-21 11:48:58 +00:00
|
|
|
}
|
2009-08-28 10:17:31 +00:00
|
|
|
|
|
|
|
int EDBM_vertColorCheck(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
/* some of these checks could be a touch overkill */
|
|
|
|
return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
|
|
|
|
}
|
|
|
|
|
2011-12-20 22:01:11 +00:00
|
|
|
static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
|
|
|
|
{
|
|
|
|
intptr_t eve_i= index_lookup[index];
|
|
|
|
return (eve_i == -1) ? NULL : (BMVert *)eve_i;
|
|
|
|
}
|
|
|
|
|
2011-10-26 07:41:56 +00:00
|
|
|
/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
|
|
|
|
* preference */
|
|
|
|
#define BM_SEARCH_MAXDIST_MIRR 0.00002f
|
2011-10-28 06:23:12 +00:00
|
|
|
#define BM_CD_LAYER_ID "__mirror_index"
|
2011-11-01 05:43:35 +00:00
|
|
|
void EDBM_CacheMirrorVerts(BMEditMesh *em, const short use_select)
|
2010-03-11 05:30:01 +00:00
|
|
|
{
|
2011-10-25 16:17:26 +00:00
|
|
|
Mesh *me = em->me;
|
2010-03-11 05:30:01 +00:00
|
|
|
BMIter iter;
|
|
|
|
BMVert *v;
|
2011-11-16 17:09:41 +00:00
|
|
|
int li, topo = 0;
|
2011-10-25 16:17:26 +00:00
|
|
|
|
2011-12-20 22:01:11 +00:00
|
|
|
/* one or the other is used depending if topo is enabled */
|
|
|
|
BMBVHTree *tree= NULL;
|
|
|
|
MirrTopoStore_t mesh_topo_store= {NULL, -1, -1, -1};
|
|
|
|
|
2011-10-25 16:17:26 +00:00
|
|
|
if (me && (me->editflag & ME_EDIT_MIRROR_TOPO)) {
|
|
|
|
topo = 1;
|
|
|
|
}
|
2010-03-11 05:30:01 +00:00
|
|
|
|
|
|
|
if (!em->vert_index) {
|
|
|
|
EDBM_init_index_arrays(em, 1, 0, 0);
|
|
|
|
em->mirr_free_arrays = 1;
|
|
|
|
}
|
|
|
|
|
2011-10-28 06:23:12 +00:00
|
|
|
if (!CustomData_get_layer_named(&em->bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID)) {
|
|
|
|
BM_add_data_layer_named(em->bm, &em->bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID);
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
2011-10-28 06:23:12 +00:00
|
|
|
li= CustomData_get_named_layer_index(&em->bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID);
|
|
|
|
|
2010-03-11 05:30:01 +00:00
|
|
|
em->bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
|
|
|
|
|
2011-11-16 12:38:40 +00:00
|
|
|
BM_ElemIndex_Ensure(em->bm, BM_VERT);
|
2011-10-26 10:04:10 +00:00
|
|
|
|
2011-12-20 22:01:11 +00:00
|
|
|
if (topo) {
|
|
|
|
ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, TRUE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tree= BMBVH_NewBVH(em, 0, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2010-03-11 05:30:01 +00:00
|
|
|
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
|
|
|
BMVert *mirr;
|
|
|
|
int *idx = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, li);
|
|
|
|
float co[3] = {-v->co[0], v->co[1], v->co[2]};
|
|
|
|
|
|
|
|
//temporary for testing, check for selection
|
2011-11-01 05:43:35 +00:00
|
|
|
if (use_select && !BM_TestHFlag(v, BM_SELECT))
|
2010-03-11 05:30:01 +00:00
|
|
|
continue;
|
2011-12-20 22:01:11 +00:00
|
|
|
|
2011-10-25 16:17:26 +00:00
|
|
|
mirr = topo ?
|
2011-12-20 22:01:11 +00:00
|
|
|
/* BMBVH_FindClosestVertTopo(tree, co, BM_SEARCH_MAXDIST_MIRR, v) */
|
|
|
|
cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, BM_GetIndex(v)) :
|
2011-10-26 07:41:56 +00:00
|
|
|
BMBVH_FindClosestVert(tree, co, BM_SEARCH_MAXDIST_MIRR);
|
|
|
|
|
2010-03-11 05:30:01 +00:00
|
|
|
if (mirr && mirr != v) {
|
2011-05-13 10:49:26 +00:00
|
|
|
*idx = BM_GetIndex(mirr);
|
2010-03-11 05:30:01 +00:00
|
|
|
idx = CustomData_bmesh_get_layer_n(&em->bm->vdata,mirr->head.data, li);
|
2011-05-13 10:49:26 +00:00
|
|
|
*idx = BM_GetIndex(v);
|
2011-10-26 07:41:56 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
*idx = -1;
|
|
|
|
}
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
2011-12-20 22:01:11 +00:00
|
|
|
|
|
|
|
if (topo) {
|
|
|
|
ED_mesh_mirrtopo_free(&mesh_topo_store);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BMBVH_FreeBVH(tree);
|
|
|
|
}
|
2011-10-28 06:23:12 +00:00
|
|
|
|
|
|
|
em->mirror_cdlayer= li;
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v)
|
|
|
|
{
|
|
|
|
int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
|
2011-10-28 06:23:12 +00:00
|
|
|
|
|
|
|
BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
|
|
|
|
|
2010-03-11 05:30:01 +00:00
|
|
|
if (mirr && *mirr >=0 && *mirr < em->bm->totvert) {
|
|
|
|
if (!em->vert_index) {
|
|
|
|
printf("err: should only be called between "
|
|
|
|
"EDBM_CacheMirrorVerts and EDBM_EndMirrorCache");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return em->vert_index[*mirr];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-11-01 05:43:35 +00:00
|
|
|
void EDBM_ClearMirrorVert(BMEditMesh *em, BMVert *v)
|
|
|
|
{
|
|
|
|
int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
|
|
|
|
|
|
|
|
BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
|
|
|
|
|
|
|
|
if (mirr) {
|
|
|
|
*mirr= -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-11 05:30:01 +00:00
|
|
|
void EDBM_EndMirrorCache(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
if (em->mirr_free_arrays) {
|
|
|
|
MEM_freeN(em->vert_index);
|
|
|
|
em->vert_index = NULL;
|
|
|
|
}
|
2011-10-28 06:23:12 +00:00
|
|
|
|
|
|
|
em->mirror_cdlayer= -1;
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
2011-10-26 07:41:56 +00:00
|
|
|
|
|
|
|
void EDBM_ApplyMirrorCache(BMEditMesh *em, const int sel_from, const int sel_to)
|
|
|
|
{
|
|
|
|
BMIter iter;
|
|
|
|
BMVert *v;
|
|
|
|
|
|
|
|
BLI_assert(em->vert_index != NULL);
|
|
|
|
|
|
|
|
BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
|
|
|
|
if (BM_TestHFlag(v, BM_SELECT) == sel_from) {
|
|
|
|
BMVert *mirr= EDBM_GetMirrorVert(em, v);
|
|
|
|
if (mirr) {
|
|
|
|
if (BM_TestHFlag(mirr, BM_SELECT) == sel_to) {
|
|
|
|
copy_v3_v3(mirr->co, v->co);
|
|
|
|
mirr->co[0] *= -1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|