Example #1
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);

	/* update modifier */
	if (omd->refresh & MOD_OCEAN_REFRESH_ADD)
		omd->ocean = BKE_add_ocean();
	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_simulate_ocean_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);
	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;
}
Example #2
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag flag)
{
	DerivedMesh *dm = derivedData;
	DerivedMesh *result;
	ScrewModifierData *ltmd = (ScrewModifierData *) md;
	const bool use_render_params = (flag & MOD_APPLY_RENDER) != 0;
	
	int *origindex;
	int mpoly_index = 0;
	unsigned int step;
	unsigned int i, j;
	unsigned int i1, i2;
	unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
	const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;

	const int quad_ord[4] = {
	    do_flip ? 3 : 0,
	    do_flip ? 2 : 1,
	    do_flip ? 1 : 2,
	    do_flip ? 0 : 3,
	};
	const int quad_ord_ofs[4] = {
	    do_flip ? 2 : 0,
	    1,
	    do_flip ? 0 : 2,
	    3,
	};

	unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
	const unsigned int totvert = (unsigned int)dm->getNumVerts(dm);
	const unsigned int totedge = (unsigned int)dm->getNumEdges(dm);
	const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm);

	unsigned int *edge_poly_map = NULL;  /* orig edge to orig poly */
	unsigned int *vert_loop_map = NULL;  /* orig vert to orig loop */

	/* UV Coords */
	const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
	MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
	float uv_u_scale;
	float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
	float uv_v_range_inv;
	float uv_axis_plane[4];

	char axis_char = 'X';
	bool close;
	float angle = ltmd->angle;
	float screw_ofs = ltmd->screw_ofs;
	float axis_vec[3] = {0.0f, 0.0f, 0.0f};
	float tmp_vec1[3], tmp_vec2[3]; 
	float mat3[3][3];
	float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */
	float mtx_tx_inv[4][4]; /* inverted */
	float mtx_tmp_a[4][4];
	
	unsigned int vc_tot_linked = 0;
	short other_axis_1, other_axis_2;
	const float *tmpf1, *tmpf2;

	unsigned int edge_offset;
	
	MPoly *mpoly_orig, *mpoly_new, *mp_new;
	MLoop *mloop_orig, *mloop_new, *ml_new;
	MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new;
	MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base;

	ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL;

	const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0;

	/* don't do anything? */
	if (!totvert)
		return CDDM_from_template(dm, 0, 0, 0, 0, 0);

	switch (ltmd->axis) {
		case 0:
			other_axis_1 = 1;
			other_axis_2 = 2;
			break;
		case 1:
			other_axis_1 = 0;
			other_axis_2 = 2;
			break;
		default: /* 2, use default to quiet warnings */
			other_axis_1 = 0;
			other_axis_2 = 1;
			break;
	}

	axis_vec[ltmd->axis] = 1.0f;

	if (ltmd->ob_axis) {
		/* calc the matrix relative to the axis object */
		invert_m4_m4(mtx_tmp_a, ob->obmat);
		copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat);
		mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv);

		/* calc the axis vec */
		mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */
		normalize_v3(axis_vec);

		/* screw */
		if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) {
			/* find the offset along this axis relative to this objects matrix */
			float totlen = len_v3(mtx_tx[3]);

			if (totlen != 0.0f) {
				float zero[3] = {0.0f, 0.0f, 0.0f};
				float cp[3];
				screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec);
			}
			else {
				screw_ofs = 0.0f;
			}
		}

		/* angle */

#if 0   /* cant incluide this, not predictable enough, though quite fun. */
		if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) {
			float mtx3_tx[3][3];
			copy_m3_m4(mtx3_tx, mtx_tx);

			float vec[3] = {0, 1, 0};
			float cross1[3];
			float cross2[3];
			cross_v3_v3v3(cross1, vec, axis_vec);

			mul_v3_m3v3(cross2, mtx3_tx, cross1);
			{
				float c1[3];
				float c2[3];
				float axis_tmp[3];

				cross_v3_v3v3(c1, cross2, axis_vec);
				cross_v3_v3v3(c2, axis_vec, c1);


				angle = angle_v3v3(cross1, c2);

				cross_v3_v3v3(axis_tmp, cross1, c2);
				normalize_v3(axis_tmp);

				if (len_v3v3(axis_tmp, axis_vec) > 1.0f)
					angle = -angle;

			}
		}
