コード例 #1
0
/**
 * Duplicate of BM_mesh_cd_validate() for Mesh data.
 */
void BKE_mesh_cd_validate(Mesh *me)
{
	int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
	int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
	int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
	int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
	int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
	int i;

	/* XXX For now, do not delete those, just warn they are not really usable. */
	if (UNLIKELY(totlayer_mtex > MAX_MTFACE)) {
		printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
		       MAX_MTFACE, totlayer_mtex - MAX_MTFACE);
	}
	if (UNLIKELY(totlayer_uv > MAX_MTFACE)) {
		printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
		       MAX_MTFACE, totlayer_uv - MAX_MTFACE);
	}
	if (UNLIKELY(totlayer_mcol > MAX_MCOL)) {
		printf("WARNING! More VCol layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
		       MAX_MCOL, totlayer_mcol - MAX_MCOL);
	}

	if (LIKELY(totlayer_mtex == totlayer_uv)) {
		/* pass */
	}
	else if (totlayer_mtex < totlayer_uv) {
		do {
			const char *from_name =  me->ldata.layers[uv_index + totlayer_mtex].name;
			CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name);
			CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex);
		} while (totlayer_uv != ++totlayer_mtex);
		mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
	}
	else if (totlayer_uv < totlayer_mtex) {
		do {
			const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name;
			CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name);
			CustomData_set_layer_unique_name(&me->ldata, totlayer_uv);
		} while (totlayer_mtex != ++totlayer_uv);
		uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
	}

	BLI_assert(totlayer_mtex == totlayer_uv);

	/* Check uv/tex names match as well!!! */
	for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) {
		const char *name_src = me->pdata.layers[mtex_index].name;
		const char *name_dst = me->ldata.layers[uv_index].name;
		if (!STREQ(name_src, name_dst)) {
			BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false);
		}
	}
}
コード例 #2
0
ファイル: mesh_data.c プロジェクト: rexbron/blender-ocio
int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *me, const char *name, int active_set)
{
	EditMesh *em;
	MCol *mcol;
	int layernum;

	if(me->edit_mesh) {
		em= me->edit_mesh;

		layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL);
		if(layernum >= MAX_MCOL)
			return 0;

		EM_add_data_layer(em, &em->fdata, CD_MCOL, name);

		if(layernum) /* copy data from active vertex color layer */
			copy_editface_active_customdata(em, CD_MCOL, layernum);

		if(active_set || layernum==0)
			CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
	}
	else {
		layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL);
		if(layernum >= MAX_MCOL)
			return 0;

		mcol= me->mcol;

		if(me->mcol)
			CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name);
		else
			CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name);

		if(active_set || layernum==0)
			CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);

		mesh_update_customdata_pointers(me);
	}

	DAG_id_tag_update(&me->id, 0);
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);

	return 1;
}
コード例 #3
0
ファイル: mesh_data.c プロジェクト: rexbron/blender-ocio
int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_set)
{
	EditMesh *em;
	int layernum;

	if(me->edit_mesh) {
		em= me->edit_mesh;

		layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
		if(layernum >= MAX_MTFACE)
			return 0;

		EM_add_data_layer(em, &em->fdata, CD_MTFACE, name);

		if(layernum) /* copy data from active UV */
			copy_editface_active_customdata(em, CD_MTFACE, layernum);

		if(active_set || layernum==0)
			CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum);
	}
	else {
		layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE);
		if(layernum >= MAX_MTFACE)
			return 0;

		if(me->mtface)
			CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name);
		else
			CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name);

		if(active_set || layernum==0)
			CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum);

		mesh_update_customdata_pointers(me);
	}

	DAG_id_tag_update(&me->id, 0);
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);

	return 1;
}
コード例 #4
0
ファイル: mesh_validate.c プロジェクト: Eibriel/kiriblender
/**
 * Duplicate of BM_mesh_cd_validate() for Mesh data.
 */
void BKE_mesh_cd_validate(Mesh *me)
{
	int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
	int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
	int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
	int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
	int i;

	if (LIKELY(totlayer_mtex == totlayer_uv)) {
		/* pass */
	}
	else if (totlayer_mtex < totlayer_uv) {
		do {
			const char *from_name =  me->ldata.layers[uv_index + totlayer_mtex].name;
			CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name);
			CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex);
		} while (totlayer_uv != ++totlayer_mtex);
		mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
	}
	else if (totlayer_uv < totlayer_mtex) {
		do {
			const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name;
			CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name);
			CustomData_set_layer_unique_name(&me->ldata, totlayer_uv);
		} while (totlayer_mtex != ++totlayer_uv);
		uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
	}

	BLI_assert(totlayer_mtex == totlayer_uv);

	/* Check uv/tex names match as well!!! */
	for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) {
		const char *name_src = me->pdata.layers[mtex_index].name;
		const char *name_dst = me->ldata.layers[uv_index].name;
		if (!STREQ(name_src, name_dst)) {
			BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false);
		}
	}
}
コード例 #5
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
{
  Curve *cu = ob->data;
  Mesh *mesh;
  MVert *allvert;
  MEdge *alledge;
  MLoop *allloop;
  MPoly *allpoly;
  MLoopUV *alluv = NULL;
  int totvert, totedge, totloop, totpoly;
  bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;

  if (BKE_mesh_nurbs_displist_to_mdata(ob,
                                       dispbase,
                                       &allvert,
                                       &totvert,
                                       &alledge,
                                       &totedge,
                                       &allloop,
                                       &allpoly,
                                       (use_orco_uv) ? &alluv : NULL,
                                       &totloop,
                                       &totpoly) != 0) {
    /* Error initializing mdata. This often happens when curve is empty */
    return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
  }

  mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
  mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;

  memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
  memcpy(mesh->medge, alledge, totedge * sizeof(MEdge));
  memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop));
  memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));

  if (alluv) {
    const char *uvname = "Orco";
    CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
  }

  MEM_freeN(allvert);
  MEM_freeN(alledge);
  MEM_freeN(allloop);
  MEM_freeN(allpoly);

  return mesh;
}
コード例 #6
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
{
  KeyBlock *kb;
  Key *key = mesh_src->key;
  int i;

  if (!mesh_src->key) {
    return;
  }

  /* ensure we can use mesh vertex count for derived mesh custom data */
  if (mesh_src->totvert != mesh_dest->totvert) {
    CLOG_ERROR(&LOG,
               "vertex size mismatch (mesh/dm) '%s' (%d != %d)",
               mesh_src->id.name + 2,
               mesh_src->totvert,
               mesh_dest->totvert);
    return;
  }

  for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
    int ci;
    float *array;

    if (mesh_src->totvert != kb->totelem) {
      CLOG_ERROR(&LOG,
                 "vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)",
                 mesh_src->id.name + 2,
                 mesh_src->totvert,
                 kb->name,
                 kb->totelem);
      array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
    }
    else {
      array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
      memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float));
    }

    CustomData_add_layer_named(
        &mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name);
    ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i);

    mesh_dest->vdata.layers[ci].uid = kb->uid;
  }
}
コード例 #7
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
	DerivedMesh *dm = derivedData;
	MDeformVert *dvert = NULL;
	MDeformWeight **dw1, **tdw1, **dw2, **tdw2;
	int numVerts;
	int defgrp_idx, defgrp_idx2 = -1;
	float *org_w;
	float *new_w;
	int *tidx, *indices = NULL;
	int numIdx = 0;
	int i;
	/* Flags. */
