2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2004 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2009-03-02 02:21:18 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup edmesh
|
2012-03-24 00:20:36 +00:00
|
|
|
*/
|
|
|
|
|
|
2009-03-02 02:21:18 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_key_types.h"
|
2012-02-19 22:17:30 +00:00
|
|
|
#include "DNA_mesh_types.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
#include "BLI_array.hh"
|
2015-05-21 13:01:44 +10:00
|
|
|
#include "BLI_kdtree.h"
|
2014-11-10 13:48:27 +01:00
|
|
|
#include "BLI_listbase.h"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_matrix.h"
|
|
|
|
|
#include "BLI_math_vector.h"
|
2009-03-02 02:21:18 +00:00
|
|
|
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
|
|
|
|
#include "BKE_customdata.hh"
|
|
|
|
|
#include "BKE_editmesh.hh"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BKE_editmesh_bvh.h"
|
2024-01-23 15:18:09 -05:00
|
|
|
#include "BKE_layer.hh"
|
2023-08-02 22:14:18 +02:00
|
|
|
#include "BKE_mesh.hh"
|
|
|
|
|
#include "BKE_mesh_mapping.hh"
|
2024-02-10 18:34:29 +01:00
|
|
|
#include "BKE_report.hh"
|
2009-03-02 02:21:18 +00:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
2017-06-08 10:14:53 +02:00
|
|
|
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "WM_api.hh"
|
|
|
|
|
#include "WM_types.hh"
|
2009-03-02 02:21:18 +00:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_mesh.hh"
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "ED_screen.hh"
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_transform_snap_object_context.hh"
|
|
|
|
|
#include "ED_uvedit.hh"
|
|
|
|
|
#include "ED_view3d.hh"
|
2009-03-02 02:21:18 +00:00
|
|
|
|
2024-01-24 11:30:39 -05:00
|
|
|
#include "mesh_intern.hh" /* own include */
|
2012-03-27 04:46:52 +00:00
|
|
|
|
2024-01-24 18:18:14 +01:00
|
|
|
using blender::Vector;
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \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 */
|
2012-05-16 14:30:41 +00:00
|
|
|
|
|
|
|
|
BMBackup EDBM_redo_state_store(BMEditMesh *em)
|
|
|
|
|
{
|
|
|
|
|
BMBackup backup;
|
|
|
|
|
backup.bmcopy = BM_mesh_copy(em->bm);
|
|
|
|
|
return backup;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-14 12:08:21 +11:00
|
|
|
void EDBM_redo_state_restore(BMBackup *backup, BMEditMesh *em, bool recalc_looptris)
|
2012-05-16 14:30:41 +00:00
|
|
|
{
|
|
|
|
|
BM_mesh_data_free(em->bm);
|
2023-01-25 12:56:05 -06:00
|
|
|
BMesh *tmpbm = BM_mesh_copy(backup->bmcopy);
|
2012-05-16 14:30:41 +00:00
|
|
|
*em->bm = *tmpbm;
|
|
|
|
|
MEM_freeN(tmpbm);
|
2023-06-13 23:05:45 +02:00
|
|
|
tmpbm = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-14 12:08:21 +11:00
|
|
|
if (recalc_looptris) {
|
|
|
|
|
BKE_editmesh_looptris_calc(em);
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2012-05-16 14:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-14 12:08:21 +11:00
|
|
|
void EDBM_redo_state_restore_and_free(BMBackup *backup, BMEditMesh *em, bool recalc_looptris)
|
2012-05-16 14:30:41 +00:00
|
|
|
{
|
2021-07-05 23:37:11 +10:00
|
|
|
BM_mesh_data_free(em->bm);
|
|
|
|
|
*em->bm = *backup->bmcopy;
|
|
|
|
|
MEM_freeN(backup->bmcopy);
|
2023-06-13 23:05:45 +02:00
|
|
|
backup->bmcopy = nullptr;
|
2023-12-14 12:08:21 +11:00
|
|
|
if (recalc_looptris) {
|
|
|
|
|
BKE_editmesh_looptris_calc(em);
|
2012-05-16 14:30:41 +00:00
|
|
|
}
|
2021-07-05 23:37:11 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-05 23:37:11 +10:00
|
|
|
void EDBM_redo_state_free(BMBackup *backup)
|
|
|
|
|
{
|
2018-03-16 20:46:14 +11:00
|
|
|
if (backup->bmcopy) {
|
2021-07-05 23:37:11 +10:00
|
|
|
BM_mesh_data_free(backup->bmcopy);
|
2012-05-16 14:30:41 +00:00
|
|
|
MEM_freeN(backup->bmcopy);
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2011-11-08 00:20:50 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
2009-05-18 14:55:34 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name BMesh Operator (BMO) API Wrapper
|
|
|
|
|
* \{ */
|
2013-07-10 02:05:16 +00:00
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
bool EDBM_op_init(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);
|
|
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
if (!BMO_op_vinitf(bm, bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
|
2012-02-20 01:52:35 +00:00
|
|
|
BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
|
2009-05-28 04:41:02 +00:00
|
|
|
va_end(list);
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2009-05-28 04:41:02 +00:00
|
|
|
}
|
2018-03-16 20:46:14 +11:00
|
|
|
|
2009-05-28 04:41:02 +00:00
|
|
|
va_end(list);
|
2009-11-06 12:59:58 +00:00
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
return true;
|
2009-05-28 04:41:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
|
2011-11-07 09:02:10 +00:00
|
|
|
{
|
2011-05-07 02:48:14 +00:00
|
|
|
const char *errmsg;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-02 12:46:08 +10:00
|
|
|
#ifndef NDEBUG
|
2023-06-13 23:05:45 +02:00
|
|
|
struct StatePrev {
|
2021-07-02 12:46:08 +10:00
|
|
|
int verts_len, edges_len, loops_len, faces_len;
|
2023-06-13 23:05:45 +02:00
|
|
|
};
|
|
|
|
|
StatePrev em_state_prev = {
|
|
|
|
|
em->bm->totvert,
|
|
|
|
|
em->bm->totedge,
|
|
|
|
|
em->bm->totloop,
|
|
|
|
|
em->bm->totface,
|
2021-07-02 12:46:08 +10:00
|
|
|
};
|
|
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-02 12:46:08 +10:00
|
|
|
BMO_op_finish(em->bm, bmop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-02 12:46:08 +10:00
|
|
|
bool changed = false;
|
|
|
|
|
bool changed_was_set = false;
|
|
|
|
|
|
|
|
|
|
eBMOpErrorLevel level;
|
2023-06-13 23:05:45 +02:00
|
|
|
while (BMO_error_pop(em->bm, &errmsg, nullptr, &level)) {
|
2021-10-19 18:33:42 +11:00
|
|
|
eReportType type = RPT_INFO;
|
2021-07-02 12:46:08 +10:00
|
|
|
switch (level) {
|
|
|
|
|
case BMO_ERROR_CANCEL: {
|
|
|
|
|
changed_was_set = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BMO_ERROR_WARN: {
|
|
|
|
|
type = RPT_WARNING;
|
|
|
|
|
changed_was_set = true;
|
|
|
|
|
changed = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BMO_ERROR_FATAL: {
|
|
|
|
|
type = RPT_ERROR;
|
|
|
|
|
changed_was_set = true;
|
|
|
|
|
changed = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-03-28 06:44:19 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-02 12:46:08 +10:00
|
|
|
if (do_report) {
|
|
|
|
|
BKE_report(op->reports, type, errmsg);
|
2020-01-07 22:27:16 +11:00
|
|
|
}
|
2021-07-02 12:46:08 +10:00
|
|
|
}
|
|
|
|
|
if (changed_was_set == false) {
|
|
|
|
|
changed = true;
|
2012-02-05 15:55:28 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-02 12:46:08 +10:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
if (changed == false) {
|
|
|
|
|
BLI_assert((em_state_prev.verts_len == em->bm->totvert) &&
|
|
|
|
|
(em_state_prev.edges_len == em->bm->totedge) &&
|
|
|
|
|
(em_state_prev.loops_len == em->bm->totloop) &&
|
|
|
|
|
(em_state_prev.faces_len == em->bm->totface));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2020-07-03 15:19:52 +02:00
|
|
|
|
2021-07-02 12:46:08 +10:00
|
|
|
return changed;
|
2009-05-28 04:41:02 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
bool EDBM_op_callf(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);
|
|
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
|
2012-02-20 01:52:35 +00:00
|
|
|
BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
|
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
|
|
|
va_end(list);
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
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
|
|
|
}
|
|
|
|
|
|
2012-02-12 10:51:45 +00:00
|
|
|
BMO_op_exec(bm, &bmop);
|
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
|
|
|
|
|
|
|
|
va_end(list);
|
2013-03-19 23:17:44 +00:00
|
|
|
return EDBM_op_finish(em, &bmop, op, true);
|
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
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
bool EDBM_op_call_and_selectf(BMEditMesh *em,
|
|
|
|
|
wmOperator *op,
|
|
|
|
|
const char *select_slot_out,
|
|
|
|
|
const bool select_extend,
|
|
|
|
|
const char *fmt,
|
|
|
|
|
...)
|
2010-01-28 00:45:30 +00:00
|
|
|
{
|
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
|
BMOperator bmop;
|
|
|
|
|
va_list list;
|
|
|
|
|
|
|
|
|
|
va_start(list, fmt);
|
|
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
|
2012-02-20 01:52:35 +00:00
|
|
|
BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
|
2010-01-28 00:45:30 +00:00
|
|
|
va_end(list);
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2010-01-28 00:45:30 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-12 10:51:45 +00:00
|
|
|
BMO_op_exec(bm, &bmop);
|
2012-02-16 19:33:46 +00:00
|
|
|
|
2023-01-25 12:56:05 -06:00
|
|
|
BMOpSlot *slot_select_out = BMO_slot_get(bmop.slots_out, select_slot_out);
|
|
|
|
|
char hflag = slot_select_out->slot_subtype.elem & BM_ALL_NOLOOP;
|
2013-07-25 07:00:07 +00:00
|
|
|
BLI_assert(hflag != 0);
|
2012-11-27 02:34:40 +00:00
|
|
|
|
2013-07-25 07:00:07 +00:00
|
|
|
if (select_extend == false) {
|
|
|
|
|
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
|
|
|
|
|
}
|
2012-02-16 19:33:46 +00:00
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
BMO_slot_buffer_hflag_enable(
|
|
|
|
|
em->bm, bmop.slots_out, select_slot_out, hflag, BM_ELEM_SELECT, true);
|
2010-01-28 00:45:30 +00:00
|
|
|
|
|
|
|
|
va_end(list);
|
2013-03-19 23:17:44 +00:00
|
|
|
return EDBM_op_finish(em, &bmop, op, true);
|
2010-01-28 00:45:30 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
bool EDBM_op_call_silentf(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);
|
|
|
|
|
|
2012-07-21 00:58:02 +00:00
|
|
|
if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
|
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
|
|
|
va_end(list);
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
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
|
|
|
}
|
|
|
|
|
|
2012-02-12 10:51:45 +00:00
|
|
|
BMO_op_exec(bm, &bmop);
|
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
|
|
|
|
|
|
|
|
va_end(list);
|
2023-06-13 23:05:45 +02:00
|
|
|
return EDBM_op_finish(em, &bmop, nullptr, false);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
2010-03-09 04:32:40 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Edit BMesh API
|
|
|
|
|
*
|
|
|
|
|
* Make/Clear/Free functions.
|
|
|
|
|
* \{ */
|
2010-03-09 04:32:40 +00:00
|
|
|
|
2018-03-14 02:02:05 +11:00
|
|
|
void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
|
2024-03-12 13:28:26 +01:00
|
|
|
{
|
|
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
|
|
|
|
EDBM_mesh_make_from_mesh(ob, mesh, select_mode, add_key_index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EDBM_mesh_make_from_mesh(Object *ob,
|
|
|
|
|
Mesh *src_mesh,
|
|
|
|
|
const int select_mode,
|
|
|
|
|
const bool add_key_index)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2023-06-13 23:05:45 +02:00
|
|
|
BMeshCreateParams create_params{};
|
|
|
|
|
create_params.use_toolflags = true;
|
2024-03-12 13:28:26 +01:00
|
|
|
BMesh *bm = BKE_mesh_to_bmesh(src_mesh, ob, add_key_index, &create_params);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-03-21 23:18:49 +01:00
|
|
|
if (mesh->runtime->edit_mesh) {
|
2011-10-30 02:15:32 +00:00
|
|
|
/* this happens when switching shape keys */
|
2024-03-21 23:18:49 +01:00
|
|
|
EDBM_mesh_free_data(mesh->runtime->edit_mesh);
|
|
|
|
|
MEM_freeN(mesh->runtime->edit_mesh);
|
2011-10-30 02:15:32 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-13 15:05:39 +10:00
|
|
|
/* Executing operators re-tessellates,
|
|
|
|
|
* so we can avoid doing here but at some point it may need to be added back. */
|
2024-03-21 23:18:49 +01:00
|
|
|
mesh->runtime->edit_mesh = BKE_editmesh_create(bm);
|
2012-01-22 22:20:20 +00:00
|
|
|
|
2024-03-21 23:18:49 +01:00
|
|
|
mesh->runtime->edit_mesh->selectmode = mesh->runtime->edit_mesh->bm->selectmode = select_mode;
|
|
|
|
|
mesh->runtime->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
|
2013-07-22 10:44:24 +00:00
|
|
|
|
|
|
|
|
/* we need to flush selection because the mode may have changed from when last in editmode */
|
2024-03-21 23:18:49 +01:00
|
|
|
EDBM_selectmode_flush(mesh->runtime->edit_mesh);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-28 06:12:17 +11:00
|
|
|
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2024-03-21 23:18:49 +01:00
|
|
|
BMesh *bm = mesh->runtime->edit_mesh->bm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-02-12 14:37:16 +11:00
|
|
|
/* Workaround for #42360, 'ob->shapenr' should be 1 in this case.
|
2014-11-10 13:32:39 +01:00
|
|
|
* however this isn't synchronized between objects at the moment. */
|
2023-12-08 16:40:06 -05:00
|
|
|
if (UNLIKELY((ob->shapenr == 0) && (mesh->key && !BLI_listbase_is_empty(&mesh->key->block)))) {
|
2014-11-10 13:32:39 +01:00
|
|
|
bm->shapenr = 1;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
BMeshToMeshParams params{};
|
|
|
|
|
params.calc_object_remap = true;
|
|
|
|
|
params.update_shapekey_indices = !free_data;
|
2023-12-08 16:40:06 -05:00
|
|
|
BM_mesh_bm_to_me(bmain, bm, mesh, ¶ms);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
2019-11-28 06:12:17 +11:00
|
|
|
void EDBM_mesh_load(Main *bmain, Object *ob)
|
|
|
|
|
{
|
|
|
|
|
EDBM_mesh_load_ex(bmain, ob, true);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 15:05:39 +10:00
|
|
|
void EDBM_mesh_free_data(BMEditMesh *em)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2012-04-23 04:24:11 +00:00
|
|
|
/* These tables aren't used yet, so it's not strictly necessary
|
2020-04-03 21:47:56 +11:00
|
|
|
* to 'end' them but if someone tries to start using them,
|
|
|
|
|
* having these in place will save a lot of pain. */
|
2023-06-13 23:05:45 +02:00
|
|
|
ED_mesh_mirror_spatial_table_end(nullptr);
|
|
|
|
|
ED_mesh_mirror_topo_table_end(nullptr);
|
2012-04-23 04:24:11 +00:00
|
|
|
|
2021-07-13 15:05:39 +10:00
|
|
|
BKE_editmesh_free_data(em);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \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);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-20 09:49:54 +00:00
|
|
|
void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
|
2009-08-05 02:34:54 +00:00
|
|
|
{
|
2021-06-18 15:31:14 +02:00
|
|
|
BM_mesh_select_mode_flush_ex(em->bm, selectmode, BM_SELECT_LEN_FLUSH_RECALC_ALL);
|
2009-08-05 02:34:54 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-10 06:16:21 +00:00
|
|
|
void EDBM_selectmode_flush(BMEditMesh *em)
|
|
|
|
|
{
|
|
|
|
|
EDBM_selectmode_flush_ex(em, em->selectmode);
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 03:03:42 +00:00
|
|
|
void EDBM_deselect_flush(BMEditMesh *em)
|
2009-09-16 17:43:09 +00:00
|
|
|
{
|
2018-09-27 15:35:22 +02:00
|
|
|
/* function below doesn't use. just do this to keep the values in sync */
|
2012-02-10 03:03:42 +00:00
|
|
|
em->bm->selectmode = em->selectmode;
|
2012-02-12 10:51:45 +00:00
|
|
|
BM_mesh_deselect_flush(em->bm);
|
2009-09-16 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-10 03:03:42 +00:00
|
|
|
void EDBM_select_flush(BMEditMesh *em)
|
2009-05-16 16:18:08 +00:00
|
|
|
{
|
2018-09-27 15:35:22 +02:00
|
|
|
/* function below doesn't use. just do this to keep the values in sync */
|
2009-05-18 10:29:37 +00:00
|
|
|
em->bm->selectmode = em->selectmode;
|
2012-02-12 10:51:45 +00:00
|
|
|
BM_mesh_select_flush(em->bm);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
|
|
|
|
|
2014-11-06 15:17:16 +01:00
|
|
|
void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
|
2009-08-06 05:06:55 +00:00
|
|
|
{
|
|
|
|
|
BMOperator bmop;
|
2014-11-06 15:17:16 +01:00
|
|
|
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
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);
|
2012-02-12 10:51:45 +00:00
|
|
|
BMO_op_exec(em->bm, &bmop);
|
2021-06-24 15:56:58 +10:00
|
|
|
/* Don't flush selection in edge/vertex mode. */
|
2013-03-19 23:17:44 +00:00
|
|
|
BMO_slot_buffer_hflag_enable(
|
|
|
|
|
em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
2012-02-12 10:51:45 +00:00
|
|
|
BMO_op_finish(em->bm, &bmop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-01-08 17:40:36 +00:00
|
|
|
EDBM_selectmode_flush(em);
|
2009-08-06 05:06:55 +00:00
|
|
|
}
|
|
|
|
|
|
2014-11-06 15:17:16 +01:00
|
|
|
void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
|
2009-08-06 05:06:55 +00:00
|
|
|
{
|
|
|
|
|
BMOperator bmop;
|
2014-11-06 15:17:16 +01:00
|
|
|
const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
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);
|
2012-02-12 10:51:45 +00:00
|
|
|
BMO_op_exec(em->bm, &bmop);
|
2021-06-24 15:56:58 +10:00
|
|
|
/* Don't flush selection in edge/vertex mode. */
|
2013-03-19 23:17:44 +00:00
|
|
|
BMO_slot_buffer_hflag_disable(
|
|
|
|
|
em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
|
2012-02-12 10:51:45 +00:00
|
|
|
BMO_op_finish(em->bm, &bmop);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 06:16:21 +00:00
|
|
|
EDBM_selectmode_flush(em);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-15 14:17:54 +11:00
|
|
|
/* only needed for select less, ensure we don't have isolated elements remaining */
|
|
|
|
|
BM_mesh_select_mode_clean(em->bm);
|
2009-08-06 05:06:55 +00:00
|
|
|
}
|
2009-05-16 16:18:08 +00:00
|
|
|
|
2012-02-12 18:43:59 +00:00
|
|
|
void EDBM_flag_disable_all(BMEditMesh *em, const char hflag)
|
2009-05-18 08:46:04 +00:00
|
|
|
{
|
2013-03-19 23:17:44 +00:00
|
|
|
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, false);
|
2009-05-18 08:46:04 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-12 18:43:59 +00:00
|
|
|
void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
|
2009-05-18 10:29:37 +00:00
|
|
|
{
|
2013-03-19 23:17:44 +00:00
|
|
|
BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
|
2009-05-16 16:18:08 +00:00
|
|
|
}
|
2009-05-18 14:55:34 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name UV Vertex Map API
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2023-01-28 10:50:59 +13:00
|
|
|
UvVertMap *BM_uv_vert_map_create(BMesh *bm, const bool use_select)
|
2009-07-21 08:39:58 +00:00
|
|
|
{
|
2023-01-31 14:22:25 +11:00
|
|
|
/* NOTE: delimiting on alternate face-winding was once supported and could be useful
|
|
|
|
|
* in some cases. If this is need see: D17137 to restore support. */
|
2009-07-21 08:39:58 +00:00
|
|
|
BMVert *ev;
|
|
|
|
|
BMFace *efa;
|
|
|
|
|
BMLoop *l;
|
|
|
|
|
BMIter iter, liter;
|
2020-04-03 16:21:24 +11:00
|
|
|
uint a;
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_PROP_FLOAT2);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-01-25 12:56:05 -06:00
|
|
|
const int totverts = bm->totvert;
|
|
|
|
|
int totuv = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-21 08:39:58 +00:00
|
|
|
/* generate UvMapVert array */
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
2013-01-12 20:01:09 +00:00
|
|
|
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
2009-07-21 08:39:58 +00:00
|
|
|
totuv += efa->len;
|
2013-01-12 20:01:09 +00:00
|
|
|
}
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
if (totuv == 0) {
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2023-01-25 12:56:05 -06:00
|
|
|
UvVertMap *vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
|
2009-07-21 08:39:58 +00:00
|
|
|
if (!vmap) {
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-21 09:10:08 +00:00
|
|
|
vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt");
|
2023-01-25 12:56:05 -06:00
|
|
|
UvMapVert *buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert");
|
|
|
|
|
|
2009-07-21 08:39:58 +00:00
|
|
|
if (!vmap->vert || !vmap->buf) {
|
2012-05-05 21:28:12 +00:00
|
|
|
BKE_mesh_uv_vert_map_free(vmap);
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-04-09 16:12:20 +02:00
|
|
|
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
|
2013-01-12 20:01:09 +00:00
|
|
|
if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
2023-01-25 12:56:05 -06:00
|
|
|
int i;
|
2019-04-21 04:40:16 +10:00
|
|
|
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
|
2023-07-24 22:06:55 +02:00
|
|
|
buf->loop_of_face_index = i;
|
|
|
|
|
buf->face_index = a;
|
2023-07-22 11:36:59 +10:00
|
|
|
buf->separate = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-12 10:51:45 +00:00
|
|
|
buf->next = vmap->vert[BM_elem_index_get(l->v)];
|
|
|
|
|
vmap->vert[BM_elem_index_get(l->v)] = buf;
|
2009-07-21 08:39:58 +00:00
|
|
|
buf++;
|
2015-05-17 23:04:34 +10:00
|
|
|
}
|
2015-04-09 16:12:20 +02:00
|
|
|
}
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-21 08:39:58 +00:00
|
|
|
/* sort individual uvs for each vert */
|
2015-04-09 16:12:20 +02:00
|
|
|
BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
|
2023-06-13 23:05:45 +02:00
|
|
|
UvMapVert *newvlist = nullptr, *vlist = vmap->vert[a];
|
2009-07-21 08:39:58 +00:00
|
|
|
UvMapVert *iterv, *v, *lastv, *next;
|
2020-07-21 12:54:23 +10:00
|
|
|
const float *uv, *uv2;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
while (vlist) {
|
|
|
|
|
v = vlist;
|
|
|
|
|
vlist = vlist->next;
|
|
|
|
|
v->next = newvlist;
|
|
|
|
|
newvlist = v;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
efa = BM_face_at_index(bm, v->face_index);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
l = static_cast<BMLoop *>(
|
2023-07-24 22:06:55 +02:00
|
|
|
BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->loop_of_face_index));
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
uv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
lastv = nullptr;
|
2012-02-10 18:09:19 +00:00
|
|
|
iterv = vlist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
while (iterv) {
|
|
|
|
|
next = iterv->next;
|
2023-07-24 22:06:55 +02:00
|
|
|
efa = BM_face_at_index(bm, iterv->face_index);
|
2023-06-13 23:05:45 +02:00
|
|
|
l = static_cast<BMLoop *>(
|
2023-07-24 22:06:55 +02:00
|
|
|
BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->loop_of_face_index));
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
uv2 = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-01-28 10:50:59 +13:00
|
|
|
if (compare_v2v2(uv2, uv, STD_UV_CONNECT_LIMIT)) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (lastv) {
|
2012-02-10 18:09:19 +00:00
|
|
|
lastv->next = next;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-02-10 18:09:19 +00:00
|
|
|
vlist = next;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-02-10 18:09:19 +00:00
|
|
|
iterv->next = newvlist;
|
|
|
|
|
newvlist = iterv;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2012-03-06 17:23:26 +00:00
|
|
|
else {
|
2012-02-10 18:09:19 +00:00
|
|
|
lastv = iterv;
|
2012-03-06 17:23:26 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
iterv = next;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-22 11:36:59 +10:00
|
|
|
newvlist->separate = true;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
vmap->vert[a] = newvlist;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-21 08:39:58 +00:00
|
|
|
return vmap;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 16:21:24 +11:00
|
|
|
UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
|
2009-07-21 08:39:58 +00:00
|
|
|
{
|
|
|
|
|
return vmap->vert[v];
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
UvElement **BM_uv_element_map_ensure_head_table(UvElementMap *element_map)
|
2022-08-11 11:20:00 +12:00
|
|
|
{
|
|
|
|
|
if (element_map->head_table) {
|
2022-08-16 19:41:35 +12:00
|
|
|
return element_map->head_table;
|
2022-08-11 11:20:00 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For each UvElement, locate the "separate" UvElement that precedes it in the linked list. */
|
2023-06-13 23:05:45 +02:00
|
|
|
element_map->head_table = static_cast<UvElement **>(
|
|
|
|
|
MEM_mallocN(sizeof(*element_map->head_table) * element_map->total_uvs, __func__));
|
2022-08-11 11:20:00 +12:00
|
|
|
UvElement **head_table = element_map->head_table;
|
|
|
|
|
for (int i = 0; i < element_map->total_uvs; i++) {
|
|
|
|
|
UvElement *head = element_map->storage + i;
|
|
|
|
|
if (head->separate) {
|
|
|
|
|
UvElement *element = head;
|
|
|
|
|
while (element) {
|
|
|
|
|
head_table[element - element_map->storage] = head;
|
|
|
|
|
element = element->next;
|
|
|
|
|
if (element && element->separate) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-16 19:41:35 +12:00
|
|
|
return element_map->head_table;
|
2022-08-11 11:20:00 +12:00
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
int *BM_uv_element_map_ensure_unique_index(UvElementMap *element_map)
|
2022-11-09 11:42:30 +13:00
|
|
|
{
|
|
|
|
|
if (!element_map->unique_index_table) {
|
2023-06-13 23:05:45 +02:00
|
|
|
element_map->unique_index_table = static_cast<int *>(
|
|
|
|
|
MEM_callocN(element_map->total_uvs * sizeof(*element_map->unique_index_table), __func__));
|
2022-11-09 11:42:30 +13:00
|
|
|
|
|
|
|
|
int j = 0;
|
|
|
|
|
for (int i = 0; i < element_map->total_uvs; i++) {
|
|
|
|
|
UvElement *element = element_map->storage + i;
|
|
|
|
|
if (!element->separate) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
BLI_assert(0 <= j);
|
|
|
|
|
BLI_assert(j < element_map->total_unique_uvs);
|
|
|
|
|
while (element) {
|
|
|
|
|
element_map->unique_index_table[element - element_map->storage] = j;
|
|
|
|
|
element = element->next;
|
|
|
|
|
if (!element || element->separate) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
}
|
|
|
|
|
BLI_assert(j == element_map->total_unique_uvs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return element_map->unique_index_table;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
int BM_uv_element_get_unique_index(UvElementMap *element_map, UvElement *child)
|
2022-11-09 11:42:30 +13:00
|
|
|
{
|
2022-11-09 14:54:37 +13:00
|
|
|
int *unique_index = BM_uv_element_map_ensure_unique_index(element_map);
|
2022-11-09 11:42:30 +13:00
|
|
|
int index = child - element_map->storage;
|
|
|
|
|
BLI_assert(0 <= index);
|
|
|
|
|
BLI_assert(index < element_map->total_uvs);
|
|
|
|
|
return unique_index[index];
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-06 10:29:02 +10:00
|
|
|
#define INVALID_ISLAND uint(-1)
|
2022-07-13 11:39:06 +12:00
|
|
|
|
2022-07-14 12:40:43 +12:00
|
|
|
static void bm_uv_assign_island(UvElementMap *element_map,
|
|
|
|
|
UvElement *element,
|
|
|
|
|
int nisland,
|
|
|
|
|
uint *map,
|
|
|
|
|
UvElement *islandbuf,
|
|
|
|
|
int islandbufsize)
|
|
|
|
|
{
|
|
|
|
|
element->island = nisland;
|
2022-08-08 10:15:13 +12:00
|
|
|
map[element - element_map->storage] = islandbufsize;
|
2022-07-14 12:40:43 +12:00
|
|
|
|
|
|
|
|
/* Copy *element to islandbuf[islandbufsize]. */
|
|
|
|
|
islandbuf[islandbufsize].l = element->l;
|
|
|
|
|
islandbuf[islandbufsize].separate = element->separate;
|
2023-07-24 22:06:55 +02:00
|
|
|
islandbuf[islandbufsize].loop_of_face_index = element->loop_of_face_index;
|
2022-07-14 12:40:43 +12:00
|
|
|
islandbuf[islandbufsize].island = element->island;
|
|
|
|
|
islandbuf[islandbufsize].flag = element->flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int bm_uv_edge_select_build_islands(UvElementMap *element_map,
|
|
|
|
|
const Scene *scene,
|
|
|
|
|
UvElement *islandbuf,
|
|
|
|
|
uint *map,
|
|
|
|
|
bool uv_selected,
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
const BMUVOffsets offsets)
|
2022-07-14 12:40:43 +12:00
|
|
|
{
|
2022-08-16 19:41:35 +12:00
|
|
|
BM_uv_element_map_ensure_head_table(element_map);
|
2022-07-14 12:40:43 +12:00
|
|
|
|
2022-08-11 11:20:00 +12:00
|
|
|
int total_uvs = element_map->total_uvs;
|
2022-07-14 12:40:43 +12:00
|
|
|
|
|
|
|
|
/* Depth first search the graph, building islands as we go. */
|
|
|
|
|
int nislands = 0;
|
|
|
|
|
int islandbufsize = 0;
|
2022-08-07 16:11:47 +12:00
|
|
|
int stack_upper_bound = total_uvs;
|
2023-06-13 23:05:45 +02:00
|
|
|
UvElement **stack_uv = static_cast<UvElement **>(
|
|
|
|
|
MEM_mallocN(sizeof(*stack_uv) * stack_upper_bound, __func__));
|
2022-07-14 12:40:43 +12:00
|
|
|
int stacksize_uv = 0;
|
2022-08-07 16:11:47 +12:00
|
|
|
for (int i = 0; i < total_uvs; i++) {
|
2022-08-08 10:15:13 +12:00
|
|
|
UvElement *element = element_map->storage + i;
|
2022-07-14 12:40:43 +12:00
|
|
|
if (element->island != INVALID_ISLAND) {
|
2023-06-13 14:51:49 -04:00
|
|
|
/* Unique UV (element and all its children) are already part of an island. */
|
2022-07-14 12:40:43 +12:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a new island, i.e. nislands++. */
|
|
|
|
|
|
|
|
|
|
BLI_assert(element->separate); /* Ensure we're the head of this unique UV. */
|
|
|
|
|
|
|
|
|
|
/* Seed the graph search. */
|
|
|
|
|
stack_uv[stacksize_uv++] = element;
|
|
|
|
|
while (element) {
|
|
|
|
|
bm_uv_assign_island(element_map, element, nislands, map, islandbuf, islandbufsize++);
|
|
|
|
|
element = element->next;
|
|
|
|
|
if (element && element->separate) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Traverse the graph. */
|
|
|
|
|
while (stacksize_uv) {
|
|
|
|
|
BLI_assert(stacksize_uv < stack_upper_bound);
|
|
|
|
|
element = stack_uv[--stacksize_uv];
|
|
|
|
|
while (element) {
|
|
|
|
|
|
|
|
|
|
/* Scan forwards around the BMFace that contains element->l. */
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if (!uv_selected || uvedit_edge_select_test(scene, element->l, offsets)) {
|
2023-05-22 23:23:23 +02:00
|
|
|
UvElement *next = BM_uv_element_get(element_map, element->l->next);
|
|
|
|
|
if (next && next->island == INVALID_ISLAND) {
|
2022-08-11 11:20:00 +12:00
|
|
|
UvElement *tail = element_map->head_table[next - element_map->storage];
|
2022-07-14 12:40:43 +12:00
|
|
|
stack_uv[stacksize_uv++] = tail;
|
|
|
|
|
while (tail) {
|
|
|
|
|
bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
|
|
|
|
|
tail = tail->next;
|
|
|
|
|
if (tail && tail->separate) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Scan backwards around the BMFace that contains element->l. */
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if (!uv_selected || uvedit_edge_select_test(scene, element->l->prev, offsets)) {
|
2023-05-22 23:23:23 +02:00
|
|
|
UvElement *prev = BM_uv_element_get(element_map, element->l->prev);
|
|
|
|
|
if (prev && prev->island == INVALID_ISLAND) {
|
2022-08-11 11:20:00 +12:00
|
|
|
UvElement *tail = element_map->head_table[prev - element_map->storage];
|
2022-07-14 12:40:43 +12:00
|
|
|
stack_uv[stacksize_uv++] = tail;
|
|
|
|
|
while (tail) {
|
|
|
|
|
bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
|
|
|
|
|
tail = tail->next;
|
|
|
|
|
if (tail && tail->separate) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The same for all the UvElements in this unique UV. */
|
|
|
|
|
element = element->next;
|
|
|
|
|
if (element && element->separate) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
nislands++;
|
|
|
|
|
}
|
2022-08-07 16:11:47 +12:00
|
|
|
BLI_assert(islandbufsize == total_uvs);
|
2022-07-14 12:40:43 +12:00
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(stack_uv);
|
2022-08-11 11:20:00 +12:00
|
|
|
MEM_SAFE_FREE(element_map->head_table);
|
2022-07-14 12:40:43 +12:00
|
|
|
|
|
|
|
|
return nislands;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-10 20:13:17 +12:00
|
|
|
static void bm_uv_build_islands(UvElementMap *element_map,
|
|
|
|
|
BMesh *bm,
|
|
|
|
|
const Scene *scene,
|
|
|
|
|
bool uv_selected)
|
|
|
|
|
{
|
|
|
|
|
int totuv = element_map->total_uvs;
|
|
|
|
|
int nislands = 0;
|
|
|
|
|
int islandbufsize = 0;
|
|
|
|
|
|
|
|
|
|
/* map holds the map from current vmap->buf to the new, sorted map */
|
2023-06-13 23:05:45 +02:00
|
|
|
uint *map = static_cast<uint *>(MEM_mallocN(sizeof(*map) * totuv, __func__));
|
|
|
|
|
BMFace **stack = static_cast<BMFace **>(MEM_mallocN(sizeof(*stack) * bm->totface, __func__));
|
|
|
|
|
UvElement *islandbuf = static_cast<UvElement *>(
|
|
|
|
|
MEM_callocN(sizeof(*islandbuf) * totuv, __func__));
|
2022-08-10 20:13:17 +12:00
|
|
|
/* Island number for BMFaces. */
|
2023-06-13 23:05:45 +02:00
|
|
|
int *island_number = static_cast<int *>(
|
|
|
|
|
MEM_callocN(sizeof(*island_number) * bm->totface, __func__));
|
2022-08-10 20:13:17 +12:00
|
|
|
copy_vn_i(island_number, bm->totface, INVALID_ISLAND);
|
|
|
|
|
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
const BMUVOffsets uv_offsets = BM_uv_map_get_offsets(bm);
|
2022-08-10 20:13:17 +12:00
|
|
|
|
|
|
|
|
const bool use_uv_edge_connectivity = scene->toolsettings->uv_flag & UV_SYNC_SELECTION ?
|
|
|
|
|
scene->toolsettings->selectmode & SCE_SELECT_EDGE :
|
|
|
|
|
scene->toolsettings->uv_selectmode & UV_SELECT_EDGE;
|
|
|
|
|
if (use_uv_edge_connectivity) {
|
|
|
|
|
nislands = bm_uv_edge_select_build_islands(
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
element_map, scene, islandbuf, map, uv_selected, uv_offsets);
|
2022-08-10 20:13:17 +12:00
|
|
|
islandbufsize = totuv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < totuv; i++) {
|
|
|
|
|
if (element_map->storage[i].island == INVALID_ISLAND) {
|
|
|
|
|
int stacksize = 0;
|
|
|
|
|
element_map->storage[i].island = nislands;
|
|
|
|
|
stack[0] = element_map->storage[i].l->f;
|
|
|
|
|
island_number[BM_elem_index_get(stack[0])] = nislands;
|
|
|
|
|
stacksize = 1;
|
|
|
|
|
|
|
|
|
|
while (stacksize > 0) {
|
|
|
|
|
BMFace *efa = stack[--stacksize];
|
|
|
|
|
|
|
|
|
|
BMLoop *l;
|
|
|
|
|
BMIter liter;
|
|
|
|
|
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if (uv_selected && !uvedit_uv_select_test(scene, l, uv_offsets)) {
|
2022-08-10 20:13:17 +12:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UvElement *initelement = element_map->vertex[BM_elem_index_get(l->v)];
|
|
|
|
|
|
|
|
|
|
for (UvElement *element = initelement; element; element = element->next) {
|
|
|
|
|
if (element->separate) {
|
|
|
|
|
initelement = element;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (element->l->f == efa) {
|
|
|
|
|
/* found the uv corresponding to our face and vertex.
|
|
|
|
|
* Now fill it to the buffer */
|
|
|
|
|
bm_uv_assign_island(element_map, element, nislands, map, islandbuf, islandbufsize++);
|
|
|
|
|
|
|
|
|
|
for (element = initelement; element; element = element->next) {
|
|
|
|
|
if (element->separate && element != initelement) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) {
|
|
|
|
|
stack[stacksize++] = element->l->f;
|
|
|
|
|
island_number[BM_elem_index_get(element->l->f)] = nislands;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nislands++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(island_number);
|
|
|
|
|
|
|
|
|
|
/* remap */
|
|
|
|
|
for (int i = 0; i < bm->totvert; i++) {
|
2023-06-13 23:05:45 +02:00
|
|
|
/* important since we may do selection only. Some of these may be nullptr */
|
2022-08-10 20:13:17 +12:00
|
|
|
if (element_map->vertex[i]) {
|
|
|
|
|
element_map->vertex[i] = &islandbuf[map[element_map->vertex[i] - element_map->storage]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
element_map->island_indices = static_cast<int *>(
|
|
|
|
|
MEM_callocN(sizeof(*element_map->island_indices) * nislands, __func__));
|
|
|
|
|
element_map->island_total_uvs = static_cast<int *>(
|
|
|
|
|
MEM_callocN(sizeof(*element_map->island_total_uvs) * nislands, __func__));
|
|
|
|
|
element_map->island_total_unique_uvs = static_cast<int *>(
|
|
|
|
|
MEM_callocN(sizeof(*element_map->island_total_unique_uvs) * nislands, __func__));
|
2022-08-10 20:13:17 +12:00
|
|
|
int j = 0;
|
|
|
|
|
for (int i = 0; i < totuv; i++) {
|
2022-08-11 14:18:31 +12:00
|
|
|
UvElement *next = element_map->storage[i].next;
|
2023-06-13 23:05:45 +02:00
|
|
|
islandbuf[map[i]].next = next ? &islandbuf[map[next - element_map->storage]] : nullptr;
|
2022-08-10 20:13:17 +12:00
|
|
|
|
|
|
|
|
if (islandbuf[i].island != j) {
|
|
|
|
|
j++;
|
2022-08-11 14:18:31 +12:00
|
|
|
element_map->island_indices[j] = i;
|
|
|
|
|
}
|
|
|
|
|
BLI_assert(islandbuf[i].island == j);
|
|
|
|
|
element_map->island_total_uvs[j]++;
|
|
|
|
|
if (islandbuf[i].separate) {
|
|
|
|
|
element_map->island_total_unique_uvs[j]++;
|
2022-08-10 20:13:17 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_SAFE_FREE(element_map->storage);
|
|
|
|
|
element_map->storage = islandbuf;
|
2023-06-13 23:05:45 +02:00
|
|
|
islandbuf = nullptr;
|
2022-08-11 14:18:31 +12:00
|
|
|
element_map->total_islands = nislands;
|
2022-08-10 20:13:17 +12:00
|
|
|
MEM_SAFE_FREE(stack);
|
|
|
|
|
MEM_SAFE_FREE(map);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-20 15:19:32 +11:00
|
|
|
/** Return true if `loop` has UV co-ordinates which match `luv_a` and `luv_b`. */
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
static bool loop_uv_match(BMLoop *loop,
|
|
|
|
|
const float luv_a[2],
|
|
|
|
|
const float luv_b[2],
|
|
|
|
|
int cd_loop_uv_offset)
|
2022-09-12 12:22:46 +12:00
|
|
|
{
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
const float *luv_c = BM_ELEM_CD_GET_FLOAT_P(loop, cd_loop_uv_offset);
|
|
|
|
|
const float *luv_d = BM_ELEM_CD_GET_FLOAT_P(loop->next, cd_loop_uv_offset);
|
|
|
|
|
return compare_v2v2(luv_a, luv_c, STD_UV_CONNECT_LIMIT) &&
|
|
|
|
|
compare_v2v2(luv_b, luv_d, STD_UV_CONNECT_LIMIT);
|
2022-09-12 12:22:46 +12:00
|
|
|
}
|
|
|
|
|
|
2023-01-16 14:49:49 +11:00
|
|
|
/**
|
|
|
|
|
* Utility function to implement #seam_connected.
|
|
|
|
|
*
|
|
|
|
|
* Given `edge`, `luv_anchor` & `luv_fan` find if `needle` is connected without
|
|
|
|
|
* seams or disjoint UVs which would delimit causing them not to be considered connected.
|
|
|
|
|
*
|
|
|
|
|
* \note The term *anchor* is used for the vertex at the center of a face-fan
|
|
|
|
|
* which is being stepped over. Even though every connected face may have a different UV,
|
|
|
|
|
* loops are only stepped onto which match the initial `luv_anchor`.
|
|
|
|
|
*
|
|
|
|
|
* \param edge: Search for `needle` in all loops connected to `edge` (recursively).
|
|
|
|
|
* \param luv_anchor: The UV of the anchor (vertex that's being stepped around).
|
|
|
|
|
* \param luv_fan: The UV of the outer edge, this changes as the fan is stepped over.
|
2023-01-20 15:20:02 +11:00
|
|
|
* \param needle: Search for this loop, also defines the vertex at the center of the face-fan.
|
2023-01-16 14:49:49 +11:00
|
|
|
* \param visited: A set of edges to prevent recursing down the same edge multiple times.
|
|
|
|
|
* \param cd_loop_uv_offset: The UV layer.
|
|
|
|
|
* \return true if there are edges that fan between them that are seam-free.
|
2024-01-11 16:46:46 +11:00
|
|
|
*/
|
2023-01-14 11:21:31 +13:00
|
|
|
static bool seam_connected_recursive(BMEdge *edge,
|
|
|
|
|
const float luv_anchor[2],
|
|
|
|
|
const float luv_fan[2],
|
2023-01-16 14:49:49 +11:00
|
|
|
const BMLoop *needle,
|
2022-09-12 12:22:46 +12:00
|
|
|
GSet *visited,
|
2023-01-16 14:49:49 +11:00
|
|
|
const int cd_loop_uv_offset)
|
2022-09-12 12:22:46 +12:00
|
|
|
{
|
2023-01-14 11:21:31 +13:00
|
|
|
BMVert *anchor = needle->v;
|
2022-09-12 12:22:46 +12:00
|
|
|
BLI_assert(edge->v1 == anchor || edge->v2 == anchor);
|
|
|
|
|
|
|
|
|
|
if (BM_elem_flag_test(edge, BM_ELEM_SEAM)) {
|
|
|
|
|
return false; /* Edge is a seam, don't traverse. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!BLI_gset_add(visited, edge)) {
|
|
|
|
|
return false; /* Already visited. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BMLoop *loop;
|
|
|
|
|
BMIter liter;
|
|
|
|
|
BM_ITER_ELEM (loop, &liter, edge, BM_LOOPS_OF_EDGE) {
|
|
|
|
|
if (loop->v == anchor) {
|
|
|
|
|
if (!loop_uv_match(loop, luv_anchor, luv_fan, cd_loop_uv_offset)) {
|
|
|
|
|
continue; /* `loop` is disjoint in UV space. */
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-14 10:46:19 +13:00
|
|
|
if (loop == needle) {
|
2022-09-12 12:22:46 +12:00
|
|
|
return true; /* Success. */
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 14:49:49 +11:00
|
|
|
const float *luv_far = BM_ELEM_CD_GET_FLOAT_P(loop->prev, cd_loop_uv_offset);
|
2022-09-12 12:22:46 +12:00
|
|
|
if (seam_connected_recursive(
|
2023-01-14 11:21:31 +13:00
|
|
|
loop->prev->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset))
|
|
|
|
|
{
|
2022-09-12 12:22:46 +12:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(loop->next->v == anchor);
|
|
|
|
|
if (!loop_uv_match(loop, luv_fan, luv_anchor, cd_loop_uv_offset)) {
|
|
|
|
|
continue; /* `loop` is disjoint in UV space. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (loop->next == needle) {
|
|
|
|
|
return true; /* Success. */
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 14:49:49 +11:00
|
|
|
const float *luv_far = BM_ELEM_CD_GET_FLOAT_P(loop->next->next, cd_loop_uv_offset);
|
2022-09-12 12:22:46 +12:00
|
|
|
if (seam_connected_recursive(
|
2023-01-14 11:21:31 +13:00
|
|
|
loop->next->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset))
|
|
|
|
|
{
|
2022-09-12 12:22:46 +12:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-16 14:49:49 +11:00
|
|
|
/**
|
|
|
|
|
* Given `loop_a` and `loop_b` originate from the same vertex and share a UV,
|
|
|
|
|
*
|
|
|
|
|
* \return true if there are edges that fan between them that are seam-free.
|
2022-09-12 12:22:46 +12:00
|
|
|
* return false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
static bool seam_connected(BMLoop *loop_a, BMLoop *loop_b, GSet *visited, int cd_loop_uv_offset)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(loop_a && loop_b);
|
|
|
|
|
BLI_assert(loop_a != loop_b);
|
|
|
|
|
BLI_assert(loop_a->v == loop_b->v);
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
BLI_gset_clear(visited, nullptr);
|
2022-09-12 12:22:46 +12:00
|
|
|
|
2023-01-14 11:21:31 +13:00
|
|
|
const float *luv_anchor = BM_ELEM_CD_GET_FLOAT_P(loop_a, cd_loop_uv_offset);
|
2023-01-14 10:46:19 +13:00
|
|
|
const float *luv_next_fan = BM_ELEM_CD_GET_FLOAT_P(loop_a->next, cd_loop_uv_offset);
|
|
|
|
|
bool result = seam_connected_recursive(
|
|
|
|
|
loop_a->e, luv_anchor, luv_next_fan, loop_b, visited, cd_loop_uv_offset);
|
|
|
|
|
if (!result) {
|
|
|
|
|
/* Search around `loop_a` in the opposite direction, as one of the edges may be delimited by
|
2023-02-12 14:37:16 +11:00
|
|
|
* a boundary, seam or disjoint UV, or itself be one of these. See: #103670, #103787. */
|
2023-01-16 14:49:49 +11:00
|
|
|
const float *luv_prev_fan = BM_ELEM_CD_GET_FLOAT_P(loop_a->prev, cd_loop_uv_offset);
|
2023-01-14 10:46:19 +13:00
|
|
|
result = seam_connected_recursive(
|
|
|
|
|
loop_a->prev->e, luv_anchor, luv_prev_fan, loop_b, visited, cd_loop_uv_offset);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 12:22:46 +12:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-20 19:28:51 +10:00
|
|
|
UvElementMap *BM_uv_element_map_create(BMesh *bm,
|
2019-12-31 12:56:27 -03:00
|
|
|
const Scene *scene,
|
|
|
|
|
const bool uv_selected,
|
2015-06-20 19:28:51 +10:00
|
|
|
const bool use_winding,
|
2022-09-12 12:22:46 +12:00
|
|
|
const bool use_seams,
|
2015-06-20 19:28:51 +10:00
|
|
|
const bool do_islands)
|
2012-01-17 21:08:25 +00:00
|
|
|
{
|
2023-04-04 12:10:30 +02:00
|
|
|
/* In uv sync selection, all UVs (from unhidden geometry) are visible. */
|
2022-07-13 11:39:06 +12:00
|
|
|
const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
|
|
|
|
|
|
2012-02-06 19:25:12 +00:00
|
|
|
BMVert *ev;
|
|
|
|
|
BMFace *efa;
|
|
|
|
|
BMIter iter, liter;
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
|
|
|
|
|
const BMUVOffsets offsets = BM_uv_map_get_offsets(bm);
|
|
|
|
|
if (offsets.uv < 0) {
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2022-08-08 11:47:30 +12:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-08 11:47:30 +12:00
|
|
|
/* Count total uvs. */
|
|
|
|
|
int totuv = 0;
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
2022-07-13 11:39:06 +12:00
|
|
|
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!uv_selected) {
|
|
|
|
|
totuv += efa->len;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-08-08 11:47:30 +12:00
|
|
|
BMLoop *l;
|
2022-07-13 11:39:06 +12:00
|
|
|
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if (uvedit_uv_select_test(scene, l, offsets)) {
|
2022-07-13 11:39:06 +12:00
|
|
|
totuv++;
|
2019-12-31 12:56:27 -03:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2013-01-12 20:01:09 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
if (totuv == 0) {
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2012-02-06 19:25:12 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-08 11:47:30 +12:00
|
|
|
UvElementMap *element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
|
2022-08-07 16:11:47 +12:00
|
|
|
element_map->total_uvs = totuv;
|
2022-08-08 11:47:30 +12:00
|
|
|
element_map->vertex = (UvElement **)MEM_callocN(sizeof(*element_map->vertex) * bm->totvert,
|
|
|
|
|
"UvElementVerts");
|
2022-08-08 10:15:13 +12:00
|
|
|
element_map->storage = (UvElement *)MEM_callocN(sizeof(*element_map->storage) * totuv,
|
|
|
|
|
"UvElement");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
bool *winding = use_winding ?
|
|
|
|
|
static_cast<bool *>(MEM_callocN(sizeof(*winding) * bm->totface, "winding")) :
|
|
|
|
|
nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-08 10:15:13 +12:00
|
|
|
UvElement *buf = element_map->storage;
|
2022-08-08 11:47:30 +12:00
|
|
|
int j;
|
2015-04-09 16:12:20 +02:00
|
|
|
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-13 11:39:06 +12:00
|
|
|
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
|
|
|
|
|
continue;
|
2015-06-20 19:28:51 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-13 11:39:06 +12:00
|
|
|
if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-08 11:47:30 +12:00
|
|
|
int i;
|
|
|
|
|
BMLoop *l;
|
2022-07-13 11:39:06 +12:00
|
|
|
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if (uv_selected && !uvedit_uv_select_test(scene, l, offsets)) {
|
2022-07-13 11:39:06 +12:00
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-13 11:39:06 +12:00
|
|
|
buf->l = l;
|
|
|
|
|
buf->island = INVALID_ISLAND;
|
2023-07-24 22:06:55 +02:00
|
|
|
buf->loop_of_face_index = i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-08 11:47:30 +12:00
|
|
|
/* Insert to head of linked list associated with BMVert. */
|
|
|
|
|
buf->next = element_map->vertex[BM_elem_index_get(l->v)];
|
|
|
|
|
element_map->vertex[BM_elem_index_get(l->v)] = buf;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-13 11:39:06 +12:00
|
|
|
buf++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (winding) {
|
2023-01-28 10:50:59 +13:00
|
|
|
winding[j] = BM_face_calc_area_uv_signed(efa, offsets.uv) > 0;
|
2012-02-06 19:25:12 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
GSet *seam_visited_gset = use_seams ? BLI_gset_ptr_new(__func__) : nullptr;
|
2022-09-12 12:22:46 +12:00
|
|
|
|
2022-08-08 11:47:30 +12:00
|
|
|
/* For each BMVert, sort associated linked list into unique uvs. */
|
2022-08-09 09:42:02 +10:00
|
|
|
int ev_index;
|
|
|
|
|
BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, ev_index) {
|
2023-06-13 23:05:45 +02:00
|
|
|
UvElement *newvlist = nullptr;
|
2022-08-09 09:42:02 +10:00
|
|
|
UvElement *vlist = element_map->vertex[ev_index];
|
2012-02-10 18:09:19 +00:00
|
|
|
while (vlist) {
|
2022-08-08 11:47:30 +12:00
|
|
|
|
|
|
|
|
/* Detach head from unsorted list. */
|
|
|
|
|
UvElement *v = vlist;
|
2012-02-10 18:09:19 +00:00
|
|
|
vlist = vlist->next;
|
|
|
|
|
v->next = newvlist;
|
2022-08-08 19:59:33 +12:00
|
|
|
newvlist = v;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
const float *uv = static_cast<const float *>(BM_ELEM_CD_GET_VOID_P(v->l, offsets.uv));
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
bool uv_vert_sel = uvedit_uv_select_test(scene, v->l, offsets);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
UvElement *lastv = nullptr;
|
2022-08-08 11:47:30 +12:00
|
|
|
UvElement *iterv = vlist;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-10 20:13:17 +12:00
|
|
|
/* Scan through unsorted list, finding UvElements which are connected to `v`. */
|
2012-02-10 18:09:19 +00:00
|
|
|
while (iterv) {
|
2022-08-08 11:47:30 +12:00
|
|
|
UvElement *next = iterv->next;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-10 20:13:17 +12:00
|
|
|
bool connected = true; /* Assume connected unless we can prove otherwise. */
|
|
|
|
|
|
|
|
|
|
if (connected) {
|
|
|
|
|
/* Are the two UVs close together? */
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
const float *uv2 = BM_ELEM_CD_GET_FLOAT_P(iterv->l, offsets.uv);
|
2022-08-10 20:13:17 +12:00
|
|
|
connected = compare_v2v2(uv2, uv, STD_UV_CONNECT_LIMIT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (connected) {
|
|
|
|
|
/* Check if the uv loops share the same selection state (if not, they are not connected
|
|
|
|
|
* as they have been ripped or other edit commands have separated them). */
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
const bool uv2_vert_sel = uvedit_uv_select_test(scene, iterv->l, offsets);
|
2022-08-10 20:13:17 +12:00
|
|
|
connected = (uv_vert_sel == uv2_vert_sel);
|
|
|
|
|
}
|
2020-07-14 17:26:13 +02:00
|
|
|
|
2022-08-10 20:13:17 +12:00
|
|
|
if (connected && use_winding) {
|
|
|
|
|
connected = winding[BM_elem_index_get(iterv->l->f)] ==
|
|
|
|
|
winding[BM_elem_index_get(v->l->f)];
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 12:22:46 +12:00
|
|
|
if (connected && use_seams) {
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
connected = seam_connected(iterv->l, v->l, seam_visited_gset, offsets.uv);
|
2022-09-12 12:22:46 +12:00
|
|
|
}
|
|
|
|
|
|
2022-08-10 20:13:17 +12:00
|
|
|
if (connected) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (lastv) {
|
2012-02-10 18:09:19 +00:00
|
|
|
lastv->next = next;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-02-10 18:09:19 +00:00
|
|
|
vlist = next;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-02-10 18:09:19 +00:00
|
|
|
iterv->next = newvlist;
|
|
|
|
|
newvlist = iterv;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
lastv = iterv;
|
2012-02-06 19:25:12 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
iterv = next;
|
2012-02-06 19:25:12 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-08 10:15:13 +12:00
|
|
|
element_map->total_unique_uvs++;
|
|
|
|
|
newvlist->separate = true;
|
2012-02-06 19:25:12 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-08 11:47:30 +12:00
|
|
|
/* Write back sorted list. */
|
2022-08-09 09:42:02 +10:00
|
|
|
element_map->vertex[ev_index] = newvlist;
|
2012-02-06 19:25:12 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-09-12 12:22:46 +12:00
|
|
|
if (seam_visited_gset) {
|
2023-06-13 23:05:45 +02:00
|
|
|
BLI_gset_free(seam_visited_gset, nullptr);
|
|
|
|
|
seam_visited_gset = nullptr;
|
2022-09-12 12:22:46 +12:00
|
|
|
}
|
2022-08-08 11:47:30 +12:00
|
|
|
MEM_SAFE_FREE(winding);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-10 20:13:17 +12:00
|
|
|
/* at this point, every UvElement in vert points to a UvElement sharing the same vertex.
|
|
|
|
|
* Now we should sort uv's in islands. */
|
2012-02-05 15:55:28 +00:00
|
|
|
if (do_islands) {
|
2022-08-10 20:13:17 +12:00
|
|
|
bm_uv_build_islands(element_map, bm, scene, uv_selected);
|
2012-01-17 21:08:25 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-08-10 20:13:17 +12:00
|
|
|
/* TODO: Confirm element_map->total_unique_uvs doesn't require recalculating. */
|
2022-08-07 16:11:47 +12:00
|
|
|
element_map->total_unique_uvs = 0;
|
|
|
|
|
for (int i = 0; i < element_map->total_uvs; i++) {
|
2022-08-08 10:15:13 +12:00
|
|
|
if (element_map->storage[i].separate) {
|
2022-08-07 16:11:47 +12:00
|
|
|
element_map->total_unique_uvs++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-06 19:25:12 +00:00
|
|
|
return element_map;
|
2012-01-17 21:08:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
void BM_uv_vert_map_free(UvVertMap *vmap)
|
2009-07-21 08:39:58 +00:00
|
|
|
{
|
|
|
|
|
if (vmap) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (vmap->vert) {
|
2009-07-21 08:39:58 +00:00
|
|
|
MEM_freeN(vmap->vert);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
if (vmap->buf) {
|
2009-07-21 08:39:58 +00:00
|
|
|
MEM_freeN(vmap->buf);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-21 08:39:58 +00:00
|
|
|
MEM_freeN(vmap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
void BM_uv_element_map_free(UvElementMap *element_map)
|
2012-01-17 21:08:25 +00:00
|
|
|
{
|
2012-02-06 19:25:12 +00:00
|
|
|
if (element_map) {
|
2022-08-08 10:15:13 +12:00
|
|
|
MEM_SAFE_FREE(element_map->storage);
|
2022-08-08 11:47:30 +12:00
|
|
|
MEM_SAFE_FREE(element_map->vertex);
|
2022-08-11 11:20:00 +12:00
|
|
|
MEM_SAFE_FREE(element_map->head_table);
|
2022-11-09 11:42:30 +13:00
|
|
|
MEM_SAFE_FREE(element_map->unique_index_table);
|
2022-08-11 14:18:31 +12:00
|
|
|
MEM_SAFE_FREE(element_map->island_indices);
|
|
|
|
|
MEM_SAFE_FREE(element_map->island_total_uvs);
|
|
|
|
|
MEM_SAFE_FREE(element_map->island_total_unique_uvs);
|
2022-08-08 10:15:13 +12:00
|
|
|
MEM_SAFE_FREE(element_map);
|
2012-01-17 21:08:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-21 08:39:58 +00:00
|
|
|
|
2023-05-22 23:23:23 +02:00
|
|
|
UvElement *BM_uv_element_get(const UvElementMap *element_map, const BMLoop *l)
|
2012-10-22 07:29:38 +00:00
|
|
|
{
|
2022-08-08 11:47:30 +12:00
|
|
|
UvElement *element = element_map->vertex[BM_elem_index_get(l->v)];
|
|
|
|
|
while (element) {
|
2023-05-22 23:23:23 +02:00
|
|
|
if (element->l == l) {
|
2012-10-22 07:29:38 +00:00
|
|
|
return element;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2022-08-08 11:47:30 +12:00
|
|
|
element = element->next;
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2012-10-22 07:29:38 +00:00
|
|
|
}
|
|
|
|
|
|
2022-08-08 11:47:30 +12:00
|
|
|
UvElement *BM_uv_element_get_head(UvElementMap *element_map, UvElement *child)
|
|
|
|
|
{
|
|
|
|
|
if (!child) {
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2022-08-08 11:47:30 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return element_map->vertex[BM_elem_index_get(child->l->v)];
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Data Layer Checks
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2017-05-25 15:11:00 +10:00
|
|
|
BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
|
2009-07-21 08:39:58 +00:00
|
|
|
{
|
2018-03-12 14:51:45 +11:00
|
|
|
if (!EDBM_uv_check(em)) {
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2018-03-12 14:51:45 +11:00
|
|
|
}
|
2023-01-25 12:56:05 -06:00
|
|
|
BMFace *efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
|
2009-07-21 08:39:58 +00:00
|
|
|
if (efa) {
|
2017-05-25 00:34:14 +10:00
|
|
|
return efa;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2009-07-21 08:39:58 +00:00
|
|
|
}
|
|
|
|
|
|
2017-05-25 15:11:00 +10:00
|
|
|
bool EDBM_uv_check(BMEditMesh *em)
|
2009-07-21 08:39:58 +00:00
|
|
|
{
|
|
|
|
|
/* some of these checks could be a touch overkill */
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_PROP_FLOAT2);
|
2009-07-21 11:48:58 +00:00
|
|
|
}
|
2009-08-28 10:17:31 +00:00
|
|
|
|
2013-04-05 14:58:30 +00:00
|
|
|
bool EDBM_vert_color_check(BMEditMesh *em)
|
2009-08-28 10:17:31 +00:00
|
|
|
{
|
|
|
|
|
/* some of these checks could be a touch overkill */
|
2022-04-20 09:10:10 -05:00
|
|
|
return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_PROP_BYTE_COLOR);
|
2009-08-28 10:17:31 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Mirror Cache API
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2020-07-13 11:27:09 +02:00
|
|
|
static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int index)
|
2011-12-20 22:01:11 +00:00
|
|
|
{
|
2012-02-10 18:09:19 +00:00
|
|
|
intptr_t eve_i = index_lookup[index];
|
2023-06-13 23:05:45 +02:00
|
|
|
return (eve_i == -1) ? nullptr : (BMVert *)eve_i;
|
2011-12-20 22:01:11 +00:00
|
|
|
}
|
|
|
|
|
|
2012-03-27 04:46:52 +00:00
|
|
|
/**
|
2015-05-27 00:00:31 +10:00
|
|
|
* Mirror editing API, usage:
|
2012-03-27 04:46:52 +00:00
|
|
|
*
|
2015-05-27 00:00:31 +10:00
|
|
|
* \code{.c}
|
|
|
|
|
* EDBM_verts_mirror_cache_begin(em, ...);
|
2012-03-27 04:46:52 +00:00
|
|
|
*
|
2015-05-27 00:00:31 +10:00
|
|
|
* BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
|
|
|
|
|
* v_mirror = EDBM_verts_mirror_get(em, v);
|
|
|
|
|
* e_mirror = EDBM_verts_mirror_get_edge(em, e);
|
|
|
|
|
* f_mirror = EDBM_verts_mirror_get_face(em, f);
|
|
|
|
|
* }
|
2012-03-27 04:46:52 +00:00
|
|
|
*
|
2015-05-27 00:00:31 +10:00
|
|
|
* EDBM_verts_mirror_cache_end(em);
|
|
|
|
|
* \endcode
|
2012-03-27 04:46:52 +00:00
|
|
|
*/
|
|
|
|
|
|
2021-12-09 00:55:11 +11:00
|
|
|
/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a preference. */
|
2011-10-26 07:41:56 +00:00
|
|
|
#define BM_SEARCH_MAXDIST_MIRR 0.00002f
|
2011-10-28 06:23:12 +00:00
|
|
|
#define BM_CD_LAYER_ID "__mirror_index"
|
2021-12-09 00:55:11 +11:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
|
|
|
|
|
const int axis,
|
|
|
|
|
const bool use_self,
|
|
|
|
|
const bool use_select,
|
2020-09-01 12:13:25 -03:00
|
|
|
const bool respecthide,
|
2018-03-16 20:46:14 +11:00
|
|
|
/* extra args */
|
|
|
|
|
const bool use_topology,
|
|
|
|
|
float maxdist,
|
|
|
|
|
int *r_index)
|
2010-03-11 05:30:01 +00:00
|
|
|
{
|
2011-12-21 00:09:44 +00:00
|
|
|
BMesh *bm = em->bm;
|
2010-03-11 05:30:01 +00:00
|
|
|
BMIter iter;
|
|
|
|
|
BMVert *v;
|
2018-05-02 10:32:01 +02:00
|
|
|
int cd_vmirr_offset = 0;
|
2013-06-19 18:22:00 +00:00
|
|
|
int i;
|
2020-03-06 17:18:10 +01:00
|
|
|
const float maxdist_sq = square_f(maxdist);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-12-20 22:01:11 +00:00
|
|
|
/* one or the other is used depending if topo is enabled */
|
2023-06-13 23:05:45 +02:00
|
|
|
KDTree_3d *tree = nullptr;
|
|
|
|
|
MirrTopoStore_t mesh_topo_store = {nullptr, -1, -1, false};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
BM_mesh_elem_table_ensure(bm, BM_VERT);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
if (r_index == nullptr) {
|
2013-06-19 18:22:00 +00:00
|
|
|
const char *layer_id = BM_CD_LAYER_ID;
|
2020-06-10 15:47:31 +02:00
|
|
|
em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT32, layer_id);
|
2013-06-19 18:22:00 +00:00
|
|
|
if (em->mirror_cdlayer == -1) {
|
2020-06-10 15:47:31 +02:00
|
|
|
BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT32, layer_id);
|
|
|
|
|
em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT32, layer_id);
|
2013-06-19 18:22:00 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
cd_vmirr_offset = CustomData_get_n_offset(
|
|
|
|
|
&bm->vdata,
|
2020-06-10 15:47:31 +02:00
|
|
|
CD_PROP_INT32,
|
|
|
|
|
em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT32));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-19 18:22:00 +00:00
|
|
|
bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-12 10:51:45 +00:00
|
|
|
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-28 17:13:09 +00:00
|
|
|
if (use_topology) {
|
2023-06-13 23:05:45 +02:00
|
|
|
ED_mesh_mirrtopo_init(em, nullptr, &mesh_topo_store, true);
|
2011-12-20 22:01:11 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2019-03-20 00:46:33 +11:00
|
|
|
tree = BLI_kdtree_3d_new(bm->totvert);
|
2015-05-21 13:01:44 +10:00
|
|
|
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
2020-09-01 12:13:25 -03:00
|
|
|
if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-20 00:46:33 +11:00
|
|
|
BLI_kdtree_3d_insert(tree, i, v->co);
|
2015-05-21 13:01:44 +10:00
|
|
|
}
|
2019-03-20 00:46:33 +11:00
|
|
|
BLI_kdtree_3d_balance(tree);
|
2011-12-20 22:01:11 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
#define VERT_INTPTR(_v, _i) \
|
|
|
|
|
(r_index ? &r_index[_i] : static_cast<int *>(BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset)))
|
2013-06-19 18:22:00 +00:00
|
|
|
|
|
|
|
|
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
2020-09-01 12:13:25 -03:00
|
|
|
if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-02-12 10:51:45 +00:00
|
|
|
if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) {
|
2020-09-01 12:13:25 -03:00
|
|
|
continue;
|
2011-10-26 07:41:56 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-01 12:13:25 -03:00
|
|
|
BLI_assert(BM_elem_index_get(v) == i);
|
|
|
|
|
BMVert *v_mirr;
|
|
|
|
|
int *idx = VERT_INTPTR(v, i);
|
|
|
|
|
|
|
|
|
|
if (use_topology) {
|
|
|
|
|
v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i);
|
2023-06-13 23:05:45 +02:00
|
|
|
if (v_mirr != nullptr) {
|
2020-12-15 18:07:12 +11:00
|
|
|
if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) {
|
2023-06-13 23:05:45 +02:00
|
|
|
v_mirr = nullptr;
|
2020-12-15 18:07:12 +11:00
|
|
|
}
|
2020-11-30 16:45:47 +01:00
|
|
|
}
|
2020-09-01 12:13:25 -03:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int i_mirr;
|
|
|
|
|
float co[3];
|
|
|
|
|
copy_v3_v3(co, v->co);
|
|
|
|
|
co[axis] *= -1.0f;
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
v_mirr = nullptr;
|
|
|
|
|
i_mirr = BLI_kdtree_3d_find_nearest(tree, co, nullptr);
|
2020-09-01 12:13:25 -03:00
|
|
|
if (i_mirr != -1) {
|
|
|
|
|
BMVert *v_test = BM_vert_at_index(bm, i_mirr);
|
|
|
|
|
if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
|
|
|
|
|
v_mirr = v_test;
|
2011-12-21 00:09:44 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2020-09-01 12:13:25 -03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-01 12:13:25 -03:00
|
|
|
if (v_mirr && (use_self || (v_mirr != v))) {
|
|
|
|
|
const int i_mirr = BM_elem_index_get(v_mirr);
|
|
|
|
|
*idx = i_mirr;
|
|
|
|
|
idx = VERT_INTPTR(v_mirr, i_mirr);
|
|
|
|
|
*idx = i;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
*idx = -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-19 18:22:00 +00:00
|
|
|
#undef VERT_INTPTR
|
2011-12-20 22:01:11 +00:00
|
|
|
|
2013-06-28 17:13:09 +00:00
|
|
|
if (use_topology) {
|
2011-12-20 22:01:11 +00:00
|
|
|
ED_mesh_mirrtopo_free(&mesh_topo_store);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-03-20 00:46:33 +11:00
|
|
|
BLI_kdtree_3d_free(tree);
|
2011-12-20 22:01:11 +00:00
|
|
|
}
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
void EDBM_verts_mirror_cache_begin(BMEditMesh *em,
|
|
|
|
|
const int axis,
|
|
|
|
|
const bool use_self,
|
|
|
|
|
const bool use_select,
|
2020-09-01 12:13:25 -03:00
|
|
|
const bool respecthide,
|
2018-03-16 20:46:14 +11:00
|
|
|
const bool use_topology)
|
2013-06-19 18:22:00 +00:00
|
|
|
{
|
2018-03-16 20:46:14 +11:00
|
|
|
EDBM_verts_mirror_cache_begin_ex(em,
|
|
|
|
|
axis,
|
|
|
|
|
use_self,
|
|
|
|
|
use_select,
|
2020-09-01 12:13:25 -03:00
|
|
|
respecthide,
|
2018-03-16 20:46:14 +11:00
|
|
|
/* extra args */
|
|
|
|
|
use_topology,
|
|
|
|
|
BM_SEARCH_MAXDIST_MIRR,
|
2023-06-13 23:05:45 +02:00
|
|
|
nullptr);
|
2013-06-19 18:22:00 +00:00
|
|
|
}
|
|
|
|
|
|
2012-03-27 04:46:52 +00:00
|
|
|
BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
|
2010-03-11 05:30:01 +00:00
|
|
|
{
|
2023-06-13 23:05:45 +02:00
|
|
|
const int *mirr = static_cast<const int *>(
|
|
|
|
|
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 */
|
|
|
|
|
|
2012-02-10 18:09:19 +00:00
|
|
|
if (mirr && *mirr >= 0 && *mirr < em->bm->totvert) {
|
2013-10-28 02:05:33 +00:00
|
|
|
if (!em->bm->vtable) {
|
2010-03-11 05:30:01 +00:00
|
|
|
printf(
|
|
|
|
|
"err: should only be called between "
|
2012-03-27 04:46:52 +00:00
|
|
|
"EDBM_verts_mirror_cache_begin and EDBM_verts_mirror_cache_end");
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-28 02:05:33 +00:00
|
|
|
return em->bm->vtable[*mirr];
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
2013-07-01 21:56:59 +00:00
|
|
|
BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e)
|
|
|
|
|
{
|
2021-06-23 20:05:52 +10:00
|
|
|
BMVert *v1_mirr, *v2_mirr;
|
|
|
|
|
if ((v1_mirr = EDBM_verts_mirror_get(em, e->v1)) &&
|
|
|
|
|
(v2_mirr = EDBM_verts_mirror_get(em, e->v2)) &&
|
2023-02-12 14:37:16 +11:00
|
|
|
/* While highly unlikely, a zero length central edges vertices can match, see #89342. */
|
2021-06-23 20:05:52 +10:00
|
|
|
LIKELY(v1_mirr != v2_mirr))
|
|
|
|
|
{
|
|
|
|
|
return BM_edge_exists(v1_mirr, v2_mirr);
|
2013-07-01 21:56:59 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2013-07-01 21:56:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
|
|
|
|
|
{
|
2023-06-13 23:05:45 +02:00
|
|
|
blender::Array<BMVert *, BM_DEFAULT_NGON_STACK_SIZE> v_mirr_arr(f->len);
|
2013-07-01 21:56:59 +00:00
|
|
|
|
|
|
|
|
BMLoop *l_iter, *l_first;
|
2020-04-03 16:21:24 +11:00
|
|
|
uint i = 0;
|
2013-07-01 21:56:59 +00:00
|
|
|
|
|
|
|
|
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
|
|
|
|
|
do {
|
2023-06-13 23:05:45 +02:00
|
|
|
if ((v_mirr_arr[i++] = EDBM_verts_mirror_get(em, l_iter->v)) == nullptr) {
|
|
|
|
|
return nullptr;
|
2013-07-01 21:56:59 +00:00
|
|
|
}
|
|
|
|
|
} while ((l_iter = l_iter->next) != l_first);
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
return BM_face_exists(v_mirr_arr.data(), v_mirr_arr.size());
|
2013-07-01 21:56:59 +00:00
|
|
|
}
|
|
|
|
|
|
2012-03-27 04:46:52 +00:00
|
|
|
void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v)
|
2011-11-01 05:43:35 +00:00
|
|
|
{
|
2023-06-13 23:05:45 +02:00
|
|
|
int *mirr = static_cast<int *>(
|
|
|
|
|
CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer));
|
2011-11-01 05:43:35 +00:00
|
|
|
|
|
|
|
|
BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
|
|
|
|
|
|
|
|
|
|
if (mirr) {
|
2012-02-10 18:09:19 +00:00
|
|
|
*mirr = -1;
|
2011-11-01 05:43:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-27 04:46:52 +00:00
|
|
|
void EDBM_verts_mirror_cache_end(BMEditMesh *em)
|
2010-03-11 05:30:01 +00:00
|
|
|
{
|
2012-02-10 18:09:19 +00:00
|
|
|
em->mirror_cdlayer = -1;
|
2010-03-11 05:30:01 +00:00
|
|
|
}
|
2011-10-26 07:41:56 +00:00
|
|
|
|
2012-03-27 04:46:52 +00:00
|
|
|
void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_to)
|
2011-10-26 07:41:56 +00:00
|
|
|
{
|
|
|
|
|
BMIter iter;
|
|
|
|
|
BMVert *v;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
BLI_assert((em->bm->vtable != nullptr) && ((em->bm->elem_table_dirty & BM_VERT) == 0));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
|
2012-02-12 10:51:45 +00:00
|
|
|
if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) {
|
2012-03-27 04:46:52 +00:00
|
|
|
BMVert *mirr = EDBM_verts_mirror_get(em, v);
|
2011-10-26 07:41:56 +00:00
|
|
|
if (mirr) {
|
2012-02-12 10:51:45 +00:00
|
|
|
if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) {
|
2011-10-26 07:41:56 +00:00
|
|
|
copy_v3_v3(mirr->co, v->co);
|
|
|
|
|
mirr->co[0] *= -1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-23 23:41:33 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Hide/Reveal API
|
|
|
|
|
* \{ */
|
2012-03-23 23:41:33 +00:00
|
|
|
|
2019-02-14 17:50:41 +11:00
|
|
|
bool EDBM_mesh_hide(BMEditMesh *em, bool swap)
|
2012-03-23 23:41:33 +00:00
|
|
|
{
|
|
|
|
|
BMIter iter;
|
|
|
|
|
BMElem *ele;
|
|
|
|
|
int itermode;
|
2013-04-05 14:58:30 +00:00
|
|
|
char hflag_swap = swap ? BM_ELEM_SELECT : 0;
|
2019-02-14 17:50:41 +11:00
|
|
|
bool changed = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (em->selectmode & SCE_SELECT_VERTEX) {
|
2012-03-23 23:41:33 +00:00
|
|
|
itermode = BM_VERTS_OF_MESH;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else if (em->selectmode & SCE_SELECT_EDGE) {
|
2012-03-23 23:41:33 +00:00
|
|
|
itermode = BM_EDGES_OF_MESH;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2012-03-23 23:41:33 +00:00
|
|
|
itermode = BM_FACES_OF_MESH;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-19 12:45:56 +00:00
|
|
|
BM_ITER_MESH (ele, &iter, em->bm, itermode) {
|
2019-02-14 17:50:41 +11:00
|
|
|
if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
|
|
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT) ^ hflag_swap) {
|
|
|
|
|
BM_elem_hide_set(em->bm, ele, true);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-23 23:41:33 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-14 17:50:41 +11:00
|
|
|
if (changed) {
|
|
|
|
|
EDBM_selectmode_flush(em);
|
|
|
|
|
}
|
|
|
|
|
return changed;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-23 23:41:33 +00:00
|
|
|
/* original hide flushing comment (OUTDATED):
|
2019-01-15 23:24:20 +11:00
|
|
|
* hide happens on least dominant select mode, and flushes up, not down!
|
|
|
|
|
* (helps preventing errors in subsurf) */
|
2012-03-23 23:41:33 +00:00
|
|
|
/* - vertex hidden, always means edge is hidden too
|
|
|
|
|
* - edge hidden, always means face is hidden too
|
|
|
|
|
* - face hidden, only set face hide
|
|
|
|
|
* - then only flush back down what's absolute hidden
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-14 17:50:41 +11:00
|
|
|
bool EDBM_mesh_reveal(BMEditMesh *em, bool select)
|
2012-03-23 23:41:33 +00:00
|
|
|
{
|
2018-03-16 20:46:14 +11:00
|
|
|
const char iter_types[3] = {
|
|
|
|
|
BM_VERTS_OF_MESH,
|
|
|
|
|
BM_EDGES_OF_MESH,
|
|
|
|
|
BM_FACES_OF_MESH,
|
|
|
|
|
};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-04-27 07:50:08 +10:00
|
|
|
const bool sels[3] = {
|
2018-03-16 20:46:14 +11:00
|
|
|
(em->selectmode & SCE_SELECT_VERTEX) != 0,
|
|
|
|
|
(em->selectmode & SCE_SELECT_EDGE) != 0,
|
|
|
|
|
(em->selectmode & SCE_SELECT_FACE) != 0,
|
2014-04-27 07:50:08 +10:00
|
|
|
};
|
2012-03-23 23:41:33 +00:00
|
|
|
int i;
|
2019-02-14 17:50:41 +11:00
|
|
|
bool changed = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-23 23:41:33 +00:00
|
|
|
/* Use tag flag to remember what was hidden before all is revealed.
|
|
|
|
|
* BM_ELEM_HIDDEN --> BM_ELEM_TAG */
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
2012-12-21 06:06:17 +00:00
|
|
|
BMIter iter;
|
|
|
|
|
BMElem *ele;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-19 12:45:56 +00:00
|
|
|
BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) {
|
2019-02-14 17:50:41 +11:00
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
|
|
|
|
|
BM_elem_flag_enable(ele, BM_ELEM_TAG);
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BM_elem_flag_disable(ele, BM_ELEM_TAG);
|
|
|
|
|
}
|
2012-03-23 23:41:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-14 17:50:41 +11:00
|
|
|
if (!changed) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-23 23:41:33 +00:00
|
|
|
/* Reveal everything */
|
|
|
|
|
EDBM_flag_disable_all(em, BM_ELEM_HIDDEN);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-23 23:41:33 +00:00
|
|
|
/* Select relevant just-revealed elements */
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
2012-12-21 06:06:17 +00:00
|
|
|
BMIter iter;
|
|
|
|
|
BMElem *ele;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-23 23:41:33 +00:00
|
|
|
if (!sels[i]) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-19 12:45:56 +00:00
|
|
|
BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) {
|
2012-03-23 23:41:33 +00:00
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_TAG)) {
|
2017-11-20 02:28:07 +11:00
|
|
|
BM_elem_select_set(em->bm, ele, select);
|
2012-03-23 23:41:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-23 23:41:33 +00:00
|
|
|
EDBM_selectmode_flush(em);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-30 01:11:11 +00:00
|
|
|
/* hidden faces can have invalid normals */
|
|
|
|
|
EDBM_mesh_normals_update(em);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-02-14 17:50:41 +11:00
|
|
|
return true;
|
2012-03-23 23:41:33 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Update API
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
void EDBM_mesh_normals_update_ex(BMEditMesh *em, const BMeshNormalsUpdate_Params *params)
|
2021-06-14 22:56:03 +10:00
|
|
|
{
|
|
|
|
|
BM_mesh_normals_update_ex(em->bm, params);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
void EDBM_mesh_normals_update(BMEditMesh *em)
|
|
|
|
|
{
|
2023-06-13 23:05:45 +02:00
|
|
|
BMeshNormalsUpdate_Params params{};
|
|
|
|
|
params.face_normals = true;
|
|
|
|
|
EDBM_mesh_normals_update_ex(em, ¶ms);
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EDBM_stats_update(BMEditMesh *em)
|
|
|
|
|
{
|
|
|
|
|
const char iter_types[3] = {
|
|
|
|
|
BM_VERTS_OF_MESH,
|
|
|
|
|
BM_EDGES_OF_MESH,
|
|
|
|
|
BM_FACES_OF_MESH,
|
|
|
|
|
};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
BMIter iter;
|
|
|
|
|
BMElem *ele;
|
|
|
|
|
int *tots[3];
|
|
|
|
|
int i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
tots[0] = &em->bm->totvertsel;
|
|
|
|
|
tots[1] = &em->bm->totedgesel;
|
|
|
|
|
tots[2] = &em->bm->totfacesel;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
for (i = 0; i < 3; i++) {
|
2023-06-13 23:05:45 +02:00
|
|
|
ele = static_cast<BMElem *>(BM_iter_new(&iter, em->bm, iter_types[i], nullptr));
|
|
|
|
|
for (; ele; ele = static_cast<BMElem *>(BM_iter_step(&iter))) {
|
2018-03-16 20:46:14 +11:00
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
|
|
|
|
(*tots[i])++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
void EDBM_update(Mesh *mesh, const EDBMUpdate_Params *params)
|
2012-03-27 00:01:35 +00:00
|
|
|
{
|
2024-03-21 23:18:49 +01:00
|
|
|
BMEditMesh *em = mesh->runtime->edit_mesh;
|
2020-01-07 22:11:19 +11:00
|
|
|
/* Order of calling isn't important. */
|
|
|
|
|
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
|
|
|
|
|
WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-14 12:08:21 +11:00
|
|
|
if (params->calc_normals && params->calc_looptris) {
|
2021-06-14 22:56:03 +10:00
|
|
|
/* Calculating both has some performance gains. */
|
2023-12-14 12:08:21 +11:00
|
|
|
BKE_editmesh_looptris_and_normals_calc(em);
|
2021-06-14 22:56:01 +10:00
|
|
|
}
|
2021-06-14 22:56:03 +10:00
|
|
|
else {
|
|
|
|
|
if (params->calc_normals) {
|
|
|
|
|
EDBM_mesh_normals_update(em);
|
|
|
|
|
}
|
2021-06-14 22:56:01 +10:00
|
|
|
|
2023-12-14 12:08:21 +11:00
|
|
|
if (params->calc_looptris) {
|
|
|
|
|
BKE_editmesh_looptris_calc(em);
|
2021-06-14 22:56:03 +10:00
|
|
|
}
|
2012-03-27 00:01:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-14 22:56:01 +10:00
|
|
|
if (params->is_destructive) {
|
2023-02-09 11:30:25 +11:00
|
|
|
/* TODO(@ideasman42): we may be able to remove this now! */
|
2013-10-28 02:05:33 +00:00
|
|
|
// BM_mesh_elem_table_free(em->bm, BM_ALL_NOLOOP);
|
2012-12-12 06:53:39 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* in debug mode double check we didn't need to recalculate */
|
2013-10-28 02:05:33 +00:00
|
|
|
BLI_assert(BM_mesh_elem_table_check(em->bm) == true);
|
2012-12-12 06:53:39 +00:00
|
|
|
}
|
2018-05-25 22:24:24 +05:30
|
|
|
if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) {
|
|
|
|
|
BM_lnorspace_invalidate(em->bm, false);
|
|
|
|
|
em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
|
|
|
|
|
}
|
2014-08-25 16:48:47 +10:00
|
|
|
|
2023-12-04 15:13:06 +01:00
|
|
|
#ifndef NDEBUG
|
2014-08-25 16:48:47 +10:00
|
|
|
{
|
2023-06-13 17:50:31 -04:00
|
|
|
LISTBASE_FOREACH (BMEditSelection *, ese, &em->bm->selected) {
|
2014-08-25 16:48:47 +10:00
|
|
|
BLI_assert(BM_elem_flag_test(ese->ele, BM_ELEM_SELECT));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2012-03-27 00:01:35 +00:00
|
|
|
}
|
2013-04-01 10:18:01 +00:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
void EDBM_update_extern(Mesh *mesh, const bool do_tessellation, const bool is_destructive)
|
2021-06-14 22:56:01 +10:00
|
|
|
{
|
2023-06-13 23:05:45 +02:00
|
|
|
EDBMUpdate_Params params{};
|
2023-12-14 12:08:21 +11:00
|
|
|
params.calc_looptris = do_tessellation;
|
2023-06-13 23:05:45 +02:00
|
|
|
params.calc_normals = false;
|
|
|
|
|
params.is_destructive = is_destructive;
|
2023-12-08 16:40:06 -05:00
|
|
|
EDBM_update(mesh, ¶ms);
|
2021-06-14 22:56:01 +10:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Operator Helpers
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
bool EDBM_view3d_poll(bContext *C)
|
2013-04-01 10:18:01 +00:00
|
|
|
{
|
2018-03-16 20:46:14 +11:00
|
|
|
if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) {
|
2023-01-25 12:56:05 -06:00
|
|
|
return true;
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2013-04-01 10:18:01 +00:00
|
|
|
|
2023-01-25 12:56:05 -06:00
|
|
|
return false;
|
2013-04-01 10:18:01 +00:00
|
|
|
}
|
2013-04-16 05:23:34 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name BMesh Element API
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2015-12-28 21:26:02 +11:00
|
|
|
BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
|
|
|
|
|
{
|
|
|
|
|
if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
|
2023-01-25 12:56:05 -06:00
|
|
|
return (BMElem *)eve;
|
2015-12-28 21:26:02 +11:00
|
|
|
}
|
2023-01-25 12:56:05 -06:00
|
|
|
if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
|
|
|
|
|
return (BMElem *)eed;
|
2015-12-28 21:26:02 +11:00
|
|
|
}
|
2023-01-25 12:56:05 -06:00
|
|
|
if ((em->selectmode & SCE_SELECT_FACE) && efa) {
|
|
|
|
|
return (BMElem *)efa;
|
2015-12-28 21:26:02 +11:00
|
|
|
}
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2015-12-28 21:26:02 +11:00
|
|
|
}
|
|
|
|
|
|
2015-12-27 18:03:20 +11:00
|
|
|
int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
|
|
|
|
|
{
|
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
|
int index = BM_elem_index_get(ele);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:03:20 +11:00
|
|
|
if (ele->head.htype == BM_VERT) {
|
|
|
|
|
BLI_assert(!(bm->elem_index_dirty & BM_VERT));
|
|
|
|
|
}
|
|
|
|
|
else if (ele->head.htype == BM_EDGE) {
|
|
|
|
|
BLI_assert(!(bm->elem_index_dirty & BM_EDGE));
|
|
|
|
|
index += bm->totvert;
|
|
|
|
|
}
|
|
|
|
|
else if (ele->head.htype == BM_FACE) {
|
|
|
|
|
BLI_assert(!(bm->elem_index_dirty & BM_FACE));
|
|
|
|
|
index += bm->totvert + bm->totedge;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(0);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:03:20 +11:00
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-23 19:44:44 +10:00
|
|
|
BMElem *EDBM_elem_from_index_any(BMEditMesh *em, uint index)
|
2015-12-27 18:03:20 +11:00
|
|
|
{
|
|
|
|
|
BMesh *bm = em->bm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:03:20 +11:00
|
|
|
if (index < bm->totvert) {
|
|
|
|
|
return (BMElem *)BM_vert_at_index_find_or_table(bm, index);
|
|
|
|
|
}
|
|
|
|
|
index -= bm->totvert;
|
|
|
|
|
if (index < bm->totedge) {
|
|
|
|
|
return (BMElem *)BM_edge_at_index_find_or_table(bm, index);
|
|
|
|
|
}
|
|
|
|
|
index -= bm->totedge;
|
|
|
|
|
if (index < bm->totface) {
|
|
|
|
|
return (BMElem *)BM_face_at_index_find_or_table(bm, index);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2015-12-27 18:03:20 +11:00
|
|
|
}
|
2013-04-18 01:20:04 +00:00
|
|
|
|
2022-09-14 21:30:20 +02:00
|
|
|
int EDBM_elem_to_index_any_multi(
|
|
|
|
|
const Scene *scene, ViewLayer *view_layer, BMEditMesh *em, BMElem *ele, int *r_object_index)
|
2020-10-13 16:51:20 +11:00
|
|
|
{
|
|
|
|
|
int elem_index = -1;
|
|
|
|
|
*r_object_index = -1;
|
2024-01-24 18:18:14 +01:00
|
|
|
Vector<Base *> bases = BKE_view_layer_array_from_bases_in_edit_mode(scene, view_layer, nullptr);
|
|
|
|
|
for (const int base_index : bases.index_range()) {
|
2020-10-13 16:51:20 +11:00
|
|
|
Base *base_iter = bases[base_index];
|
|
|
|
|
if (BKE_editmesh_from_object(base_iter->object) == em) {
|
|
|
|
|
*r_object_index = base_index;
|
|
|
|
|
elem_index = EDBM_elem_to_index_any(em, ele);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return elem_index;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-14 21:30:20 +02:00
|
|
|
BMElem *EDBM_elem_from_index_any_multi(const Scene *scene,
|
|
|
|
|
ViewLayer *view_layer,
|
2021-06-23 19:44:44 +10:00
|
|
|
uint object_index,
|
|
|
|
|
uint elem_index,
|
2020-10-13 16:51:20 +11:00
|
|
|
Object **r_obedit)
|
|
|
|
|
{
|
2024-01-24 18:18:14 +01:00
|
|
|
Vector<Base *> bases = BKE_view_layer_array_from_bases_in_edit_mode(scene, view_layer, nullptr);
|
2023-06-13 23:05:45 +02:00
|
|
|
*r_obedit = nullptr;
|
2024-01-24 18:18:14 +01:00
|
|
|
Object *obedit = (object_index < bases.size()) ? bases[object_index]->object : nullptr;
|
2023-06-13 23:05:45 +02:00
|
|
|
if (obedit != nullptr) {
|
2020-10-13 16:51:20 +11:00
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
|
|
|
|
BMElem *ele = EDBM_elem_from_index_any(em, elem_index);
|
2023-06-13 23:05:45 +02:00
|
|
|
if (ele != nullptr) {
|
2020-10-13 16:51:20 +11:00
|
|
|
*r_obedit = obedit;
|
|
|
|
|
return ele;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2020-10-13 16:51:20 +11:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
2013-04-16 05:23:34 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name BMesh BVH API
|
|
|
|
|
* \{ */
|
2013-04-16 05:23:34 +00:00
|
|
|
|
|
|
|
|
static BMFace *edge_ray_cast(
|
2023-06-03 08:36:28 +10:00
|
|
|
BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
|
2013-04-16 05:23:34 +00:00
|
|
|
{
|
2023-06-13 23:05:45 +02:00
|
|
|
BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, nullptr, r_hitout, nullptr);
|
2013-04-16 05:23:34 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
if (f && BM_edge_in_face(e, f)) {
|
2023-06-13 23:05:45 +02:00
|
|
|
return nullptr;
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2013-04-16 05:23:34 +00:00
|
|
|
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void scale_point(float c1[3], const float p[3], const float s)
|
|
|
|
|
{
|
|
|
|
|
sub_v3_v3(c1, p);
|
|
|
|
|
mul_v3_fl(c1, s);
|
|
|
|
|
add_v3_v3(c1, p);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-03 08:36:28 +10:00
|
|
|
bool BMBVH_EdgeVisible(
|
|
|
|
|
BMBVHTree *tree, BMEdge *e, Depsgraph *depsgraph, ARegion *region, View3D *v3d, Object *obedit)
|
2013-04-16 05:23:34 +00:00
|
|
|
{
|
|
|
|
|
BMFace *f;
|
|
|
|
|
float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3];
|
|
|
|
|
float origin[3], invmat[4][4];
|
|
|
|
|
float epsilon = 0.01f;
|
|
|
|
|
float end[3];
|
2018-03-16 20:46:14 +11:00
|
|
|
const float mval_f[2] = {
|
2020-03-06 16:56:42 +01:00
|
|
|
region->winx / 2.0f,
|
|
|
|
|
region->winy / 2.0f,
|
2018-03-16 20:46:14 +11:00
|
|
|
};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_view3d_win_to_segment_clipped(depsgraph, region, v3d, mval_f, origin, end, false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-02-14 16:14:49 +01:00
|
|
|
invert_m4_m4(invmat, obedit->object_to_world().ptr());
|
2013-04-16 05:23:34 +00:00
|
|
|
mul_m4_v3(invmat, origin);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-04-16 05:23:34 +00:00
|
|
|
copy_v3_v3(co1, e->v1->co);
|
|
|
|
|
mid_v3_v3v3(co2, e->v1->co, e->v2->co);
|
|
|
|
|
copy_v3_v3(co3, e->v2->co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-04-16 05:23:34 +00:00
|
|
|
scale_point(co1, co2, 0.99);
|
|
|
|
|
scale_point(co3, co2, 0.99);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* OK, idea is to generate rays going from the camera origin to the
|
|
|
|
|
* three points on the edge (v1, mid, v2). */
|
2013-04-16 05:23:34 +00:00
|
|
|
sub_v3_v3v3(dir1, origin, co1);
|
|
|
|
|
sub_v3_v3v3(dir2, origin, co2);
|
|
|
|
|
sub_v3_v3v3(dir3, origin, co3);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-08 10:14:49 +10:00
|
|
|
normalize_v3_length(dir1, epsilon);
|
|
|
|
|
normalize_v3_length(dir2, epsilon);
|
|
|
|
|
normalize_v3_length(dir3, epsilon);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-06-26 21:35:18 +10:00
|
|
|
/* Offset coordinates slightly along view vectors,
|
|
|
|
|
* to avoid hitting the faces that own the edge. */
|
2013-04-16 05:23:34 +00:00
|
|
|
add_v3_v3v3(co1, co1, dir1);
|
|
|
|
|
add_v3_v3v3(co2, co2, dir2);
|
|
|
|
|
add_v3_v3v3(co3, co3, dir3);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-04-16 05:23:34 +00:00
|
|
|
normalize_v3(dir1);
|
|
|
|
|
normalize_v3(dir2);
|
|
|
|
|
normalize_v3(dir3);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-04-16 05:23:34 +00:00
|
|
|
/* do three samplings: left, middle, right */
|
2023-06-13 23:05:45 +02:00
|
|
|
f = edge_ray_cast(tree, co1, dir1, nullptr, e);
|
|
|
|
|
if (f && !edge_ray_cast(tree, co2, dir2, nullptr, e)) {
|
2013-04-16 05:23:34 +00:00
|
|
|
return true;
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2023-06-13 23:05:45 +02:00
|
|
|
if (f && !edge_ray_cast(tree, co3, dir3, nullptr, e)) {
|
2013-04-16 05:23:34 +00:00
|
|
|
return true;
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if (!f) {
|
2013-04-16 05:23:34 +00:00
|
|
|
return true;
|
2018-03-16 20:46:14 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-04-16 05:23:34 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-03-16 20:46:14 +11:00
|
|
|
|
|
|
|
|
/** \} */
|
2020-04-07 14:44:13 +10:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name BMesh Vertex Projection API
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
void EDBM_project_snap_verts(
|
|
|
|
|
bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
|
|
|
|
|
{
|
|
|
|
|
BMIter iter;
|
|
|
|
|
BMVert *eve;
|
|
|
|
|
|
2023-06-13 23:05:45 +02:00
|
|
|
ED_view3d_init_mats_rv3d(obedit, static_cast<RegionView3D *>(region->regiondata));
|
2020-04-07 14:44:13 +10:00
|
|
|
|
2023-02-11 14:50:37 -03:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2023-06-03 08:36:28 +10:00
|
|
|
SnapObjectContext *snap_context = ED_transform_snap_object_context_create(scene, 0);
|
2023-02-11 14:50:37 -03:00
|
|
|
|
|
|
|
|
eSnapTargetOP target_op = SCE_SNAP_TARGET_NOT_ACTIVE;
|
|
|
|
|
const int snap_flag = scene->toolsettings->snap_flag;
|
|
|
|
|
|
|
|
|
|
SET_FLAG_FROM_TEST(
|
|
|
|
|
target_op, !(snap_flag & SCE_SNAP_TO_INCLUDE_EDITED), SCE_SNAP_TARGET_NOT_EDITED);
|
|
|
|
|
SET_FLAG_FROM_TEST(
|
|
|
|
|
target_op, !(snap_flag & SCE_SNAP_TO_INCLUDE_NONEDITED), SCE_SNAP_TARGET_NOT_NONEDITED);
|
|
|
|
|
SET_FLAG_FROM_TEST(
|
|
|
|
|
target_op, (snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE), SCE_SNAP_TARGET_ONLY_SELECTABLE);
|
2020-04-07 14:44:13 +10:00
|
|
|
|
|
|
|
|
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
|
|
|
|
|
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
|
|
|
|
|
float mval[2], co_proj[3];
|
|
|
|
|
if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
|
2024-01-02 18:12:54 +01:00
|
|
|
V3D_PROJ_RET_OK)
|
|
|
|
|
{
|
2023-06-13 23:05:45 +02:00
|
|
|
SnapObjectParams params{};
|
|
|
|
|
params.snap_target_select = target_op;
|
|
|
|
|
params.edit_mode_type = SNAP_GEOM_FINAL;
|
|
|
|
|
params.use_occlusion_test = true;
|
2023-02-11 14:50:37 -03:00
|
|
|
if (ED_transform_snap_object_project_view3d(snap_context,
|
|
|
|
|
depsgraph,
|
|
|
|
|
region,
|
|
|
|
|
CTX_wm_view3d(C),
|
2023-06-23 16:58:16 -03:00
|
|
|
SCE_SNAP_TO_FACE,
|
2023-06-13 23:05:45 +02:00
|
|
|
¶ms,
|
|
|
|
|
nullptr,
|
2023-02-11 14:50:37 -03:00
|
|
|
mval,
|
2023-06-13 23:05:45 +02:00
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
2023-02-11 14:50:37 -03:00
|
|
|
co_proj,
|
2023-06-13 23:05:45 +02:00
|
|
|
nullptr))
|
2023-02-11 14:50:37 -03:00
|
|
|
{
|
2024-02-14 16:14:49 +01:00
|
|
|
mul_v3_m4v3(eve->co, obedit->world_to_object().ptr(), co_proj);
|
2020-04-07 14:44:13 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ED_transform_snap_object_context_destroy(snap_context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|