287 lines
8.3 KiB
C
287 lines
8.3 KiB
C
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*
|
|
* The primary purpose of this API is to avoid unnecessary mesh conversion for the final
|
|
* output of a modified mesh.
|
|
*
|
|
* This API handles the case when the modifier stack outputs a mesh which does not have
|
|
* #Mesh data (#MPoly, #MLoop, #MEdge, #MVert).
|
|
* Currently this is used so the resulting mesh can have #BMEditMesh data,
|
|
* postponing the converting until it's needed or avoiding conversion entirely
|
|
* which can be an expensive operation.
|
|
* Once converted, the meshes type changes to #ME_WRAPPER_TYPE_MDATA,
|
|
* although the edit mesh is not cleared.
|
|
*
|
|
* This API exposes functions that abstract over the different kinds of internal data,
|
|
* as well as supporting converting the mesh into regular mesh.
|
|
*/
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "BLI_ghash.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_threads.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BKE_editmesh.h"
|
|
#include "BKE_editmesh_cache.h"
|
|
#include "BKE_lib_id.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_mesh_runtime.h"
|
|
#include "BKE_mesh_wrapper.h"
|
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
|
|
const CustomData_MeshMasks *cd_mask_extra,
|
|
const float (*vert_coords)[3],
|
|
const Mesh *me_settings)
|
|
{
|
|
Mesh *me = BKE_id_new_nomain(ID_ME, NULL);
|
|
BKE_mesh_copy_settings(me, me_settings);
|
|
BKE_mesh_runtime_ensure_edit_data(me);
|
|
|
|
me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH;
|
|
if (cd_mask_extra) {
|
|
me->runtime.cd_mask_extra = *cd_mask_extra;
|
|
}
|
|
|
|
/* Use edit-mesh directly where possible. */
|
|
me->runtime.is_original = true;
|
|
me->edit_mesh = MEM_dupallocN(em);
|
|
|
|
/* Make sure, we crash if these are ever used. */
|
|
#ifdef DEBUG
|
|
me->totvert = INT_MAX;
|
|
me->totedge = INT_MAX;
|
|
me->totpoly = INT_MAX;
|
|
me->totloop = INT_MAX;
|
|
#else
|
|
me->totvert = 0;
|
|
me->totedge = 0;
|
|
me->totpoly = 0;
|
|
me->totloop = 0;
|
|
#endif
|
|
|
|
EditMeshData *edit_data = me->runtime.edit_data;
|
|
edit_data->vertexCos = vert_coords;
|
|
return me;
|
|
}
|
|
|
|
Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
|
|
const CustomData_MeshMasks *cd_mask_extra,
|
|
const Mesh *me_settings)
|
|
{
|
|
return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, NULL, me_settings);
|
|
}
|
|
|
|
void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
|
|
{
|
|
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
|
|
BLI_mutex_lock(mesh_eval_mutex);
|
|
|
|
if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
|
|
BLI_mutex_unlock(mesh_eval_mutex);
|
|
return;
|
|
}
|
|
|
|
const eMeshWrapperType geom_type_orig = me->runtime.wrapper_type;
|
|
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
|
|
|
|
switch (geom_type_orig) {
|
|
case ME_WRAPPER_TYPE_MDATA: {
|
|
break; /* Quiet warning. */
|
|
}
|
|
case ME_WRAPPER_TYPE_BMESH: {
|
|
me->totvert = 0;
|
|
me->totedge = 0;
|
|
me->totpoly = 0;
|
|
me->totloop = 0;
|
|
|
|
BLI_assert(me->edit_mesh != NULL);
|
|
BLI_assert(me->runtime.edit_data != NULL);
|
|
|
|
BMEditMesh *em = me->edit_mesh;
|
|
BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
|
|
|
|
EditMeshData *edit_data = me->runtime.edit_data;
|
|
if (edit_data->vertexCos) {
|
|
BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
|
|
me->runtime.is_original = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (me->runtime.wrapper_type_finalize) {
|
|
BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
|
|
}
|
|
|
|
BLI_mutex_unlock(mesh_eval_mutex);
|
|
}
|
|
|
|
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
|
|
{
|
|
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
|
|
case ME_WRAPPER_TYPE_BMESH:
|
|
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
|
|
case ME_WRAPPER_TYPE_MDATA:
|
|
return BKE_mesh_minmax(me, min, max);
|
|
}
|
|
BLI_assert_unreachable();
|
|
return false;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Mesh Coordinate Access
|
|
* \{ */
|
|
|
|
void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me,
|
|
float (*vert_coords)[3],
|
|
int vert_coords_len)
|
|
{
|
|
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
|
|
case ME_WRAPPER_TYPE_BMESH: {
|
|
BMesh *bm = me->edit_mesh->bm;
|
|
BLI_assert(vert_coords_len <= bm->totvert);
|
|
EditMeshData *edit_data = me->runtime.edit_data;
|
|
if (edit_data->vertexCos != NULL) {
|
|
for (int i = 0; i < vert_coords_len; i++) {
|
|
copy_v3_v3(vert_coords[i], edit_data->vertexCos[i]);
|
|
}
|
|
}
|
|
else {
|
|
BMIter iter;
|
|
BMVert *v;
|
|
int i;
|
|
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
|
copy_v3_v3(vert_coords[i], v->co);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case ME_WRAPPER_TYPE_MDATA: {
|
|
BLI_assert(vert_coords_len <= me->totvert);
|
|
const MVert *mvert = me->mvert;
|
|
for (int i = 0; i < vert_coords_len; i++) {
|
|
copy_v3_v3(vert_coords[i], mvert[i].co);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
BLI_assert_unreachable();
|
|
}
|
|
|
|
void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
|
|
float (*vert_coords)[3],
|
|
int vert_coords_len,
|
|
const float mat[4][4])
|
|
{
|
|
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
|
|
case ME_WRAPPER_TYPE_BMESH: {
|
|
BMesh *bm = me->edit_mesh->bm;
|
|
BLI_assert(vert_coords_len == bm->totvert);
|
|
EditMeshData *edit_data = me->runtime.edit_data;
|
|
if (edit_data->vertexCos != NULL) {
|
|
for (int i = 0; i < vert_coords_len; i++) {
|
|
mul_v3_m4v3(vert_coords[i], mat, edit_data->vertexCos[i]);
|
|
}
|
|
}
|
|
else {
|
|
BMIter iter;
|
|
BMVert *v;
|
|
int i;
|
|
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
|
|
mul_v3_m4v3(vert_coords[i], mat, v->co);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case ME_WRAPPER_TYPE_MDATA: {
|
|
BLI_assert(vert_coords_len == me->totvert);
|
|
const MVert *mvert = me->mvert;
|
|
for (int i = 0; i < vert_coords_len; i++) {
|
|
mul_v3_m4v3(vert_coords[i], mat, mvert[i].co);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
BLI_assert_unreachable();
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Mesh Array Length Access
|
|
* \{ */
|
|
|
|
int BKE_mesh_wrapper_vert_len(const Mesh *me)
|
|
{
|
|
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
|
|
case ME_WRAPPER_TYPE_BMESH:
|
|
return me->edit_mesh->bm->totvert;
|
|
case ME_WRAPPER_TYPE_MDATA:
|
|
return me->totvert;
|
|
}
|
|
BLI_assert_unreachable();
|
|
return -1;
|
|
}
|
|
|
|
int BKE_mesh_wrapper_edge_len(const Mesh *me)
|
|
{
|
|
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
|
|
case ME_WRAPPER_TYPE_BMESH:
|
|
return me->edit_mesh->bm->totedge;
|
|
case ME_WRAPPER_TYPE_MDATA:
|
|
return me->totedge;
|
|
}
|
|
BLI_assert_unreachable();
|
|
return -1;
|
|
}
|
|
|
|
int BKE_mesh_wrapper_loop_len(const Mesh *me)
|
|
{
|
|
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
|
|
case ME_WRAPPER_TYPE_BMESH:
|
|
return me->edit_mesh->bm->totloop;
|
|
case ME_WRAPPER_TYPE_MDATA:
|
|
return me->totloop;
|
|
}
|
|
BLI_assert_unreachable();
|
|
return -1;
|
|
}
|
|
|
|
int BKE_mesh_wrapper_poly_len(const Mesh *me)
|
|
{
|
|
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
|
|
case ME_WRAPPER_TYPE_BMESH:
|
|
return me->edit_mesh->bm->totface;
|
|
case ME_WRAPPER_TYPE_MDATA:
|
|
return me->totpoly;
|
|
}
|
|
BLI_assert_unreachable();
|
|
return -1;
|
|
}
|
|
|
|
/** \} */
|