#if 0
	int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
#endif

	/* Get number of verts. */
	numVerts = dm->getNumVerts(dm);

	/* Check if we can just return the original mesh.
	 * Must have verts and therefore verts assigned to vgroups to do anything useful!
	 */
	if ((numVerts == 0) || (ob->defbase.first == NULL))
		return dm;

	/* Get vgroup idx from its name. */
	defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name_a);
	if (defgrp_idx < 0)
		return dm;
	/* Get seconf vgroup idx from its name, if given. */
	if (wmd->defgrp_name_b[0] != (char)0) {
		defgrp_idx2 = defgroup_name_index(ob, wmd->defgrp_name_b);
		if (defgrp_idx2 < 0)
			return dm;
	}

	dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
	/* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
	if (!dvert) {
		/* If not affecting all vertices, just return. */
		if (wmd->mix_set != MOD_WVG_SET_ALL)
			return dm;
		/* Else, add a valid data layer! */
		dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
		                                   NULL, numVerts, wmd->defgrp_name_a);
		/* Ultimate security check. */
		if (!dvert)
			return dm;
	}
	/* Find out which vertices to work on. */
	tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGMix Modifier, tidx");
	tdw1 = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGMix Modifier, tdw1");
	tdw2 = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGMix Modifier, tdw2");
	switch (wmd->mix_set) {
		case MOD_WVG_SET_A:
			/* All vertices in first vgroup. */
			for (i = 0; i < numVerts; i++) {
				MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_idx);
				if (dw) {
					tdw1[numIdx] = dw;
					tdw2[numIdx] = defvert_find_index(&dvert[i], defgrp_idx2);
					tidx[numIdx++] = i;
				}
			}
			break;
		case MOD_WVG_SET_B:
			/* All vertices in second vgroup. */
			for (i = 0; i < numVerts; i++) {
				MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_idx2);
				if (dw) {
					tdw1[numIdx] = defvert_find_index(&dvert[i], defgrp_idx);
					tdw2[numIdx] = dw;
					tidx[numIdx++] = i;
				}
			}
			break;
		case MOD_WVG_SET_OR:
			/* All vertices in one vgroup or the other. */
			for (i = 0; i < numVerts; i++) {
				MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_idx);
				MDeformWeight *bdw = defvert_find_index(&dvert[i], defgrp_idx2);
				if (adw || bdw) {
					tdw1[numIdx] = adw;
					tdw2[numIdx] = bdw;
					tidx[numIdx++] = i;
				}
			}
			break;
		case MOD_WVG_SET_AND:
			/* All vertices in both vgroups. */
			for (i = 0; i < numVerts; i++) {
				MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_idx);
				MDeformWeight *bdw = defvert_find_index(&dvert[i], defgrp_idx2);
				if (adw && bdw) {
					tdw1[numIdx] = adw;
					tdw2[numIdx] = bdw;
					tidx[numIdx++] = i;
				}
			}
			break;
		case MOD_WVG_SET_ALL:
		default:
			/* Use all vertices. */
			for (i = 0; i < numVerts; i++) {
				tdw1[i] = defvert_find_index(&dvert[i], defgrp_idx);
				tdw2[i] = defvert_find_index(&dvert[i], defgrp_idx2);
			}
			numIdx = -1;
			break;
	}
	if (numIdx == 0) {
		/* Use no vertices! Hence, return org data. */
		MEM_freeN(tdw1);
		MEM_freeN(tdw2);
		MEM_freeN(tidx);
		return dm;
	}
	if (numIdx != -1) {
		indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGMix Modifier, indices");
		memcpy(indices, tidx, sizeof(int) * numIdx);
		dw1 = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGMix Modifier, dw1");
		memcpy(dw1, tdw1, sizeof(MDeformWeight *) * numIdx);
		MEM_freeN(tdw1);
		dw2 = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGMix Modifier, dw2");
		memcpy(dw2, tdw2, sizeof(MDeformWeight *) * numIdx);
		MEM_freeN(tdw2);
	}
	else {
		/* Use all vertices. */
		numIdx = numVerts;
		/* Just copy MDeformWeight pointers arrays, they will be freed at the end. */
		dw1 = tdw1;
		dw2 = tdw2;
	}
	MEM_freeN(tidx);

	org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, org_w");
	new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, new_w");

	/* Mix weights. */
	for (i = 0; i < numIdx; i++) {
		float weight2 = 0.0;
		org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
		weight2  = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;

		new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
	}

	/* Do masking. */
	weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant,
	                 wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
	                 wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
	                 wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);

	/* Update (add to) vgroup.
	 * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
	 */
	weightvg_update_vg(dvert, defgrp_idx, dw1, numIdx, indices, org_w, TRUE, -FLT_MAX, FALSE, 0.0f);

	/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
	if (do_prev)
		DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices);
#endif

	/* Freeing stuff. */
	MEM_freeN(org_w);
	MEM_freeN(new_w);
	MEM_freeN(dw1);
	MEM_freeN(dw2);

	if (indices)
		MEM_freeN(indices);

	/* Return the vgroup-modified mesh. */
	return dm;
}
コード例 #8
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
	DerivedMesh *dm = derivedData;
	MDeformVert *dvert = NULL;
	MDeformWeight **dw = NULL;
	float *org_w; /* Array original weights. */
	float *new_w; /* Array new weights. */
	int numVerts;
	int defgrp_index;
	int i;
	/* Flags. */
	int do_add  = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0;
	int do_rem  = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0;
	/* Only do weight-preview in Object, Sculpt and Pose modes! */