#endif
	}
	else {
		/* exis char is used by i_rotate*/
		axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */

		/* useful to be able to use the axis vec in some cases still */
		zero_v3(axis_vec);
		axis_vec[ltmd->axis] = 1.0f;
	}

	/* apply the multiplier */
	angle *= (float)ltmd->iter;
	screw_ofs *= (float)ltmd->iter;
	uv_u_scale = 1.0f / (float)(step_tot);

	/* multiplying the steps is a bit tricky, this works best */
	step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1);

	/* will the screw be closed?
	 * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */
	if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) &&
	    fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f))
	{
		close = 1;
		step_tot--;
		if (step_tot < 3) step_tot = 3;
	
		maxVerts = totvert  * step_tot;   /* -1 because we're joining back up */
		maxEdges = (totvert * step_tot) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys = totedge * step_tot;

		screw_ofs = 0.0f;
	}
	else {
		close = 0;
		if (step_tot < 3) step_tot = 3;

		maxVerts =  totvert  * step_tot; /* -1 because we're joining back up */
		maxEdges =  (totvert * (step_tot - 1)) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys =  totedge * (step_tot - 1);
	}

	if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) {
		uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f));
	}
	
	result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys);
	
	/* copy verts from mesh */
	mvert_orig =    dm->getVertArray(dm);
	medge_orig =    dm->getEdgeArray(dm);
	
	mvert_new =     result->getVertArray(result);
	mpoly_new =     result->getPolyArray(result);
	mloop_new =     result->getLoopArray(result);
	medge_new =     result->getEdgeArray(result);

	if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) {
		CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys);
	}

	origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */

	if (mloopuv_layers_tot) {
		float zero_co[3] = {0};
		plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec);
	}

	if (mloopuv_layers_tot) {
		unsigned int uv_lay;
		for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
			mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay);
		}

		if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
			for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) {
				const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane);
				uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]);
				uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]);
			}
			uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]);
			uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]);
		}

		uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0];
		uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f;
	}

	/* Set the locations of the first set of verts */
	
	mv_new = mvert_new;
	mv_orig = mvert_orig;
	
	/* Copy the first set of edges */
	med_orig = medge_orig;
	med_new = medge_new;
	for (i = 0; i < totedge; i++, med_orig++, med_new++) {
		med_new->v1 = med_orig->v1;
		med_new->v2 = med_orig->v2;
		med_new->crease = med_orig->crease;
		med_new->flag = med_orig->flag &  ~ME_LOOSEEDGE;
	}
	
	/* build polygon -> edge map */
	if (totpoly) {
		MPoly *mp_orig;

		mpoly_orig = dm->getPolyArray(dm);
		mloop_orig = dm->getLoopArray(dm);
		edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__);
		memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge);

		vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__);
		memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);

		for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
			unsigned int loopstart = (unsigned int)mp_orig->loopstart;
			unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop;

			MLoop *ml_orig = &mloop_orig[loopstart];
			unsigned int k;
			for (k = loopstart; k < loopend; k++, ml_orig++) {
				edge_poly_map[ml_orig->e] = i;
				vert_loop_map[ml_orig->v] = k;

				/* also order edges based on faces */
				if (medge_new[ml_orig->e].v1 != ml_orig->v) {
					SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
				}
			}
		}
	}
