static DMDrawOption draw_em_tf_mapped__set_draw(void *userData, int origindex, int mat_nr)
{
	drawEMTFMapped_userData *data = userData;
	BMEditMesh *em = data->em;
	BMFace *efa;

	if (UNLIKELY(origindex >= em->bm->totface))
		return DM_DRAW_OPTION_NORMAL;

	efa = BM_face_at_index(em->bm, origindex);

	if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
		return DM_DRAW_OPTION_SKIP;
	}
	else {
		MTexPoly *mtexpoly = (data->cd_poly_tex_offset != -1) ?
		        BM_ELEM_CD_GET_VOID_P(efa, data->cd_poly_tex_offset) : NULL;
		int matnr = (mat_nr != -1) ? mat_nr : efa->mat_nr;

		return draw_tface__set_draw_legacy(mtexpoly, data->has_mcol, matnr);
	}
}
Beispiel #2
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);
	}
}
Beispiel #3
0
/* calculates offset for co, based on fractal, sphere or smooth settings  */
static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params, float perc,
                     BMVert *vsta, BMVert *vend)
{
	float tvec[3], fac;
	float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
	int i;

	copy_v3_v3(co, v->co);

	if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
		normalize_v3(co);
		mul_v3_fl(co, params->smooth);
	}
	else if (params->use_smooth) {
		/* we calculate an offset vector vec1[], to be added to *co */
		float len, nor[3], nor1[3], nor2[3], val;

		sub_v3_v3v3(nor, vsta->co, vend->co);
		len = 0.5f * normalize_v3(nor);

		copy_v3_v3(nor1, vsta->no);
		copy_v3_v3(nor2, vend->no);

		/* cosine angle */
		fac = dot_v3v3(nor, nor1);
		mul_v3_v3fl(tvec, nor1, fac);

		/* cosine angle */
		fac = -dot_v3v3(nor, nor2);
		madd_v3_v3fl(tvec, nor2, fac);

		/* falloff for multi subdivide */
		val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
		val = bmesh_subd_falloff_calc(params->smooth_falloff, val);

		if (params->use_smooth_even) {
			val *= BM_vert_calc_shell_factor(v);
		}

		mul_v3_fl(tvec, params->smooth * val * len);

		add_v3_v3(co, tvec);
	}

	if (params->use_fractal) {
		const float len = len_v3v3(vsta->co, vend->co);
		float normal[3], co2[3], base1[3], base2[3];

		fac = params->fractal * len;

		mid_v3_v3v3(normal, vsta->no, vend->no);
		ortho_basis_v3v3_v3(base1, base2, normal);

		add_v3_v3v3(co2, v->co, params->fractal_ofs);
		mul_v3_fl(co2, 10.0f);

		tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f);
		tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f);
		tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f);

		/* add displacement */
		madd_v3_v3fl(co, normal, tvec[0]);
		madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal));
		madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal));
	}

	/* apply the new difference to the rest of the shape keys,
	 * note that this doesn't take rotations into account, we _could_ support
	 * this by getting the normals and coords for each shape key and
	 * re-calculate the smooth value for each but this is quite involved.
	 * for now its ok to simply apply the difference IMHO - campbell */
	sub_v3_v3v3(tvec, v->co, co);

	if (params->shape_info.totlayer > 1) {
		/* skip the last layer since its the temp */
		i = params->shape_info.totlayer - 1;
		co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset);
		while (i--) {
			BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
			sub_v3_v3(co += 3, tvec);
		}
	}
}
/* calculates offset for co, based on fractal, sphere or smooth settings  */
static void alter_co(
        BMVert *v, BMEdge *UNUSED(e_orig),
        const SubDParams *params, const float perc,
        const BMVert *v_a, const BMVert *v_b)
{
	float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
	int i;

	copy_v3_v3(co, v->co);

	if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
		normalize_v3(co);
		mul_v3_fl(co, params->smooth);
	}
	else if (params->use_smooth) {
		/* calculating twice and blending gives smoother results,
		 * removing visible seams. */
#define USE_SPHERE_DUAL_BLEND

		const float eps_unit_vec = 1e-5f;
		float smooth;
		float no_dir[3];

#ifdef USE_SPHERE_DUAL_BLEND
		float no_reflect[3], co_a[3], co_b[3];
#endif

		sub_v3_v3v3(no_dir, v_a->co, v_b->co);
		normalize_v3(no_dir);

#ifndef USE_SPHERE_DUAL_BLEND
		if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) {
			interp_v3_v3v3(co, v_a->co, v_b->co, perc);
		}
		else {
			interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co);
		}
#else
		/* sphere-a */
		reflect_v3_v3v3(no_reflect, v_a->no, no_dir);
		if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) {
			interp_v3_v3v3(co_a, v_a->co, v_b->co, perc);
		}
		else {
			interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a);
		}

		/* sphere-b */
		reflect_v3_v3v3(no_reflect, v_b->no, no_dir);
		if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) {
			interp_v3_v3v3(co_b, v_a->co, v_b->co, perc);
		}
		else {
			interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b);
		}

		/* blend both spheres */
		interp_v3_v3v3(co, co_a, co_b, perc);
#endif  /* USE_SPHERE_DUAL_BLEND */

		/* apply falloff */
		if (params->smooth_falloff == SUBD_FALLOFF_LIN) {
			smooth = 1.0f;
		}
		else {
			smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
			smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth);
		}

		if (params->use_smooth_even) {
			smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
		}

		smooth *= params->smooth;
		if (smooth != 1.0f) {
			float co_flat[3];
			interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc);
			interp_v3_v3v3(co, co_flat, co, smooth);
		}

#undef USE_SPHERE_DUAL_BLEND
	}

	if (params->use_fractal) {
		float normal[3], co2[3], base1[3], base2[3], tvec[3];
		const float len = len_v3v3(v_a->co, v_b->co);
		float fac;

		fac = params->fractal * len;

		mid_v3_v3v3(normal, v_a->no, v_b->no);
		ortho_basis_v3v3_v3(base1, base2, normal);

		add_v3_v3v3(co2, v->co, params->fractal_ofs);
		mul_v3_fl(co2, 10.0f);

		tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f);
		tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f);
		tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f);

		/* add displacement */
		madd_v3_v3fl(co, normal, tvec[0]);
		madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal));
		madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal));
	}

	/* apply the new difference to the rest of the shape keys,
	 * note that this doesn't take rotations into account, we _could_ support
	 * this by getting the normals and coords for each shape key and
	 * re-calculate the smooth value for each but this is quite involved.
	 * for now its ok to simply apply the difference IMHO - campbell */

	if (params->shape_info.totlayer > 1) {
		float tvec[3];

		sub_v3_v3v3(tvec, v->co, co);

		/* skip the last layer since its the temp */
		i = params->shape_info.totlayer - 1;
		co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset);
		while (i--) {
			BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
			sub_v3_v3(co += 3, tvec);
		}
	}
}