#if 0
	int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
#endif

	/* Get number of verts. */
	numVerts = dm->getNumVerts(dm);

	/* Check if we can just return the original mesh.
	 * Must have verts and therefore verts assigned to vgroups to do anything useful!
	 */
	if ((numVerts == 0) || (ob->defbase.first == NULL))
		return dm;

	/* Get vgroup idx from its name. */
	defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
	if (defgrp_index == -1)
		return dm;

	dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
	/* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
	if (!dvert) {
		/* If this modifier is not allowed to add vertices, just return. */
		if (!do_add)
			return dm;
		/* Else, add a valid data layer! */
		dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
		                                   NULL, numVerts, wmd->defgrp_name);
		/* Ultimate security check. */
		if (!dvert)
			return dm;
	}

	/* Get org weights, assuming 0.0 for vertices not in given vgroup. */
	org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
	new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, new_w");
	dw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGEdit Modifier, dw");
	for (i = 0; i < numVerts; i++) {
		dw[i] = defvert_find_index(&dvert[i], defgrp_index);
		if (dw[i]) {
			org_w[i] = new_w[i] = dw[i]->weight;
		}
		else {
			org_w[i] = new_w[i] = wmd->default_weight;
		}
	}

	/* Do mapping. */
	if (wmd->falloff_type != MOD_WVG_MAPPING_NONE) {
		RNG *rng = NULL;

		if (wmd->falloff_type == MOD_WVG_MAPPING_RANDOM)
			rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2));

		weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve, rng);

		if (rng)
			BLI_rng_free(rng);
	}

	/* Do masking. */
	weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, dm, wmd->mask_constant,
	                 wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
	                 wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
	                 wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);

	/* Update/add/remove from vgroup. */
	weightvg_update_vg(dvert, defgrp_index, dw, numVerts, NULL, org_w, do_add, wmd->add_threshold,
	                   do_rem, wmd->rem_threshold);

	/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
	if (do_prev)
		DM_update_weight_mcol(ob, dm, 0, org_w, 0, NULL);
#endif

	/* Freeing stuff. */
	MEM_freeN(org_w);
	MEM_freeN(new_w);
	MEM_freeN(dw);

	/* Return the vgroup-modified mesh. */
	return dm;
}
コード例 #9
0
static DerivedMesh *doOcean(ModifierData *md, Object *ob,
                            DerivedMesh *derivedData,
                            int UNUSED(useRenderParams))
{
	OceanModifierData *omd = (OceanModifierData *) md;

	DerivedMesh *dm = NULL;
	OceanResult ocr;

	MVert *mverts, *mv;
	MLoop *mloops;

	int i, j;

	int num_verts;
	int num_faces;

	int cfra;

	/* use cached & inverted value for speed
	 * expanded this would read...
	 *
	 * (axis / (omd->size * omd->spatial_size)) + 0.5f) */
#define OCEAN_CO(_size_co_inv, _v) ((_v * _size_co_inv) + 0.5f)

	const float size_co_inv = 1.0f / (omd->size * omd->spatial_size);

	/* can happen in when size is small, avoid bad array lookups later and quit now */
	if (!finite(size_co_inv)) {
		return derivedData;
	}

	/* update modifier */
	if (omd->refresh & MOD_OCEAN_REFRESH_ADD)
		omd->ocean = BKE_ocean_add();
	if (omd->refresh & MOD_OCEAN_REFRESH_RESET)
		init_ocean_modifier(omd);
	if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE)
		clear_cache_data(omd);

	omd->refresh = 0;

	/* do ocean simulation */
	if (omd->cached == true) {
		if (!omd->oceancache) init_cache_data(ob, omd);
		BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
	}
	else {
		simulate_ocean_modifier(omd);
	}

	if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
		dm = generate_ocean_geometry(omd);
		DM_ensure_normals(dm);
	}
	else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
		dm = CDDM_copy(derivedData);
	}

	cfra = md->scene->r.cfra;
	CLAMP(cfra, omd->bakestart, omd->bakeend);
	cfra -= omd->bakestart; /* shift to 0 based */

	num_verts = dm->getNumVerts(dm);
	num_faces = dm->getNumPolys(dm);

	mverts = dm->getVertArray(dm);
	mloops = dm->getLoopArray(dm);

	/* add vcols before displacement - allows lookup based on position */

	if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
		int cdlayer = CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL);

		if (cdlayer < MAX_MCOL) {
			MLoopCol *mloopcols = CustomData_add_layer_named(&dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL,
			                                                 num_faces * 4, omd->foamlayername);

			if (mloopcols) { /* unlikely to fail */
				MLoopCol *mlcol;
				MPoly *mpolys = dm->getPolyArray(dm);
				MPoly *mp;

				float foam;

				for (i = 0, mp = mpolys; i < num_faces; i++, mp++) {
					j = mp->totloop - 1;

					/* highly unlikely */
					if (j <= 0) continue;

					do {
						const float *co = mverts[mloops[mp->loopstart + j].v].co;
						const float u = OCEAN_CO(size_co_inv, co[0]);
						const float v = OCEAN_CO(size_co_inv, co[1]);

						if (omd->oceancache && omd->cached == true) {
							BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
							foam = ocr.foam;
							CLAMP(foam, 0.0f, 1.0f);
						}
						else {
							BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
							foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
						}

						mlcol = &mloopcols[mp->loopstart + j];
						mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255);
						/* This needs to be set (render engine uses) */
						mlcol->a = 255;
					} while (j--);
				}
			}
		}
	}


	/* displace the geometry */

	/* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */
	for (i = 0, mv = mverts; i < num_verts; i++, mv++) {
		const float u = OCEAN_CO(size_co_inv, mv->co[0]);
		const float v = OCEAN_CO(size_co_inv, mv->co[1]);

		if (omd->oceancache && omd->cached == true)
			BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
		else
			BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);

		mv->co[2] += ocr.disp[1];

		if (omd->chop_amount > 0.0f) {
			mv->co[0] += ocr.disp[0];
			mv->co[1] += ocr.disp[2];
		}
	}

