375 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * ***** BEGIN GPL LICENSE BLOCK *****
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of the GNU General Public License
 | 
						|
 * as published by the Free Software Foundation; either version 2
 | 
						|
 * of the License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 * The Original Code is Copyright (C) 2005 Blender Foundation.
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * The Original Code is: all of this file.
 | 
						|
 *
 | 
						|
 * Contributor(s): none yet.
 | 
						|
 *
 | 
						|
 * ***** END GPL LICENSE BLOCK *****
 | 
						|
 */
 | 
						|
 | 
						|
/** \file blender/blenkernel/intern/editmesh.c
 | 
						|
 *  \ingroup bke
 | 
						|
 */
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
#include "DNA_listBase.h"
 | 
						|
#include "DNA_object_types.h"
 | 
						|
#include "DNA_mesh_types.h"
 | 
						|
 | 
						|
#include "BLI_math.h"
 | 
						|
#include "BLI_scanfill.h"
 | 
						|
 | 
						|
#include "BKE_editmesh.h"
 | 
						|
#include "BKE_cdderivedmesh.h"
 | 
						|
 | 
						|
 | 
						|
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
 | 
						|
{
 | 
						|
	BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
 | 
						|
 | 
						|
	em->bm = bm;
 | 
						|
	if (do_tessellate) {
 | 
						|
		BKE_editmesh_tessface_calc(em);
 | 
						|
	}
 | 
						|
 | 
						|
	return em;
 | 
						|
}
 | 
						|
 | 
						|
BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
 | 
						|
{
 | 
						|
	BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
 | 
						|
	*em_copy = *em;
 | 
						|
 | 
						|
	em_copy->derivedCage = em_copy->derivedFinal = NULL;
 | 
						|
	em_copy->derivedVertColor = NULL;
 | 
						|
	em_copy->derivedFaceColor = NULL;
 | 
						|
 | 
						|
	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;
 | 
						|
 | 
						|
	em_copy->vert_index = NULL;
 | 
						|
	em_copy->edge_index = NULL;
 | 
						|
	em_copy->face_index = NULL;
 | 
						|
 | 
						|
	return em_copy;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \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 */
 | 
						|
#ifndef NDEBUG
 | 
						|
	if (((Mesh *)ob->data)->edit_btmesh) {
 | 
						|
		BLI_assert(((Mesh *)ob->data)->edit_btmesh->ob == ob);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	return ((Mesh *)ob->data)->edit_btmesh;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void editmesh_tessface_calc_intern(BMEditMesh *em)
 | 
						|
{
 | 
						|
	/* use this to avoid locking pthread for _every_ polygon
 | 
						|
	 * and calling the fill function */
 | 
						|
#define USE_TESSFACE_SPEEDUP
 | 
						|
 | 
						|
	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];
 | 
						|
	BMIter iter;
 | 
						|
	BMFace *efa;
 | 
						|
	BMLoop *l;
 | 
						|
	int i = 0;
 | 
						|
 | 
						|
	ScanFillContext sf_ctx;
 | 
						|
 | 
						|
#if 0
 | 
						|
	/* note, we could be clever and re-use this array but would need to ensure
 | 
						|
	 * its realloced at some point, for now just free it */
 | 
						|
	if (em->looptris) MEM_freeN(em->looptris);
 | 
						|
 | 
						|
	/* Use em->tottri when set, this means no reallocs while transforming,
 | 
						|
	 * (unless scanfill fails), otherwise... */
 | 
						|
	/* allocate the length of totfaces, avoid many small reallocs,
 | 
						|
	 * if all faces are tri's it will be correct, quads == 2x allocs */
 | 
						|
	BLI_array_reserve(looptris, (em->tottri && em->tottri < bm->totface * 3) ? em->tottri : bm->totface);
 | 
						|
#else
 | 
						|
 | 
						|
	/* this means no reallocs for quad dominant models, for */
 | 
						|
	if ((em->looptris != NULL) &&
 | 
						|
	    /* (em->tottri >= looptris_tot)) */
 | 
						|
	    /* 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__);
 | 
						|
	}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
	BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
 | 
						|
		/* don't consider two-edged faces */
 | 
						|
		if (UNLIKELY(efa->len < 3)) {
 | 
						|
			/* do nothing */
 | 
						|
		}
 | 
						|
 | 
						|
#ifdef USE_TESSFACE_SPEEDUP
 | 
						|
 | 
						|
		/* no need to ensure the loop order, we know its ok */
 | 
						|
 | 
						|
		else if (efa->len == 3) {
 | 
						|
#if 0
 | 
						|
			int j;
 | 
						|
			BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, j) {
 | 
						|
				looptris[i][j] = l;
 | 
						|
			}
 | 
						|
			i += 1;
 | 
						|
#else
 | 
						|
			/* more cryptic but faster */
 | 
						|
			BMLoop **l_ptr = looptris[i++];
 | 
						|
			l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
 | 
						|
			l_ptr[1] = l = l->next;
 | 
						|
			l_ptr[2] = l->next;
 | 
						|
#endif
 | 
						|
		}
 | 
						|
		else if (efa->len == 4) {
 | 
						|
#if 0
 | 
						|
			BMLoop *ltmp[4];
 | 
						|
			int j;
 | 
						|
			BLI_array_grow_items(looptris, 2);
 | 
						|
			BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, j) {
 | 
						|
				ltmp[j] = l;
 | 
						|
			}
 | 
						|
 | 
						|
			looptris[i][0] = ltmp[0];
 | 
						|
			looptris[i][1] = ltmp[1];
 | 
						|
			looptris[i][2] = ltmp[2];
 | 
						|
			i += 1;
 | 
						|
 | 
						|
			looptris[i][0] = ltmp[0];
 | 
						|
			looptris[i][1] = ltmp[2];
 | 
						|
			looptris[i][2] = ltmp[3];
 | 
						|
			i += 1;
 | 
						|
#else
 | 
						|
			/* more cryptic but faster */
 | 
						|
			BMLoop **l_ptr_a = looptris[i++];
 | 
						|
			BMLoop **l_ptr_b = looptris[i++];
 | 
						|
			(l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa));
 | 
						|
			(l_ptr_a[1]              = l = l->next);
 | 
						|
			(l_ptr_a[2] = l_ptr_b[1] = l = l->next);
 | 
						|
			(             l_ptr_b[2] = l->next);
 | 
						|
#endif
 | 
						|
		}
 | 
						|
 | 
						|
