302 lines
7.2 KiB
C
302 lines
7.2 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.
|
|
*
|
|
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_string.h"
|
|
#include "BLI_string_utils.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BKE_customdata.h"
|
|
#include "BKE_editmesh.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_object_deform.h"
|
|
#include "BKE_object_facemap.h" /* own include */
|
|
|
|
#include "BLT_translation.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "RNA_access.h"
|
|
#include "RNA_define.h"
|
|
|
|
static bool fmap_unique_check(void *arg, const char *name)
|
|
{
|
|
struct {
|
|
Object *ob;
|
|
void *fm;
|
|
} *data = arg;
|
|
|
|
bFaceMap *fmap;
|
|
|
|
for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
|
|
if (data->fm != fmap) {
|
|
if (!strcmp(fmap->name, name)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bFaceMap *fmap_duplicate(bFaceMap *infmap)
|
|
{
|
|
bFaceMap *outfmap;
|
|
|
|
if (!infmap) {
|
|
return NULL;
|
|
}
|
|
|
|
outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
|
|
|
|
/* For now, just copy everything over. */
|
|
memcpy(outfmap, infmap, sizeof(bFaceMap));
|
|
|
|
outfmap->next = outfmap->prev = NULL;
|
|
|
|
return outfmap;
|
|
}
|
|
|
|
void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
|
|
{
|
|
bFaceMap *fmap, *fmapn;
|
|
|
|
BLI_listbase_clear(outbase);
|
|
|
|
for (fmap = inbase->first; fmap; fmap = fmap->next) {
|
|
fmapn = fmap_duplicate(fmap);
|
|
BLI_addtail(outbase, fmapn);
|
|
}
|
|
}
|
|
|
|
void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap)
|
|
{
|
|
struct {
|
|
Object *ob;
|
|
void *fmap;
|
|
} data;
|
|
data.ob = ob;
|
|
data.fmap = fmap;
|
|
|
|
BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
|
|
}
|
|
|
|
bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name)
|
|
{
|
|
bFaceMap *fmap;
|
|
|
|
if (!ob || ob->type != OB_MESH) {
|
|
return NULL;
|
|
}
|
|
|
|
fmap = MEM_callocN(sizeof(bFaceMap), __func__);
|
|
|
|
BLI_strncpy(fmap->name, name, sizeof(fmap->name));
|
|
|
|
BLI_addtail(&ob->fmaps, fmap);
|
|
|
|
ob->actfmap = BLI_listbase_count(&ob->fmaps);
|
|
|
|
BKE_object_facemap_unique_name(ob, fmap);
|
|
|
|
return fmap;
|
|
}
|
|
|
|
bFaceMap *BKE_object_facemap_add(Object *ob)
|
|
{
|
|
return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
|
|
}
|
|
|
|
static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
|
|
{
|
|
const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
|
|
|
|
if (ob->type == OB_MESH) {
|
|
Mesh *me = ob->data;
|
|
|
|
if (me->edit_mesh) {
|
|
BMEditMesh *em = me->edit_mesh;
|
|
const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
|
|
|
|
if (cd_fmap_offset != -1) {
|
|
BMFace *efa;
|
|
BMIter iter;
|
|
int *map;
|
|
|
|
if (purge) {
|
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
|
map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
|
|
|
|
if (map) {
|
|
if (*map == fmap_nr) {
|
|
*map = -1;
|
|
}
|
|
else if (*map > fmap_nr) {
|
|
*map -= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
|
map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
|
|
|
|
if (map && *map == fmap_nr &&
|
|
(!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
|
|
*map = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) {
|
|
ob->actfmap--;
|
|
}
|
|
|
|
BLI_remlink(&ob->fmaps, fmap);
|
|
MEM_freeN(fmap);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
|
|
{
|
|
const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
|
|
|
|
if (ob->type == OB_MESH) {
|
|
Mesh *me = ob->data;
|
|
|
|
if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
|
|
int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
|
|
int i;
|
|
|
|
if (map) {
|
|
for (i = 0; i < me->totpoly; i++) {
|
|
if (map[i] == fmap_nr) {
|
|
map[i] = -1;
|
|
}
|
|
else if (purge && map[i] > fmap_nr) {
|
|
map[i]--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) {
|
|
ob->actfmap--;
|
|
}
|
|
|
|
BLI_remlink(&ob->fmaps, fmap);
|
|
MEM_freeN(fmap);
|
|
}
|
|
}
|
|
|
|
static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
|
|
{
|
|
if (is_edit_mode) {
|
|
object_fmap_remove_edit_mode(ob, fmap, false, purge);
|
|
}
|
|
else {
|
|
object_fmap_remove_object_mode(ob, fmap, purge);
|
|
}
|
|
}
|
|
|
|
void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap)
|
|
{
|
|
fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
|
|
}
|
|
|
|
void BKE_object_facemap_clear(Object *ob)
|
|
{
|
|
bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
|
|
|
|
if (fmap) {
|
|
const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
|
|
|
|
while (fmap) {
|
|
bFaceMap *next_fmap = fmap->next;
|
|
fmap_remove_exec(ob, fmap, edit_mode, false);
|
|
fmap = next_fmap;
|
|
}
|
|
}
|
|
/* remove all face-maps */
|
|
if (ob->type == OB_MESH) {
|
|
Mesh *me = ob->data;
|
|
CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
|
|
}
|
|
ob->actfmap = 0;
|
|
}
|
|
|
|
int BKE_object_facemap_name_index(Object *ob, const char *name)
|
|
{
|
|
return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
|
|
}
|
|
|
|
bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
|
|
{
|
|
return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
|
|
}
|
|
|
|
int *BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
|
|
{
|
|
/* Build src to merged mapping of facemap indices. */
|
|
if (BLI_listbase_is_empty(&ob_src->fmaps) || BLI_listbase_is_empty(&ob_dst->fmaps)) {
|
|
*r_map_len = 0;
|
|
return NULL;
|
|
}
|
|
|
|
*r_map_len = BLI_listbase_count(&ob_src->fmaps);
|
|
int *fmap_index_map = MEM_malloc_arrayN(
|
|
*r_map_len, sizeof(*fmap_index_map), "defgroup index map create");
|
|
bool is_fmap_remap_needed = false;
|
|
|
|
int i = 0;
|
|
for (bFaceMap *fmap_src = ob_src->fmaps.first; fmap_src; fmap_src = fmap_src->next, i++) {
|
|
fmap_index_map[i] = BKE_object_facemap_name_index(ob_dst, fmap_src->name);
|
|
is_fmap_remap_needed = is_fmap_remap_needed || (fmap_index_map[i] != i);
|
|
}
|
|
|
|
if (!is_fmap_remap_needed) {
|
|
MEM_freeN(fmap_index_map);
|
|
fmap_index_map = NULL;
|
|
*r_map_len = 0;
|
|
}
|
|
|
|
return fmap_index_map;
|
|
}
|
|
|
|
void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
|
|
{
|
|
if (map == NULL || map_len == 0) {
|
|
return;
|
|
}
|
|
for (int i = 0; i < fmap_len; i++, fmap++) {
|
|
*fmap = (*fmap < map_len && *fmap != -1) ? map[*fmap] : -1;
|
|
}
|
|
}
|