#undef OCEAN_CO

	return dm;
}
コード例 #10
0
/**
 * \brief Mesh -> BMesh
 * \param bm: The mesh to write into, while this is typically a newly created BMesh,
 * merging into existing data is supported.
 * Note the custom-data layout isn't used.
 * If more comprehensive merging is needed we should move this into a separate function
 * since this should be kept fast for edit-mode switching and storing undo steps.
 *
 * \warning This function doesn't calculate face normals.
 */
void BM_mesh_bm_from_me(
        BMesh *bm, Mesh *me,
        const struct BMeshFromMeshParams *params)
{
	const bool is_new =
	        !(bm->totvert ||
	          (bm->vdata.totlayer || bm->edata.totlayer || bm->pdata.totlayer || bm->ldata.totlayer));
	MVert *mvert;
	MEdge *medge;
	MLoop *mloop;
	MPoly *mp;
	KeyBlock *actkey, *block;
	BMVert *v, **vtable = NULL;
	BMEdge *e, **etable = NULL;
	BMFace *f, **ftable = NULL;
	float (*keyco)[3] = NULL;
	int totuv, totloops, i;

	if (!me || !me->totvert) {
		if (me && is_new) { /*no verts? still copy customdata layout*/
			CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0);
			CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0);
			CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0);
			CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_ASSIGN, 0);

			CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
			CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
			CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
			CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
		}
		return; /* sanity check */
	}

	if (is_new) {
		CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
		CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
		CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
		CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);

		/* make sure uv layer names are consisten */
		totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
		for (i = 0; i < totuv; i++) {
			int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
			CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
		}
	}

	/* -------------------------------------------------------------------- */
	/* Shape Key */
	int tot_shape_keys = me->key ? BLI_listbase_count(&me->key->block) : 0;
	if (is_new == false) {
		tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY));
	}
	const float (**shape_key_table)[3] = tot_shape_keys ? BLI_array_alloca(shape_key_table, tot_shape_keys) : NULL;

	if ((params->active_shapekey != 0) && (me->key != NULL)) {
		actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
	}
	else {
		actkey = NULL;
	}

	if (is_new) {
		if (tot_shape_keys || params->add_key_index) {
			CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
		}
	}

	if (tot_shape_keys) {
		if (is_new) {
			/* check if we need to generate unique ids for the shapekeys.
			 * this also exists in the file reading code, but is here for
			 * a sanity check */
			if (!me->key->uidgen) {
				fprintf(stderr,
				        "%s had to generate shape key uid's in a situation we shouldn't need to! "
				        "(bmesh internal error)\n",
				        __func__);

				me->key->uidgen = 1;
				for (block = me->key->block.first; block; block = block->next) {
					block->uid = me->key->uidgen++;
				}
			}
		}

		if (actkey && actkey->totelem == me->totvert) {
			keyco = params->use_shapekey ? actkey->data : NULL;
			if (is_new) {
				bm->shapenr = params->active_shapekey;
			}
		}

		for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) {
			if (is_new) {
				CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
				                           CD_ASSIGN, NULL, 0, block->name);
				int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
				bm->vdata.layers[j].uid = block->uid;
			}
			shape_key_table[i] = (const float (*)[3])block->data;
		}
	}

	if (is_new) {
		CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
		CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
		CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
		CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);

		BM_mesh_cd_flag_apply(bm, me->cd_flag);
	}

	const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
	const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
	const int cd_edge_crease_offset  = CustomData_get_offset(&bm->edata, CD_CREASE);
	const int cd_shape_key_offset = me->key ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) : -1;
	const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ?
	          CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) : -1;

	vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);

	for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
		v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
		BM_elem_index_set(v, i); /* set_ok */

		/* transfer flag */
		v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);

		/* this is necessary for selection counts to work properly */
		if (mvert->flag & SELECT) {
			BM_vert_select_set(bm, v, true);
		}

		normal_short_to_float_v3(v->no, mvert->no);

		/* Copy Custom Data */
		CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);

		if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);

		/* set shape key original index */
		if (cd_shape_keyindex_offset != -1) BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);

		/* set shapekey data */
		if (tot_shape_keys) {
			float (*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
			for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
				copy_v3_v3(*co_dst, shape_key_table[j][i]);
			}
		}
	}
	if (is_new) {
		bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */
	}

	etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);

	medge = me->medge;
	for (i = 0; i < me->totedge; i++, medge++) {
		e = etable[i] = BM_edge_create(bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD);
		BM_elem_index_set(e, i); /* set_ok */

		/* transfer flags */
		e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);

		/* this is necessary for selection counts to work properly */
		if (medge->flag & SELECT) {
			BM_edge_select_set(bm, e, true);
		}

		/* Copy Custom Data */
		CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);

		if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f);
		if (cd_edge_crease_offset  != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset,  (float)medge->crease  / 255.0f);

	}
	if (is_new) {
		bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */
	}

	/* only needed for selection. */
	if (me->mselect && me->totselect != 0) {
		ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__);
	}

	mloop = me->mloop;
	mp = me->mpoly;
	for (i = 0, totloops = 0; i < me->totpoly; i++, mp++) {
		BMLoop *l_iter;
		BMLoop *l_first;

		f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart,
		                              bm, vtable, etable);
		if (ftable != NULL) {
			ftable[i] = f;
		}

		if (UNLIKELY(f == NULL)) {
			printf("%s: Warning! Bad face in mesh"
			       " \"%s\" at index %d!, skipping\n",
			       __func__, me->id.name + 2, i);
			continue;
		}

		/* don't use 'i' since we may have skipped the face */
		BM_elem_index_set(f, bm->totface - 1); /* set_ok */

		/* transfer flag */
		f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL);

		/* this is necessary for selection counts to work properly */
		if (mp->flag & ME_FACE_SEL) {
			BM_face_select_set(bm, f, true);
		}

		f->mat_nr = mp->mat_nr;
		if (i == me->act_face) bm->act_face = f;

		int j = mp->loopstart;
		l_iter = l_first = BM_FACE_FIRST_LOOP(f);
		do {
			/* don't use 'j' since we may have skipped some faces, hence some loops. */
			BM_elem_index_set(l_iter, totloops++); /* set_ok */

			/* Save index of correspsonding MLoop */
			CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true);
		} while ((l_iter = l_iter->next) != l_first);

		/* Copy Custom Data */
		CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true);

		if (params->calc_face_normal) {
			BM_face_normal_update(f);
		}
	}
	if (is_new) {
		bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
	}

	/* -------------------------------------------------------------------- */
	/* MSelect clears the array elements (avoid adding multiple times).
	 *
	 * Take care to keep this last and not use (v/e/ftable) after this.
	 */

	if (me->mselect && me->totselect != 0) {
		MSelect *msel;
		for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
			BMElem **ele_p;
			switch (msel->type) {
				case ME_VSEL:
					ele_p = (BMElem **)&vtable[msel->index];
					break;
				case ME_ESEL:
					ele_p = (BMElem **)&etable[msel->index];
					break;
				case ME_FSEL:
					ele_p = (BMElem **)&ftable[msel->index];
					break;
				default:
					continue;
			}

			if (*ele_p != NULL) {
				BM_select_history_store_notest(bm, *ele_p);
				*ele_p = NULL;
			}
		}
	}
	else {
		BM_select_history_clear(bm);
	}

	MEM_freeN(vtable);
	MEM_freeN(etable);
	if (ftable) {
		MEM_freeN(ftable);
	}
}
コード例 #11
0
static bool data_transfer_layersmapping_cdlayers(
        ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
        const int num_elem_dst, const bool use_create, const bool use_delete,
        CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
        const int fromlayers, const int tolayers)
{
	int idx_src, idx_dst;
	void *data_src, *data_dst = NULL;

	if (CustomData_layertype_is_singleton(cddata_type)) {
		if (!(data_src = CustomData_get_layer(cd_src, cddata_type))) {
			if (use_delete) {
				CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, 0);
			}
			return true;
		}

		data_dst = CustomData_get_layer(cd_dst, cddata_type);
		if (!data_dst) {
			if (!use_create) {
				return true;
			}
			data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
		}
		else if (use_dupref_dst && r_map) {
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst);
		}

		if (r_map) {
			data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
			                                        data_src, data_dst);
		}
	}
	else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
		/* Note: use_delete has not much meaning in this case, ignored. */

		if (fromlayers >= 0) {  /* Real-layer index */
			idx_src = fromlayers;
		}
		else {
			if ((idx_src = CustomData_get_active_layer(cd_src, cddata_type)) == -1) {
				return true;
			}
		}
		data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
		if (!data_src) {
			return true;
		}

		if (tolayers >= 0) {  /* Real-layer index */
			idx_dst = tolayers;
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			if (use_dupref_dst && r_map) {
				data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
			}
			else {
				data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
			}
		}
		else if (tolayers == DT_LAYERS_ACTIVE_DST) {
			if ((idx_dst = CustomData_get_active_layer(cd_dst, cddata_type)) == -1) {
				if (!use_create) {
					return true;
				}
				data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
			}
			else {
				/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
				if (use_dupref_dst && r_map) {
					data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
				}
				else {
					data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
				}
			}
		}
		else if (tolayers == DT_LAYERS_INDEX_DST) {
			int num = CustomData_number_of_layers(cd_dst, cddata_type);
			idx_dst = idx_src;
			if (num <= idx_dst) {
				if (!use_create) {
					return true;
				}
				/* Create as much data layers as necessary! */
				for (; num <= idx_dst; num++) {
					CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
				}
			}
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			if (use_dupref_dst && r_map) {
				data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
			}
			else {
				data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
			}
		}
		else if (tolayers == DT_LAYERS_NAME_DST) {
			const char *name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
			if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
				if (!use_create) {
					return true;
				}
				CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
				idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
			}
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			if (use_dupref_dst && r_map) {
				data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
			}
			else {
				data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
			}
		}
		else {
			return false;
		}

		if (!data_dst) {
			return false;
		}

		if (r_map) {
			data_transfer_layersmapping_add_item_cd(
			        r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst);
		}
	}
	else if (fromlayers == DT_LAYERS_ALL_SRC) {
		int num_src = CustomData_number_of_layers(cd_src, cddata_type);
		bool *use_layers_src = num_src ? MEM_mallocN(sizeof(*use_layers_src) * (size_t)num_src, __func__) : NULL;
		bool ret;

		if (use_layers_src) {
			memset(use_layers_src, true, sizeof(*use_layers_src) * num_src);
		}

		ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst(
		        r_map, cddata_type, mix_mode, mix_factor, mix_weights,
		        num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst,
		        tolayers, use_layers_src, num_src);

		if (use_layers_src) {
			MEM_freeN(use_layers_src);
		}
		return ret;
	}
	else {
		return false;
	}

	return true;
}
コード例 #12
0
static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
        ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
        const int num_elem_dst, const bool use_create, const bool use_delete,
        CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
        const int tolayers, bool *use_layers_src, const int num_layers_src)
{
	void *data_src, *data_dst = NULL;
	int idx_src = num_layers_src;
	int idx_dst, tot_dst = CustomData_number_of_layers(cd_dst, cddata_type);
	bool *data_dst_to_delete = NULL;

	if (!use_layers_src) {
		/* No source at all, we can only delete all dest if requested... */
		if (use_delete) {
			idx_dst = tot_dst;
			while (idx_dst--) {
				CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
			}
		}
		return true;
	}

	switch (tolayers) {
		case DT_LAYERS_INDEX_DST:
			idx_dst = tot_dst;

			/* Find last source actually used! */
			while (idx_src-- && !use_layers_src[idx_src]);
			idx_src++;

			if (idx_dst < idx_src) {
				if (!use_create) {
					return true;
				}
				/* Create as much data layers as necessary! */
				for (; idx_dst < idx_src; idx_dst++) {
					CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
				}
			}
			else if (use_delete && idx_dst > idx_src) {
				while (idx_dst-- > idx_src) {
					CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
				}
			}
			if (r_map) {
				while (idx_src--) {
					if (!use_layers_src[idx_src]) {
						continue;
					}
					data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
					/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
					if (use_dupref_dst) {
						data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst);
					}
					else {
						data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src);
					}
					data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
					                                        data_src, data_dst);
				}
			}
			break;
		case DT_LAYERS_NAME_DST:
			if (use_delete) {
				if (tot_dst) {
					data_dst_to_delete = MEM_mallocN(sizeof(*data_dst_to_delete) * (size_t)tot_dst, __func__);
					memset(data_dst_to_delete, true, sizeof(*data_dst_to_delete) * (size_t)tot_dst);
				}
			}

			while (idx_src--) {
				const char *name;

				if (!use_layers_src[idx_src]) {
					continue;
				}

				name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
				data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);

				if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
					if (!use_create) {
						if (r_map) {
							BLI_freelistN(r_map);
						}
						return true;
					}
					CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
					idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
				}
				else if (data_dst_to_delete) {
					data_dst_to_delete[idx_dst] = false;
				}
				if (r_map) {
					/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
					if (use_dupref_dst) {
						data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
					}
					else {
						data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
					}
					data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
					                                        data_src, data_dst);
				}
			}

			if (data_dst_to_delete) {
				/* Note: This won't affect newly created layers, if any, since tot_dst has not been updated!
				 *       Also, looping backward ensures us we do not suffer from index shifting when deleting a layer.
				 */
				for (idx_dst = tot_dst; idx_dst--;) {
					if (data_dst_to_delete[idx_dst]) {
						CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
					}
				}

				MEM_freeN(data_dst_to_delete);
			}
			break;
		default:
			return false;
	}

	return true;
}
コード例 #13
0
// =================================================================
// Return the number of faces by summing up
// the facecounts of the parts.
// hint: This is done because mesh->getFacesCount() does
// count loose edges as extra faces, which is not what we want here.
// =================================================================
void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
	COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives();
	int total_poly_count  = 0;
	int total_loop_count  = 0;

	// collect edge_count and face_count from all parts
	for (int i = 0; i < prim_arr.getCount(); i++) {
		COLLADAFW::MeshPrimitive *mp = prim_arr[i];
		int type = mp->getPrimitiveType();
		switch (type) {
			case COLLADAFW::MeshPrimitive::TRIANGLES:
			case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
			case COLLADAFW::MeshPrimitive::POLYLIST:
			case COLLADAFW::MeshPrimitive::POLYGONS:
			{
				COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
				size_t prim_poly_count    = mpvc->getFaceCount();

				size_t prim_loop_count    = 0;
				for (int index=0; index < prim_poly_count; index++) {
					prim_loop_count += get_vertex_count(mpvc, index);
				}

				total_poly_count += prim_poly_count;
				total_loop_count += prim_loop_count;

				break;
			}
			default:
				break;
		}
	}

	// Add the data containers
	if (total_poly_count > 0) {
		me->totpoly = total_poly_count;
		me->totloop = total_loop_count;
		me->mpoly   = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, me->totpoly);
		me->mloop   = (MLoop *)CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, me->totloop);

		unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount();
		for (int i = 0; i < totuvset; i++) {
			if (collada_mesh->getUVCoords().getLength(i) == 0) {
				totuvset = 0;
				break;
			}
		}

		if (totuvset > 0) {
			for (int i = 0; i < totuvset; i++) {
				COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i];
				COLLADAFW::String &uvname = info->mName;
				// Allocate space for UV_data
				CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str());
				CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str());
			}
			// activate the first uv map
			me->mtpoly  = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0);
			me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0);
		}

		int totcolset = collada_mesh->getColors().getInputInfosArray().getCount();
		if (totcolset > 0) {
			for (int i = 0; i < totcolset; i++) {
				COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getColors().getInputInfosArray()[i];
				COLLADAFW::String colname = extract_vcolname(info->mName);
				CustomData_add_layer_named(&me->ldata,CD_MLOOPCOL,CD_DEFAULT,NULL,me->totloop, colname.c_str());
			}
			me->mloopcol = (MLoopCol *) CustomData_get_layer_n(&me->ldata, CD_MLOOPCOL, 0);
		}

	}
}
コード例 #14
0
ファイル: bmesh_mesh_conv.c プロジェクト: doug65536/blender
/**
 * \brief Mesh -> BMesh
 *
 * \warning This function doesn't calculate face normals.
 */