#endif /* USE_TESSFACE_SPEEDUP */
 | 
						|
 | 
						|
		else {
 | 
						|
			int j;
 | 
						|
			BMLoop *l_iter;
 | 
						|
			BMLoop *l_first;
 | 
						|
 | 
						|
			ScanFillVert *sf_vert, *sf_vert_last = NULL, *sf_vert_first = NULL;
 | 
						|
			/* ScanFillEdge *e; */ /* UNUSED */
 | 
						|
			ScanFillFace *sf_tri;
 | 
						|
			int totfilltri;
 | 
						|
 | 
						|
			BLI_scanfill_begin(&sf_ctx);
 | 
						|
 | 
						|
			/* scanfill time */
 | 
						|
			j = 0;
 | 
						|
			l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
 | 
						|
			do {
 | 
						|
				sf_vert = BLI_scanfill_vert_add(&sf_ctx, l_iter->v->co);
 | 
						|
				sf_vert->tmp.p = l_iter;
 | 
						|
 | 
						|
				if (sf_vert_last) {
 | 
						|
					/* e = */ BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert);
 | 
						|
				}
 | 
						|
 | 
						|
				sf_vert_last = sf_vert;
 | 
						|
				if (sf_vert_first == NULL) {
 | 
						|
					sf_vert_first = sf_vert;
 | 
						|
				}
 | 
						|
 | 
						|
				/*mark order */
 | 
						|
				BM_elem_index_set(l_iter, j++); /* set_loop */
 | 
						|
 | 
						|
			} while ((l_iter = l_iter->next) != l_first);
 | 
						|
 | 
						|
			/* complete the loop */
 | 
						|
			BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert);
 | 
						|
 | 
						|
			totfilltri = BLI_scanfill_calc_ex(&sf_ctx, 0, efa->no);
 | 
						|
			BLI_assert(totfilltri <= efa->len - 2);
 | 
						|
			(void)totfilltri;
 | 
						|
 | 
						|
			for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
 | 
						|
				BMLoop **l_ptr = looptris[i++];
 | 
						|
				BMLoop *l1 = sf_tri->v1->tmp.p;
 | 
						|
				BMLoop *l2 = sf_tri->v2->tmp.p;
 | 
						|
				BMLoop *l3 = sf_tri->v3->tmp.p;
 | 
						|
 | 
						|
				if (BM_elem_index_get(l1) > BM_elem_index_get(l2)) { SWAP(BMLoop *, l1, l2); }
 | 
						|
				if (BM_elem_index_get(l2) > BM_elem_index_get(l3)) { SWAP(BMLoop *, l2, l3); }
 | 
						|
				if (BM_elem_index_get(l1) > BM_elem_index_get(l2)) { SWAP(BMLoop *, l1, l2); }
 | 
						|
 | 
						|
				l_ptr[0] = l1;
 | 
						|
				l_ptr[1] = l2;
 | 
						|
				l_ptr[2] = l3;
 | 
						|
			}
 | 
						|
 | 
						|
			BLI_scanfill_end(&sf_ctx);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	em->tottri = i;
 | 
						|
	em->looptris = looptris;
 | 
						|
 | 
						|
	BLI_assert(em->tottri <= looptris_tot);
 | 
						|
 | 
						|