Example #3
0
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated)
{
	Object *ob, *ob_iter;
	Base *base = NULL;
	DupliObject *dob;
	DerivedMesh *dm;
	Mesh *me = par->data;
	MLoopUV *mloopuv;
	MPoly *mpoly, *mp;
	MLoop *mloop;
	MVert *mvert;
	float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w;
	int lay, oblay, totface, a;
	Scene *sce = NULL;
	Group *group = NULL;
	GroupObject *go = NULL;
	BMEditMesh *em;
	float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
	
	/* simple preventing of too deep nested groups */
	if (level > MAX_DUPLI_RECUR) return;
	
	copy_m4_m4(pmat, par->obmat);
	em = me->edit_btmesh;

	if (em) {
		dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
	}
	else {
		dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
	}

	totface = dm->getNumPolys(dm);
	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);
	mvert = dm->getVertArray(dm);

	if (G.rendering) {

		orco = (float(*)[3])BKE_mesh_orco_verts_get(par);
		BKE_mesh_orco_verts_transform(me, orco, me->totvert, 0);
		mloopuv = me->mloopuv;
	}
	else {
		orco = NULL;
		mloopuv = NULL;
	}
	
	/* having to loop on scene OR group objects is NOT FUN */
	if (GS(id->name) == ID_SCE) {
		sce = (Scene *)id;
		lay = sce->lay;
		base = sce->base.first;
	}
	else {
		group = (Group *)id;
		lay = group->layer;
		go = group->gobject.first;
	}
	
	/* Start looping on Scene OR Group objects */
	while (base || go) { 
		if (sce) {
			ob_iter = base->object;
			oblay = base->lay;
		}
		else {
			ob_iter = go->ob;
			oblay = ob_iter->lay;
		}
		
		if (lay & oblay && scene->obedit != ob_iter) {
			ob = ob_iter->parent;
			while (ob) {
				if (ob == par) {
					ob = ob_iter;
					/* End Scene/Group object loop, below is generic */
					
					/* par_space_mat - only used for groups so we can modify the space dupli's are in
					 * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat
					 */
					if (par_space_mat)
						mult_m4_m4m4(ob__obmat, par_space_mat, ob->obmat);
					else
						copy_m4_m4(ob__obmat, ob->obmat);
					
					copy_m3_m4(imat, ob->parentinv);
						
					/* mballs have a different dupli handling */
					if (ob->type != OB_MBALL) ob->flag |= OB_DONE;  /* doesnt render */

					for (a = 0, mp = mpoly; a < totface; a++, mp++) {
						int mv1;
						int mv2;
						int mv3;
						/* int mv4; */ /* UNUSED */
						float *v1;
						float *v2;
						float *v3;
						/* float *v4; */ /* UNUSED */
						float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
						MLoop *loopstart = mloop + mp->loopstart;

						if (mp->totloop < 3) {
							/* highly unlikely but to be safe */
							continue;
						}
						else {
							v1 = mvert[(mv1 = loopstart[0].v)].co;
							v2 = mvert[(mv2 = loopstart[1].v)].co;
							v3 = mvert[(mv3 = loopstart[2].v)].co;
#if 0
							if (mp->totloop > 3) {
								v4 = mvert[(mv4 = loopstart[3].v)].co;
							}
#endif
						}

						/* translation */
						BKE_mesh_calc_poly_center(mp, loopstart, mvert, cent);

						mul_m4_v3(pmat, cent);
						
						sub_v3_v3v3(cent, cent, pmat[3]);
						add_v3_v3(cent, ob__obmat[3]);
						
						copy_m4_m4(obmat, ob__obmat);
						
						copy_v3_v3(obmat[3], cent);
						
						/* rotation */
						tri_to_quat(quat, v1, v2, v3);
						quat_to_mat3(mat, quat);
						
						/* scale */
						if (par->transflag & OB_DUPLIFACES_SCALE) {
							float size = BKE_mesh_calc_poly_area(mp, loopstart, mvert, NULL);
							size = sqrtf(size) * par->dupfacesca;
							mul_m3_fl(mat, size);
						}
						
						copy_m3_m3(mat3, mat);
						mul_m3_m3m3(mat, imat, mat3);
						
						copy_m4_m4(tmat, obmat);
						mul_m4_m4m3(obmat, tmat, mat);
						
						dob = new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated);
						if (G.rendering) {
							w = 1.0f / (float)mp->totloop;

							if (orco) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
								}
							}

							if (mloopuv) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w);
								}
							}
						}
						
						if (ob->transflag & OB_DUPLI) {
							float tmpmat[4][4];
							copy_m4_m4(tmpmat, ob->obmat);
							copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */
							object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level + 1, animated);
							copy_m4_m4(ob->obmat, tmpmat);
						}
					}
					
					break;
				}
				ob = ob->parent;
			}
		}
		if (sce) base = base->next;     /* scene loop */
		else go = go->next;             /* group loop */
	}

	if (orco)
		MEM_freeN(orco);
	
	dm->release(dm);
}
Example #4
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	MaskModifierData *mmd = (MaskModifierData *)md;
	DerivedMesh *dm = derivedData, *result = NULL;
	GHash *vertHash = NULL, *edgeHash, *polyHash;
	GHashIterator *hashIter;
	MDeformVert *dvert = NULL, *dv;
	int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0;
	int maxVerts, maxEdges, maxPolys;
	int i;

	MPoly *mpoly;
	MLoop *mloop;

	MPoly *mpoly_new;
	MLoop *mloop_new;
	MEdge *medge_new;
	MVert *mvert_new;


	int *loop_mapping;

	/* Overview of Method:
	 *	1. Get the vertices that are in the vertexgroup of interest 
	 *	2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
	 *	3. Make a new mesh containing only the mapping data
	 */
	
	/* get original number of verts, edges, and faces */
	maxVerts = dm->getNumVerts(dm);
	maxEdges = dm->getNumEdges(dm);
	maxPolys = dm->getNumPolys(dm);
	
	/* check if we can just return the original mesh 
	 *	- must have verts and therefore verts assigned to vgroups to do anything useful
	 */
	if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
	    (maxVerts == 0) || (ob->defbase.first == NULL) )
	{
		return derivedData;
	}
	
	/* if mode is to use selected armature bones, aggregate the bone groups */
	if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */
		GHash *vgroupHash;
		Object *oba = mmd->ob_arm;
		bPoseChannel *pchan;
		bDeformGroup *def;
		char *bone_select_array;
		int bone_select_tot = 0;
		const int defbase_tot = BLI_countlist(&ob->defbase);
		
		/* check that there is armature object with bones to use, otherwise return original mesh */
		if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first))
			return derivedData;
		
		bone_select_array = MEM_mallocN(defbase_tot * sizeof(char), "mask array");
		
		for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
			pchan = BKE_pose_channel_find_name(oba->pose, def->name);
			if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
				bone_select_array[i] = TRUE;
				bone_select_tot++;
			}
			else {
				bone_select_array[i] = FALSE;
			}
		}

		/* hashes for finding mapping of:
		 * - vgroups to indices -> vgroupHash  (string, int)
		 * - bones to vgroup indices -> boneHash (index of vgroup, dummy)
		 */
		vgroupHash = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh");
		
		/* build mapping of names of vertex groups to indices */
		for (i = 0, def = ob->defbase.first; def; def = def->next, i++) 
			BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i));
		
		/* if no bones selected, free hashes and return original mesh */
		if (bone_select_tot == 0) {
			BLI_ghash_free(vgroupHash, NULL, NULL);
			MEM_freeN(bone_select_array);
			
			return derivedData;
		}
		
		/* repeat the previous check, but for dverts */
		dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
		if (dvert == NULL) {
			BLI_ghash_free(vgroupHash, NULL, NULL);
			MEM_freeN(bone_select_array);
			
			return derivedData;
		}
		
		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh");
		
		/* add vertices which exist in vertexgroups into vertHash for filtering */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			MDeformWeight *dw = dv->dw;
			int j;
			
			for (j = dv->totweight; j > 0; j--, dw++) {
				if (dw->def_nr < defbase_tot) {
					if (bone_select_array[dw->def_nr]) {
						if (dw->weight != 0.0f) {
							break;
						}
					}
				}
			}
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (dw) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!dw) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
		
		/* free temp hashes */
		BLI_ghash_free(vgroupHash, NULL, NULL);
		MEM_freeN(bone_select_array);
	}
	else {  /* --- Using Nominated VertexGroup only --- */
		int defgrp_index = defgroup_name_index(ob, mmd->vgroup);
		
		/* get dverts */
		if (defgrp_index >= 0)
			dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
			
		/* if no vgroup (i.e. dverts) found, return the initial mesh */
		if ((defgrp_index < 0) || (dvert == NULL))
			return dm;
			
		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert2 bh");
		
		/* add vertices which exist in vertexgroup into ghash for filtering */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			const int weight_set = defvert_find_weight(dv, defgrp_index) != 0.0f;
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (weight_set) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!weight_set) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
	}

	/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
	edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh");
	polyHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh");
	
	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);

	loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */

	/* loop over edges and faces, and do the same thing to 
	 * ensure that they only reference existing verts 
	 */
	for (i = 0; i < maxEdges; i++)  {
		MEdge me;
		dm->getEdge(dm, i, &me);
		
		/* only add if both verts will be in new mesh */
		if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) &&
		    BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)))
		{
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges));
			numEdges++;
		}
	}
	for (i = 0; i < maxPolys; i++) {
		MPoly *mp = &mpoly[i];
		MLoop *ml = mloop + mp->loopstart;
		int ok = TRUE;
		int j;
		
		for (j = 0; j < mp->totloop; j++, ml++) {
			if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) {
				ok = FALSE;
				break;
			}
		}
		
		/* all verts must be available */
		if (ok) {
			BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys));
			loop_mapping[numPolys] = numLoops;
			numPolys++;
			numLoops += mp->totloop;
		}
	}
	
	
	/* now we know the number of verts, edges and faces, 
	 * we can create the new (reduced) mesh
	 */
	result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys);
	
	mpoly_new = CDDM_get_polys(result);
	mloop_new = CDDM_get_loops(result);
	medge_new = CDDM_get_edges(result);
	mvert_new = CDDM_get_verts(result);
	
	/* using ghash-iterators, map data into new mesh */
	/* vertices */
	for (hashIter = BLI_ghashIterator_new(vertHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter) )
	{
		MVert source;
		MVert *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getVert(dm, oldIndex, &source);
		dest = &mvert_new[newIndex];
		
		DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
		
	/* edges */
	for (hashIter = BLI_ghashIterator_new(edgeHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter))
	{
		MEdge source;
		MEdge *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getEdge(dm, oldIndex, &source);
		dest = &medge_new[newIndex];
		
		source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
		source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
		
		DM_copy_edge_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
	
	/* faces */
	for (hashIter = BLI_ghashIterator_new(polyHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter) )
	{
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		MPoly *source = &mpoly[oldIndex];
		MPoly *dest = &mpoly_new[newIndex];
		int oldLoopIndex = source->loopstart;
		int newLoopIndex = loop_mapping[newIndex];
		MLoop *source_loop = &mloop[oldLoopIndex];
		MLoop *dest_loop = &mloop_new[newLoopIndex];
		
		DM_copy_poly_data(dm, result, oldIndex, newIndex, 1);
		DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop);

		*dest = *source;
		dest->loopstart = newLoopIndex;
		for (i = 0; i < source->totloop; i++) {
			dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v)));
			dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e)));
		}
	}

	BLI_ghashIterator_free(hashIter);

	MEM_freeN(loop_mapping);

	/* why is this needed? - campbell */
	/* recalculate normals */
	CDDM_calc_normals(result);
	
	/* free hashes */
	BLI_ghash_free(vertHash, NULL, NULL);
	BLI_ghash_free(edgeHash, NULL, NULL);
	BLI_ghash_free(polyHash, NULL, NULL);

	/* return the new mesh */
	return result;
}
Example #5
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DerivedMesh *dm = derivedData, *result;
	ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
	ParticleSimulationData sim;
	ParticleSystem *psys = NULL;
	ParticleData *pa = NULL;
	MPoly *mpoly, *orig_mpoly;
	MLoop *mloop, *orig_mloop;
	MVert *mvert, *orig_mvert;
	int totvert, totpoly, totloop /* , totedge */;
	int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0;
	int k, p, p_skip;
	short track = ob->trackflag % 3, trackneg, axis = pimd->axis;
	float max_co = 0.0, min_co = 0.0, temp_co[3], cross[3];
	float *size = NULL;

	trackneg = ((ob->trackflag > 2) ? 1 : 0);

	if (pimd->ob == ob) {
		pimd->ob = NULL;
		return derivedData;
	}

	if (pimd->ob) {
		psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1);
		if (psys == NULL || psys->totpart == 0)
			return derivedData;
	}
	else {
		return derivedData;
	}

	if (pimd->flag & eParticleInstanceFlag_Parents)
		totpart += psys->totpart;
	if (pimd->flag & eParticleInstanceFlag_Children) {
		if (totpart == 0)
			first_particle = psys->totpart;
		totpart += psys->totchild;
	}

	if (totpart == 0)
		return derivedData;

	sim.scene = md->scene;
	sim.ob = pimd->ob;
	sim.psys = psys;
	sim.psmd = psys_get_modifier(pimd->ob, psys);

	if (pimd->flag & eParticleInstanceFlag_UseSize) {
		float *si;
		si = size = MEM_callocN(totpart * sizeof(float), "particle size array");

		if (pimd->flag & eParticleInstanceFlag_Parents) {
			for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++)
				*si = pa->size;
		}

		if (pimd->flag & eParticleInstanceFlag_Children) {
			ChildParticle *cpa = psys->child;

			for (p = 0; p < psys->totchild; p++, cpa++, si++) {
				*si = psys_get_child_size(psys, cpa, 0.0f, NULL);
			}
		}
	}

	totvert = dm->getNumVerts(dm);
	totpoly = dm->getNumPolys(dm);
	totloop = dm->getNumLoops(dm);
	/* totedge = dm->getNumEdges(dm); */ /* UNUSED */

	/* count particles */
	maxvert = 0;
	maxpoly = 0;
	maxloop = 0;

	for (p = 0; p < totpart; p++) {
		if (particle_skip(pimd, psys, p))
			continue;

		maxvert += totvert;
		maxpoly += totpoly;
		maxloop += totloop;
	}

	psys->lattice = psys_get_lattice(&sim);

	if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) {
		float min_r[3], max_r[3];
		INIT_MINMAX(min_r, max_r);
		dm->getMinMax(dm, min_r, max_r);
		min_co = min_r[track];
		max_co = max_r[track];
	}

	result = CDDM_from_template(dm, maxvert, 0, 0, maxloop, maxpoly);

	mvert = result->getVertArray(result);
	orig_mvert = dm->getVertArray(dm);

	mpoly = result->getPolyArray(result);
	orig_mpoly = dm->getPolyArray(dm);
	mloop = result->getLoopArray(result);
	orig_mloop = dm->getLoopArray(dm);

	for (p = 0, p_skip = 0; p < totpart; p++) {
		/* skip particle? */
		if (particle_skip(pimd, psys, p))
			continue;

		/* set vertices coordinates */
		for (k = 0; k < totvert; k++) {
			ParticleKey state;
			MVert *inMV;
			MVert *mv = mvert + p_skip * totvert + k;

			inMV = orig_mvert + k;
			DM_copy_vert_data(dm, result, k, p_skip * totvert + k, 1);
			*mv = *inMV;

			/*change orientation based on object trackflag*/
			copy_v3_v3(temp_co, mv->co);
			mv->co[axis] = temp_co[track];
			mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3];
			mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3];

			/* get particle state */
			if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) &&
				(pimd->flag & eParticleInstanceFlag_Path))
			{
				float ran = 0.0f;
				if (pimd->random_position != 0.0f) {
					ran = pimd->random_position * BLI_hash_frand(psys->seed + p);
				}

				if (pimd->flag & eParticleInstanceFlag_KeepShape) {
					state.time = pimd->position * (1.0f - ran);
				}
				else {
					state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran);

					if (trackneg)
						state.time = 1.0f - state.time;

					mv->co[axis] = 0.0;
				}

				psys_get_particle_on_path(&sim, first_particle + p, &state, 1);

				normalize_v3(state.vel);

				/* TODO: incremental rotations somehow */
				if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
					unit_qt(state.rot);
				}
				else {
					float temp[3] = {0.0f, 0.0f, 0.0f};
					temp[axis] = 1.0f;

					cross_v3_v3v3(cross, temp, state.vel);

					/* state.vel[axis] is the only component surviving from a dot product with the axis */
					axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis]));
				}
			}
			else {
				state.time = -1.0;
				psys_get_particle_state(&sim, first_particle + p, &state, 1);
			}

			mul_qt_v3(state.rot, mv->co);
			if (pimd->flag & eParticleInstanceFlag_UseSize)
				mul_v3_fl(mv->co, size[p]);
			add_v3_v3(mv->co, state.co);
		}

		/* create polys and loops */
		for (k = 0; k < totpoly; k++) {
			MPoly *inMP = orig_mpoly + k;
			MPoly *mp = mpoly + p_skip * totpoly + k;

			DM_copy_poly_data(dm, result, k, p_skip * totpoly + k, 1);
			*mp = *inMP;
			mp->loopstart += p_skip * totloop;

			{
				MLoop *inML = orig_mloop + inMP->loopstart;
				MLoop *ml = mloop + mp->loopstart;
				int j = mp->totloop;

				DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j);
				for (; j; j--, ml++, inML++) {
					ml->v = inML->v + (p_skip * totvert);
				}
			}
		}

		p_skip++;
	}

	CDDM_calc_edges(result);

	if (psys->lattice) {
		end_latt_deform(psys->lattice);
		psys->lattice = NULL;
	}

	if (size)
		MEM_freeN(size);

	result->dirty |= DM_DIRTY_NORMALS;

	return result;
}
static DerivedMesh *doOcean(ModifierData *md, Object *ob,
                            DerivedMesh *derivedData,
                            int UNUSED(useRenderParams))
{
	OceanModifierData *omd = (OceanModifierData *) md;

	DerivedMesh *dm = NULL;
	OceanResult ocr;

	MVert *mverts;

	int cfra;
	int i, j;

	/* 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 (!isfinite(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 */

	mverts = dm->getVertArray(dm);

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

	if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
		if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) {
			const int num_polys = dm->getNumPolys(dm);
			const int num_loops = dm->getNumLoops(dm);
			MLoop *mloops = dm->getLoopArray(dm);
			MLoopCol *mloopcols = CustomData_add_layer_named(
			                          &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);

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

				for (i = 0, mp = mpolys; i < num_polys; i++, mp++) {
					MLoop *ml = &mloops[mp->loopstart];
					MLoopCol *mlcol = &mloopcols[mp->loopstart];

					for (j = mp->totloop; j--; ml++, mlcol++) {
						const float *vco = mverts[ml->v].co;
						const float u = OCEAN_CO(size_co_inv, vco[0]);
						const float v = OCEAN_CO(size_co_inv, vco[1]);
						float foam;

						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->r = mlcol->g = mlcol->b = (char)(foam * 255);
						/* This needs to be set (render engine uses) */
						mlcol->a = 255;
					}
				}
			}
		}
	}


	/* displace the geometry */

	/* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */
	{
		const int num_verts = dm->getNumVerts(dm);

		for (i = 0; i < num_verts; i++) {
			float *vco = mverts[i].co;
			const float u = OCEAN_CO(size_co_inv, vco[0]);
			const float v = OCEAN_CO(size_co_inv, vco[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);
			}

			vco[2] += ocr.disp[1];

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

#undef OCEAN_CO

	return dm;
}