void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
                        const bool calc_face_normal, const bool set_key, int act_key_nr)
{
	MVert *mvert;
	MEdge *medge;
	MLoop *mloop;
	MPoly *mp;
	KeyBlock *actkey, *block;
	BMVert *v, **vtable = NULL;
	BMEdge *e, **etable = NULL;
	BMFace *f;
	float (*keyco)[3] = NULL;
	int *keyi;
	int totuv, i, j;

	int cd_vert_bweight_offset;
	int cd_edge_bweight_offset;
	int cd_edge_crease_offset;

	/* free custom data */
	/* this isnt needed in most cases but do just incase */
	CustomData_free(&bm->vdata, bm->totvert);
	CustomData_free(&bm->edata, bm->totedge);
	CustomData_free(&bm->ldata, bm->totloop);
	CustomData_free(&bm->pdata, bm->totface);

	if (!me || !me->totvert) {
		if (me) { /*no verts? still copy customdata layout*/
			CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_ASSIGN, 0);
			CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_ASSIGN, 0);
			CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_ASSIGN, 0);
			CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_ASSIGN, 0);

			CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
			CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
			CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
			CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
		}
		return; /* sanity check */
	}

	vtable = MEM_mallocN(sizeof(void **) * me->totvert, "mesh to bmesh vtable");

	CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
	CustomData_copy(&me->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
	CustomData_copy(&me->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
	CustomData_copy(&me->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);

	/* make sure uv layer names are consisten */
	totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
	for (i = 0; i < totuv; i++) {
		int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i);
		CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name);
	}

	if ((act_key_nr != 0) && (me->key != NULL)) {
		actkey = BLI_findlink(&me->key->block, act_key_nr - 1);
	}
	else {
		actkey = NULL;
	}

	if (me->key) {
		CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);

		/* check if we need to generate unique ids for the shapekeys.
		 * this also exists in the file reading code, but is here for
		 * a sanity check */
		if (!me->key->uidgen) {
			fprintf(stderr,
			        "%s had to generate shape key uid's in a situation we shouldn't need to! "
			        "(bmesh internal error)\n",
			        __func__);

			me->key->uidgen = 1;
			for (block = me->key->block.first; block; block = block->next) {
				block->uid = me->key->uidgen++;
			}
		}

		if (actkey && actkey->totelem == me->totvert) {
			keyco = actkey->data;
			bm->shapenr = act_key_nr;
		}

		for (i = 0, block = me->key->block.first; block; block = block->next, i++) {
			CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY,
			                           CD_ASSIGN, NULL, 0, block->name);

			j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
			bm->vdata.layers[j].uid = block->uid;
		}
	}

	CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT);
	CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
	CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
	CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);

	BM_mesh_cd_flag_apply(bm, me->cd_flag);

	cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
	cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
	cd_edge_crease_offset  = CustomData_get_offset(&bm->edata, CD_CREASE);

	for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
		v = vtable[i] = BM_vert_create(bm, keyco && set_key ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
		BM_elem_index_set(v, i); /* set_ok */

		/* transfer flag */
		v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);

		/* this is necessary for selection counts to work properly */
		if (mvert->flag & SELECT) {
			BM_vert_select_set(bm, v, true);
		}

		normal_short_to_float_v3(v->no, mvert->no);

		/* Copy Custom Data */
		CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);

		if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);

		/* set shapekey data */
		if (me->key) {
			/* set shape key original index */
			keyi = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_SHAPE_KEYINDEX);
			if (keyi) {
				*keyi = i;
			}

			for (block = me->key->block.first, j = 0; block; block = block->next, j++) {
				float *co = CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, j);

				if (co) {
					copy_v3_v3(co, ((float *)block->data) + 3 * i);
				}
			}
		}
	}

	bm->elem_index_dirty &= ~BM_VERT; /* added in order, clear dirty flag */

	if (!me->totedge) {
		MEM_freeN(vtable);
		return;
	}

	etable = MEM_mallocN(sizeof(void **) * me->totedge, "mesh to bmesh etable");

	medge = me->medge;
	for (i = 0; i < me->totedge; i++, medge++) {
		e = etable[i] = BM_edge_create(bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD);
		BM_elem_index_set(e, i); /* set_ok */

		/* transfer flags */
		e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);

		/* this is necessary for selection counts to work properly */
		if (medge->flag & SELECT) {
			BM_edge_select_set(bm, e, true);
		}

		/* Copy Custom Data */
		CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);

		if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f);
		if (cd_edge_crease_offset  != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset,  (float)medge->crease  / 255.0f);

	}

	bm->elem_index_dirty &= ~BM_EDGE; /* added in order, clear dirty flag */

	mloop = me->mloop;
	mp = me->mpoly;
	for (i = 0; i < me->totpoly; i++, mp++) {
		BMLoop *l_iter;
		BMLoop *l_first;

		f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart,
		                              bm, vtable, etable);

		if (UNLIKELY(f == NULL)) {
			printf("%s: Warning! Bad face in mesh"
			       " \"%s\" at index %d!, skipping\n",
			       __func__, me->id.name + 2, i);
			continue;
		}

		/* don't use 'i' since we may have skipped the face */
		BM_elem_index_set(f, bm->totface - 1); /* set_ok */

		/* transfer flag */
		f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL);

		/* this is necessary for selection counts to work properly */
		if (mp->flag & ME_FACE_SEL) {
			BM_face_select_set(bm, f, true);
		}

		f->mat_nr = mp->mat_nr;
		if (i == me->act_face) bm->act_face = f;

		j = mp->loopstart;
		l_iter = l_first = BM_FACE_FIRST_LOOP(f);
		do {
			/* Save index of correspsonding MLoop */
			CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true);
		} while ((l_iter = l_iter->next) != l_first);

		/* Copy Custom Data */
		CustomData_to_bmesh_block(&me->pdata, &bm->pdata, i, &f->head.data, true);

		if (calc_face_normal) {
			BM_face_normal_update(f);
		}
	}

	bm->elem_index_dirty &= ~BM_FACE; /* added in order, clear dirty flag */

	if (me->mselect && me->totselect != 0) {

		BMVert **vert_array = MEM_mallocN(sizeof(BMVert *) * bm->totvert, "VSelConv");
		BMEdge **edge_array = MEM_mallocN(sizeof(BMEdge *) * bm->totedge, "ESelConv");
		BMFace **face_array = MEM_mallocN(sizeof(BMFace *) * bm->totface, "FSelConv");
		MSelect *msel;

#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
		{
#pragma omp section
			{ BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)vert_array, bm->totvert); }