#undef USE_TESSFACE_SPEEDUP
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void BKE_editmesh_tessface_calc(BMEditMesh *em)
 | 
						|
{
 | 
						|
	editmesh_tessface_calc_intern(em);
 | 
						|
 | 
						|
	/* commented because editbmesh_build_data() ensures we get tessfaces */
 | 
						|
#if 0
 | 
						|
	if (em->derivedFinal && em->derivedFinal == em->derivedCage) {
 | 
						|
		if (em->derivedFinal->recalcTessellation)
 | 
						|
			em->derivedFinal->recalcTessellation(em->derivedFinal);
 | 
						|
	}
 | 
						|
	else if (em->derivedFinal) {
 | 
						|
		if (em->derivedCage->recalcTessellation)
 | 
						|
			em->derivedCage->recalcTessellation(em->derivedCage);
 | 
						|
		if (em->derivedFinal->recalcTessellation)
 | 
						|
			em->derivedFinal->recalcTessellation(em->derivedFinal);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void BKE_editmesh_update_linked_customdata(BMEditMesh *em)
 | 
						|
{
 | 
						|
	BMesh *bm = em->bm;
 | 
						|
	int act;
 | 
						|
 | 
						|
	if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
 | 
						|
		act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
 | 
						|
		CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
 | 
						|
 | 
						|
		act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
 | 
						|
		CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
 | 
						|
 | 
						|
		act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
 | 
						|
		CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
 | 
						|
 | 
						|
		act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
 | 
						|
		CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*does not free the BMEditMesh struct itself*/
 | 
						|
void BKE_editmesh_free(BMEditMesh *em)
 | 
						|
{
 | 
						|
	if (em->derivedFinal) {
 | 
						|
		if (em->derivedFinal != em->derivedCage) {
 | 
						|
			em->derivedFinal->needsFree = 1;
 | 
						|
			em->derivedFinal->release(em->derivedFinal);
 | 
						|
		}
 | 
						|
		em->derivedFinal = NULL;
 | 
						|
	}
 | 
						|
	if (em->derivedCage) {
 | 
						|
		em->derivedCage->needsFree = 1;
 | 
						|
		em->derivedCage->release(em->derivedCage);
 | 
						|
		em->derivedCage = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	BKE_editmesh_color_free(em);
 | 
						|
 | 
						|
	if (em->looptris) MEM_freeN(em->looptris);
 | 
						|
 | 
						|
	if (em->vert_index) MEM_freeN(em->vert_index);
 | 
						|
	if (em->edge_index) MEM_freeN(em->edge_index);
 | 
						|
	if (em->face_index) MEM_freeN(em->face_index);
 | 
						|
 | 
						|
	if (em->bm)
 | 
						|
		BM_mesh_free(em->bm);
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
	}
 | 
						|
}
 |