2013-04-16 05:46:17 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2005 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2019-02-06 15:42:22 +11:00
|
|
|
/** \file \ingroup bke
|
2013-04-16 05:46:17 +00:00
|
|
|
*/
|
|
|
|
|
2013-04-16 05:59:48 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
2013-04-16 05:46:17 +00:00
|
|
|
|
2013-04-16 05:59:48 +00:00
|
|
|
#include "DNA_listBase.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
2013-04-16 05:46:17 +00:00
|
|
|
|
2013-04-16 05:59:48 +00:00
|
|
|
#include "BLI_math.h"
|
2013-04-16 05:46:17 +00:00
|
|
|
|
|
|
|
#include "BKE_editmesh.h"
|
2013-04-16 05:59:48 +00:00
|
|
|
#include "BKE_cdderivedmesh.h"
|
2018-10-09 16:52:46 +11:00
|
|
|
#include "BKE_library.h"
|
2013-04-16 05:46:17 +00:00
|
|
|
|
|
|
|
|
2013-04-16 05:59:48 +00:00
|
|
|
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
|
2013-04-16 05:46:17 +00:00
|
|
|
{
|
|
|
|
BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
|
|
|
|
|
|
|
|
em->bm = bm;
|
|
|
|
if (do_tessellate) {
|
2013-04-16 05:59:48 +00:00
|
|
|
BKE_editmesh_tessface_calc(em);
|
2013-04-16 05:46:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return em;
|
|
|
|
}
|
|
|
|
|
2013-04-16 05:59:48 +00:00
|
|
|
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
|
2013-04-16 05:46:17 +00:00
|
|
|
{
|
|
|
|
BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
|
|
|
|
*em_copy = *em;
|
|
|
|
|
2018-10-09 16:52:46 +11:00
|
|
|
em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
|
2013-04-27 23:42:42 +00:00
|
|
|
|
2013-04-16 05:46:17 +00:00
|
|
|
em_copy->derivedVertColor = NULL;
|
2013-04-27 23:42:42 +00:00
|
|
|
em_copy->derivedVertColorLen = 0;
|
2013-04-17 09:27:23 +00:00
|
|
|
em_copy->derivedFaceColor = NULL;
|
2013-04-27 23:42:42 +00:00
|
|
|
em_copy->derivedFaceColorLen = 0;
|
2013-04-16 05:46:17 +00:00
|
|
|
|
|
|
|
em_copy->bm = BM_mesh_copy(em->bm);
|
|
|
|
|
|
|
|
/* The tessellation is NOT calculated on the copy here,
|
|
|
|
* because currently all the callers of this function use
|
|
|
|
* it to make a backup copy of the BMEditMesh to restore
|
|
|
|
* it in the case of errors in an operation. For perf
|
|
|
|
* reasons, in that case it makes more sense to do the
|
|
|
|
* tessellation only when/if that copy ends up getting
|
|
|
|
* used.*/
|
|
|
|
em_copy->looptris = NULL;
|
|
|
|
|
|
|
|
return em_copy;
|
|
|
|
}
|
|
|
|
|
2013-04-16 05:59:48 +00:00
|
|
|
/**
|
|
|
|
* \brief Return the BMEditMesh for a given object
|
|
|
|
*
|
|
|
|
* \note this function assumes this is a mesh object,
|
|
|
|
* don't add NULL data check here. caller must do that
|
|
|
|
*/
|
|
|
|
BMEditMesh *BKE_editmesh_from_object(Object *ob)
|
|
|
|
{
|
|
|
|
BLI_assert(ob->type == OB_MESH);
|
|
|
|
/* sanity check */
|
2018-04-16 16:27:55 +02:00
|
|
|
#if 0 /* disable in mutlti-object edit. */
|
2013-04-16 05:59:48 +00:00
|
|
|
#ifndef NDEBUG
|
2019-02-17 18:05:18 +11:00
|
|
|
if (((Mesh *)ob->data)->edit_mesh) {
|
|
|
|
BLI_assert(((Mesh *)ob->data)->edit_mesh->ob == ob);
|
2013-04-16 05:59:48 +00:00
|
|
|
}
|
2018-04-16 16:27:55 +02:00
|
|
|
#endif
|
2013-04-16 05:59:48 +00:00
|
|
|
#endif
|
2019-02-17 18:05:18 +11:00
|
|
|
return ((Mesh *)ob->data)->edit_mesh;
|
2013-04-16 05:59:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void editmesh_tessface_calc_intern(BMEditMesh *em)
|
2013-04-16 05:46:17 +00:00
|
|
|
{
|
2013-11-18 18:20:21 +11:00
|
|
|
/* allocating space before calculating the tessellation */
|
|
|
|
|
2013-04-16 05:46:17 +00:00
|
|
|
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
|
|
|
|
/* this assumes all faces can be scan-filled, which isn't always true,
|
|
|
|
* worst case we over alloc a little which is acceptable */
|
|
|
|
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
|
|
|
|
const int looptris_tot_prev_alloc = em->looptris ? (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) : 0;
|
|
|
|
|
|
|
|
BMLoop *(*looptris)[3];
|
|
|
|
|
|
|
|
/* this means no reallocs for quad dominant models, for */
|
|
|
|
if ((em->looptris != NULL) &&
|
2013-11-18 18:20:21 +11:00
|
|
|
/* (*em->tottri >= looptris_tot)) */
|
2013-04-16 05:46:17 +00:00
|
|
|
/* check against alloc'd size incase we over alloc'd a little */
|
|
|
|
((looptris_tot_prev_alloc >= looptris_tot) && (looptris_tot_prev_alloc <= looptris_tot * 2)))
|
|
|
|
{
|
|
|
|
looptris = em->looptris;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (em->looptris) MEM_freeN(em->looptris);
|
|
|
|
looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
em->looptris = looptris;
|
|
|
|
|
2013-11-18 18:20:21 +11:00
|
|
|
/* after allocating the em->looptris, we're ready to tessellate */
|
2016-01-14 13:00:11 +11:00
|
|
|
BM_mesh_calc_tessellation(em->bm, em->looptris, &em->tottri);
|
2013-04-16 05:46:17 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-04-16 05:59:48 +00:00
|
|
|
void BKE_editmesh_tessface_calc(BMEditMesh *em)
|
2013-04-16 05:46:17 +00:00
|
|
|
{
|
2013-04-16 05:59:48 +00:00
|
|
|
editmesh_tessface_calc_intern(em);
|
2013-04-16 05:46:17 +00:00
|
|
|
|
|
|
|
/* commented because editbmesh_build_data() ensures we get tessfaces */
|
|
|
|
#if 0
|
2018-10-15 16:06:42 +11:00
|
|
|
if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) {
|
|
|
|
BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
|
2013-04-16 05:46:17 +00:00
|
|
|
}
|
2018-10-15 16:06:42 +11:00
|
|
|
else if (em->mesh_eval_final) {
|
|
|
|
BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
|
|
|
|
BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage);
|
2013-04-16 05:46:17 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-02-28 20:02:30 +11:00
|
|
|
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
|
2013-04-16 05:46:17 +00:00
|
|
|
{
|
2018-10-09 16:52:46 +11:00
|
|
|
if (em->mesh_eval_cage) {
|
|
|
|
BKE_id_free(NULL, em->mesh_eval_cage);
|
2013-04-16 05:46:17 +00:00
|
|
|
}
|
2018-10-09 16:52:46 +11:00
|
|
|
if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
|
|
|
|
BKE_id_free(NULL, em->mesh_eval_final);
|
2014-02-28 20:02:30 +11:00
|
|
|
}
|
2018-10-09 16:52:46 +11:00
|
|
|
em->mesh_eval_cage = em->mesh_eval_final = NULL;
|
2014-02-28 20:02:30 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/*does not free the BMEditMesh struct itself*/
|
|
|
|
void BKE_editmesh_free(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
BKE_editmesh_free_derivedmesh(em);
|
2013-04-16 05:46:17 +00:00
|
|
|
|
2013-04-18 17:09:56 +00:00
|
|
|
BKE_editmesh_color_free(em);
|
2013-04-16 05:46:17 +00:00
|
|
|
|
|
|
|
if (em->looptris) MEM_freeN(em->looptris);
|
|
|
|
|
|
|
|
if (em->bm)
|
|
|
|
BM_mesh_free(em->bm);
|
|
|
|
}
|
2013-04-18 17:09:56 +00:00
|
|
|
|
|
|
|
void BKE_editmesh_color_free(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
if (em->derivedVertColor) MEM_freeN(em->derivedVertColor);
|
|
|
|
if (em->derivedFaceColor) MEM_freeN(em->derivedFaceColor);
|
|
|
|
em->derivedVertColor = NULL;
|
|
|
|
em->derivedFaceColor = NULL;
|
|
|
|
|
|
|
|
em->derivedVertColorLen = 0;
|
|
|
|
em->derivedFaceColorLen = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype)
|
|
|
|
{
|
|
|
|
switch (htype) {
|
|
|
|
case BM_VERT:
|
|
|
|
if (em->derivedVertColorLen != em->bm->totvert) {
|
|
|
|
BKE_editmesh_color_free(em);
|
|
|
|
em->derivedVertColor = MEM_mallocN(sizeof(*em->derivedVertColor) * em->bm->totvert, __func__);
|
|
|
|
em->derivedVertColorLen = em->bm->totvert;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BM_FACE:
|
|
|
|
if (em->derivedFaceColorLen != em->bm->totface) {
|
|
|
|
BKE_editmesh_color_free(em);
|
|
|
|
em->derivedFaceColor = MEM_mallocN(sizeof(*em->derivedFaceColor) * em->bm->totface, __func__);
|
|
|
|
em->derivedFaceColorLen = em->bm->totface;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BLI_assert(0);
|
2013-07-21 08:16:37 +00:00
|
|
|
break;
|
2013-04-18 17:09:56 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-29 04:44:05 +11:00
|
|
|
|
|
|
|
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
|
|
|
|
{
|
|
|
|
BMIter iter;
|
|
|
|
BMVert *eve;
|
|
|
|
float (*orco)[3];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
orco = MEM_mallocN(em->bm->totvert * sizeof(*orco), __func__);
|
|
|
|
|
|
|
|
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
|
|
|
|
copy_v3_v3(orco[i], eve->co);
|
|
|
|
}
|
|
|
|
|
|
|
|
*r_numVerts = em->bm->totvert;
|
|
|
|
|
|
|
|
return orco;
|
|
|
|
}
|
2018-05-25 22:24:24 +05:30
|
|
|
|
|
|
|
void BKE_editmesh_lnorspace_update(BMEditMesh *em)
|
|
|
|
{
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
|
2018-08-21 17:18:42 +10:00
|
|
|
/* We need to create clnors data if none exist yet, otherwise there is no way to edit them.
|
2018-08-04 22:11:57 +05:30
|
|
|
* Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading
|
2018-08-21 17:18:42 +10:00
|
|
|
* in case we were using autosmooth so far...
|
2018-08-04 22:11:57 +05:30
|
|
|
* Note: there is a problem here, which is that if someone starts a normal editing operation on previously
|
2018-05-25 22:24:24 +05:30
|
|
|
* autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges
|
|
|
|
* (and hence autosmooth is 'lost').
|
|
|
|
* Not sure how critical this is, and how to fix that issue? */
|
|
|
|
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
|
|
|
|
Mesh *me = em->ob->data;
|
|
|
|
if (me->flag & ME_AUTOSMOOTH) {
|
|
|
|
BM_edges_sharp_from_angle_set(bm, me->smoothresh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BM_lnorspace_update(bm);
|
|
|
|
}
|