#pragma omp section
			{ BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edge_array, bm->totedge); }
#pragma omp section
			{ BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)face_array, bm->totface); }
		}

		for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
			switch (msel->type) {
				case ME_VSEL:
					BM_select_history_store(bm, (BMElem *)vert_array[msel->index]);
					break;
				case ME_ESEL:
					BM_select_history_store(bm, (BMElem *)edge_array[msel->index]);
					break;
				case ME_FSEL:
					BM_select_history_store(bm, (BMElem *)face_array[msel->index]);
					break;
			}
		}

		MEM_freeN(vert_array);
		MEM_freeN(edge_array);
		MEM_freeN(face_array);
	}
	else {
		me->totselect = 0;
		if (me->mselect) {
			MEM_freeN(me->mselect);
			me->mselect = NULL;
		}
	}

	MEM_freeN(vtable);
	MEM_freeN(etable);
}
コード例 #15
0
ファイル: mesh_convert.c プロジェクト: wangyxuan/blender
/* this may fail replacing ob->data, be sure to check ob->type */
void BKE_mesh_from_nurbs_displist(Main *bmain,
                                  Object *ob,
                                  ListBase *dispbase,
                                  const bool use_orco_uv,
                                  const char *obdata_name,
                                  bool temporary)
{
  Object *ob1;
  Mesh *me_eval = ob->runtime.mesh_eval;
  Mesh *me;
  Curve *cu;
  MVert *allvert = NULL;
  MEdge *alledge = NULL;
  MLoop *allloop = NULL;
  MLoopUV *alluv = NULL;
  MPoly *allpoly = NULL;
  int totvert, totedge, totloop, totpoly;

  cu = ob->data;

  if (me_eval == NULL) {
    if (BKE_mesh_nurbs_displist_to_mdata(ob,
                                         dispbase,
                                         &allvert,
                                         &totvert,
                                         &alledge,
                                         &totedge,
                                         &allloop,
                                         &allpoly,
                                         (use_orco_uv) ? &alluv : NULL,
                                         &totloop,
                                         &totpoly) != 0) {
      /* Error initializing */
      return;
    }

    /* make mesh */
    me = BKE_mesh_add(bmain, obdata_name);
    me->totvert = totvert;
    me->totedge = totedge;
    me->totloop = totloop;
    me->totpoly = totpoly;

    me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
    me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
    me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
    me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);

    if (alluv) {
      const char *uvname = "Orco";
      me->mloopuv = CustomData_add_layer_named(
          &me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
    }

    BKE_mesh_calc_normals(me);
  }
  else {
    me = BKE_mesh_add(bmain, obdata_name);
    ob->runtime.mesh_eval = NULL;
    BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true);
  }

  me->totcol = cu->totcol;
  me->mat = cu->mat;

  /* Copy evaluated texture space from curve to mesh.
   *
   * Note that we disable auto texture space feature since that will cause
   * texture space to evaluate differently for curve and mesh, since curve
   * uses CV to calculate bounding box, and mesh uses what is coming from
   * tessellated curve.
   */
  me->texflag = cu->texflag & ~CU_AUTOSPACE;
  copy_v3_v3(me->loc, cu->loc);
  copy_v3_v3(me->size, cu->size);
  copy_v3_v3(me->rot, cu->rot);
  BKE_mesh_texspace_calc(me);

  cu->mat = NULL;
  cu->totcol = 0;

  /* Do not decrement ob->data usercount here,
   * it's done at end of func with BKE_id_free_us() call. */
  ob->data = me;
  ob->type = OB_MESH;

  /* other users */
  ob1 = bmain->objects.first;
  while (ob1) {
    if (ob1->data == cu) {
      ob1->type = OB_MESH;

      id_us_min((ID *)ob1->data);
      ob1->data = ob->data;
      id_us_plus((ID *)ob1->data);
    }
    ob1 = ob1->id.next;
  }

  if (temporary) {
    /* For temporary objects in BKE_mesh_new_from_object don't remap
     * the entire scene with associated depsgraph updates, which are
     * problematic for renderers exporting data. */
    BKE_id_free(NULL, cu);
  }
  else {
    BKE_id_free_us(bmain, cu);
  }
}
コード例 #16
0
ファイル: mesh_navmesh.c プロジェクト: BHCLL/blendocv
static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base* base)
{
	float co[3], rot[3];
	EditMesh *em;
	int i,j, k;
	unsigned short* v;
	int face[3];
	Scene *scene= CTX_data_scene(C);
	Object* obedit;
	int createob= base==NULL;
	int nverts, nmeshes, nvp;
	unsigned short *verts, *polys;
	unsigned int *meshes;
	float bmin[3], cs, ch, *dverts;
	unsigned char *tris;

	zero_v3(co);
	zero_v3(rot);

	if(createob) {
		/* create new object */
		obedit= ED_object_add_type(C, OB_MESH, co, rot, FALSE, 1);
	}
	else {
		obedit= base->object;
		scene_select_base(scene, base);
		copy_v3_v3(obedit->loc, co);
		copy_v3_v3(obedit->rot, rot);
	}

	ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER);
	em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));

	if(!createob) {
		/* clear */
		if(em->verts.first) free_vertlist(em, &em->verts);
		if(em->edges.first) free_edgelist(em, &em->edges);
		if(em->faces.first) free_facelist(em, &em->faces);
		if(em->selected.first) BLI_freelistN(&(em->selected));
	}

	/* create verts for polygon mesh */
	verts= recast_polyMeshGetVerts(pmesh, &nverts);
	recast_polyMeshGetBoundbox(pmesh, bmin, NULL);
	recast_polyMeshGetCell(pmesh, &cs, &ch);

	for(i= 0; i<nverts; i++) {
		v= &verts[3*i];
		co[0]= bmin[0] + v[0]*cs;
		co[1]= bmin[1] + v[1]*ch;
		co[2]= bmin[2] + v[2]*cs;
		SWAP(float, co[1], co[2]);
		addvertlist(em, co, NULL);
	}

	/* create custom data layer to save polygon idx */
	CustomData_add_layer_named(&em->fdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");

	/* create verts and faces for detailed mesh */
	meshes= recast_polyMeshDetailGetMeshes(dmesh, &nmeshes);
	polys= recast_polyMeshGetPolys(pmesh, NULL, &nvp);
	dverts= recast_polyMeshDetailGetVerts(dmesh, NULL);
	tris= recast_polyMeshDetailGetTris(dmesh, NULL);

	for(i= 0; i<nmeshes; i++) {
		int uniquevbase= em->totvert;
		unsigned int vbase= meshes[4*i+0];
		unsigned short ndv= meshes[4*i+1];
		unsigned short tribase= meshes[4*i+2];
		unsigned short trinum= meshes[4*i+3];
		const unsigned short* p= &polys[i*nvp*2];
		int nv= 0;

		for(j= 0; j < nvp; ++j) {
			if(p[j]==0xffff) break;
			nv++;
		}

		/* create unique verts  */
		for(j= nv; j<ndv; j++) {
			copy_v3_v3(co, &dverts[3*(vbase + j)]);
			SWAP(float, co[1], co[2]);
			addvertlist(em, co, NULL);
		}

		EM_init_index_arrays(em, 1, 0, 0);

		/* create faces */
		for(j= 0; j<trinum; j++) {
			unsigned char* tri= &tris[4*(tribase+j)];
			EditFace* newFace;
			int* polygonIdx;

			for(k= 0; k<3; k++) {
				if(tri[k]<nv)
					face[k]= p[tri[k]]; /* shared vertex */
				else
					face[k]= uniquevbase+tri[k]-nv; /* unique vertex */
			}
			newFace= addfacelist(em, EM_get_vert_for_index(face[0]), EM_get_vert_for_index(face[2]),
									EM_get_vert_for_index(face[1]), NULL, NULL, NULL);

			/* set navigation polygon idx to the custom layer */
			polygonIdx= (int*)CustomData_em_get(&em->fdata, newFace->data, CD_RECAST);
			*polygonIdx= i+1; /* add 1 to avoid zero idx */
		}
		
		EM_free_index_arrays();
	}

	recast_destroyPolyMesh(pmesh);
	recast_destroyPolyMeshDetail(dmesh);

	BKE_mesh_end_editmesh((Mesh*)obedit->data, em);
	
	DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA);
	WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);


	ED_object_exit_editmode(C, EM_FREEDATA); 
	WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);

	if(createob) {
		obedit->gameflag&= ~OB_COLLISION;
		obedit->gameflag|= OB_NAVMESH;
		obedit->body_type= OB_BODY_TYPE_NAVMESH;
		rename_id((ID *)obedit, "Navmesh");
	}

	BKE_mesh_ensure_navmesh(obedit->data);

	return obedit;
}