예제 #1
0
static void particle_system_minmax(Scene *scene,
                                   Object *object,
                                   ParticleSystem *psys,
                                   float radius,
                                   float min[3], float max[3])
{
	const float size[3] = {radius, radius, radius};
	const float cfra = BKE_scene_frame_get(scene);
	ParticleSettings *part = psys->part;
	ParticleSimulationData sim = {NULL};
	ParticleData *pa = NULL;
	int i;
	int total_particles;
	float mat[4][4], imat[4][4];

	INIT_MINMAX(min, max);
	if (part->type == PART_HAIR) {
		/* TOOD(sergey): Not supported currently. */
		return;
	}

	unit_m4(mat);
	psys_render_set(object, psys, mat, mat, 1, 1, 0);

	sim.scene = scene;
	sim.ob = object;
	sim.psys = psys;
	sim.psmd = psys_get_modifier(object, psys);

	invert_m4_m4(imat, object->obmat);
	total_particles = psys->totpart + psys->totchild;
	psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);

	for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
		float co_object[3], co_min[3], co_max[3];
		ParticleKey state;
		state.time = cfra;
		if (!psys_get_particle_state(&sim, i, &state, 0)) {
			continue;
		}
		mul_v3_m4v3(co_object, imat, state.co);
		sub_v3_v3v3(co_min, co_object, size);
		add_v3_v3v3(co_max, co_object, size);
		minmax_v3v3_v3(min, max, co_min);
		minmax_v3v3_v3(min, max, co_max);
	}

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

	psys_render_restore(object, psys);
}
예제 #2
0
파일: editface.c 프로젝트: mgschwan/blensor
bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
{
	const Mesh *me;
	const MPoly *mp;
	const MLoop *ml;
	const MVert *mvert;
	int a, b;
	bool ok = false;
	float vec[3], bmat[3][3];

	me = BKE_mesh_from_object(ob);
	if (!me || !me->mloopuv) {
		return ok;
	}
	
	copy_m3_m4(bmat, ob->obmat);

	mvert = me->mvert;
	mp = me->mpoly;
	for (a = me->totpoly; a > 0; a--, mp++) {
		if (mp->flag & ME_HIDE || !(mp->flag & ME_FACE_SEL))
			continue;

		ml = me->mloop + mp->totloop;
		for (b = 0; b < mp->totloop; b++, ml++) {
			mul_v3_m3v3(vec, bmat, mvert[ml->v].co);
			add_v3_v3v3(vec, vec, ob->obmat[3]);
			minmax_v3v3_v3(r_min, r_max, vec);
		}

		ok = true;
	}

	return ok;
}
예제 #3
0
파일: mball.c 프로젝트: mcgrathd/blender
bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3],
                         float obmat[4][4], const short flag)
{
    const float scale = obmat ? mat4_to_scale(obmat) : 1.0f;
    MetaElem *ml;
    bool changed = false;
    float centroid[3], vec[3];

    INIT_MINMAX(min, max);

    for (ml = mb->elems.first; ml; ml = ml->next) {
        if ((ml->flag & flag) == flag) {
            const float scale_mb = (ml->rad * 0.5f) * scale;
            int i;

            if (obmat) {
                mul_v3_m4v3(centroid, obmat, &ml->x);
            }
            else {
                copy_v3_v3(centroid, &ml->x);
            }

            /* TODO, non circle shapes cubes etc, probably nobody notices - campbell */
            for (i = -1; i != 3; i += 2) {
                copy_v3_v3(vec, centroid);
                add_v3_fl(vec, scale_mb * i);
                minmax_v3v3_v3(min, max, vec);
            }
            changed = true;
        }
    }

    return changed;
}
예제 #4
0
/* find the bounding box of an objectinstance in global space */
void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float bbmin[3], float bbmax[3])
{
	ObjectRen *obr = obi->obr;
	VolumePrecache *vp = obi->volume_precache;
	VertRen *ver= NULL;
	float co[3];
	int a;
	
	if (vp->bbmin != NULL && vp->bbmax != NULL) {
		copy_v3_v3(bbmin, vp->bbmin);
		copy_v3_v3(bbmax, vp->bbmax);
		return;
	}
	
	vp->bbmin = MEM_callocN(sizeof(float)*3, "volume precache min boundbox corner");
	vp->bbmax = MEM_callocN(sizeof(float)*3, "volume precache max boundbox corner");
	
	INIT_MINMAX(bbmin, bbmax);
	
	for (a=0; a<obr->totvert; a++) {
		if ((a & 255)==0) ver= obr->vertnodes[a>>8].vert;
		else ver++;
		
		copy_v3_v3(co, ver->co);
		
		/* transformed object instance in camera space */
		if (obi->flag & R_TRANSFORMED)
			mul_m4_v3(obi->mat, co);
		
		/* convert to global space */
		mul_m4_v3(re->viewinv, co);
		
		minmax_v3v3_v3(vp->bbmin, vp->bbmax, co);
	}
예제 #5
0
void strand_minmax(StrandRen *strand, float min[3], float max[3], const float width)
{
	StrandVert *svert;
	const float width2 = width * 2.0f;
	float vec[3];
	int a;

	for (a=0, svert=strand->vert; a<strand->totvert; a++, svert++) {
		copy_v3_v3(vec, svert->co);
		minmax_v3v3_v3(min, max, vec);
		
		if (width!=0.0f) {
			add_v3_fl(vec, width);
			minmax_v3v3_v3(min, max, vec);
			add_v3_fl(vec, -width2);
			minmax_v3v3_v3(min, max, vec);
		}
	}
}
예제 #6
0
void BKE_lattice_minmax(Lattice *lt, float min[3], float max[3])
{
	int i, numVerts;

	if (lt->editlatt) lt = lt->editlatt->latt;
	numVerts = lt->pntsu * lt->pntsv * lt->pntsw;

	for (i = 0; i < numVerts; i++)
		minmax_v3v3_v3(min, max, lt->def[i].vec);
}
예제 #7
0
파일: mball.c 프로젝트: mcgrathd/blender
/* basic vertex data functions */
bool BKE_mball_minmax(MetaBall *mb, float min[3], float max[3])
{
    MetaElem *ml;

    INIT_MINMAX(min, max);

    for (ml = mb->elems.first; ml; ml = ml->next) {
        minmax_v3v3_v3(min, max, &ml->x);
    }

    return (BLI_listbase_is_empty(&mb->elems) == false);
}
예제 #8
0
static void bundle_midpoint(Scene *scene, Object *ob, float vec[3])
{
	MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
	MovieTracking *tracking;
	MovieTrackingObject *object;
	bool ok = false;
	float min[3], max[3], mat[4][4], pos[3], cammat[4][4];

	if (!clip)
		return;

	tracking = &clip->tracking;

	copy_m4_m4(cammat, ob->obmat);

	BKE_tracking_get_camera_object_matrix(scene, ob, mat);

	INIT_MINMAX(min, max);

	for (object = tracking->objects.first; object; object = object->next) {
		ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
		MovieTrackingTrack *track = tracksbase->first;
		float obmat[4][4];

		if (object->flag & TRACKING_OBJECT_CAMERA) {
			copy_m4_m4(obmat, mat);
		}
		else {
			float imat[4][4];

			BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, scene->r.cfra, imat);
			invert_m4(imat);

			mul_m4_m4m4(obmat, cammat, imat);
		}

		while (track) {
			if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
				ok = 1;
				mul_v3_m4v3(pos, obmat, track->bundle_pos);
				minmax_v3v3_v3(min, max, pos);
			}

			track = track->next;
		}
	}

	if (ok) {
		mid_v3_v3v3(vec, min, max);
	}
}
/* Raytracing for vertex to bone/vertex visibility */
static void heat_ray_tree_create(LaplacianSystem *sys)
{
	const MLoopTri *looptri = sys->heat.mlooptri;
	const MLoop *mloop = sys->heat.mloop;
	float (*verts)[3] = sys->heat.verts;
	int tottri = sys->heat.tottri;
	int totvert = sys->heat.totvert;
	int a;

	sys->heat.bvhtree = BLI_bvhtree_new(tottri, 0.0f, 4, 6);
	sys->heat.vltree = MEM_callocN(sizeof(MLoopTri *) * totvert, "HeatVFaces");

	for (a = 0; a < tottri; a++) {
		const MLoopTri *lt = &looptri[a];
		float bb[6];
		int vtri[3];
		
		vtri[0] = mloop[lt->tri[0]].v;
		vtri[1] = mloop[lt->tri[1]].v;
		vtri[2] = mloop[lt->tri[2]].v;

		INIT_MINMAX(bb, bb + 3);
		minmax_v3v3_v3(bb, bb + 3, verts[vtri[0]]);
		minmax_v3v3_v3(bb, bb + 3, verts[vtri[1]]);
		minmax_v3v3_v3(bb, bb + 3, verts[vtri[2]]);

		BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
		
		//Setup inverse pointers to use on isect.orig
		sys->heat.vltree[vtri[0]] = lt;
		sys->heat.vltree[vtri[1]] = lt;
		sys->heat.vltree[vtri[2]] = lt;
	}

	BLI_bvhtree_balance(sys->heat.bvhtree); 
}
예제 #10
0
/* ******************************************************** */
bool ED_gpencil_stroke_minmax(
        const bGPDstroke *gps, const bool use_select,
        float r_min[3], float r_max[3])
{
	const bGPDspoint *pt;
	int i;
	bool changed = false;

	for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
		if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {;
			minmax_v3v3_v3(r_min, r_max, &pt->x);
			changed = true;
		}
	}
	return changed;
}
예제 #11
0
void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3])
{
	DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL;

	if (!dl) {
		BKE_lattice_minmax(lt, min, max);
	}
	else {
		int i, numVerts;
		
		if (lt->editlatt) lt = lt->editlatt->latt;
		numVerts = lt->pntsu * lt->pntsv * lt->pntsw;

		for (i = 0; i < numVerts; i++)
			minmax_v3v3_v3(min, max, &dl->verts[i * 3]);
	}
}
예제 #12
0
파일: mball.c 프로젝트: mcgrathd/blender
/** Compute bounding box of all MetaElems/MetaBalls.
 *
 * Bounding box is computed from polygonized surface. Object *ob is
 * basic MetaBall (usually with name Meta). All other MetaBalls (with
 * names Meta.001, Meta.002, etc) are included in this Bounding Box.
 */
void BKE_mball_texspace_calc(Object *ob)
{
    DispList *dl;
    BoundBox *bb;
    float *data, min[3], max[3] /*, loc[3], size[3] */;
    int tot;
    bool do_it = false;

    if (ob->bb == NULL) ob->bb = MEM_callocN(sizeof(BoundBox), "mb boundbox");
    bb = ob->bb;

    /* Weird one, this. */
    /*      INIT_MINMAX(min, max); */
    (min)[0] = (min)[1] = (min)[2] = 1.0e30f;
    (max)[0] = (max)[1] = (max)[2] = -1.0e30f;

    dl = ob->curve_cache->disp.first;
    while (dl) {
        tot = dl->nr;
        if (tot) do_it = true;
        data = dl->verts;
        while (tot--) {
            /* Also weird... but longer. From utildefines. */
            minmax_v3v3_v3(min, max, data);
            data += 3;
        }
        dl = dl->next;
    }

    if (!do_it) {
        min[0] = min[1] = min[2] = -1.0f;
        max[0] = max[1] = max[2] = 1.0f;
    }
#if 0
    loc[0] = (min[0] + max[0]) / 2.0f;
    loc[1] = (min[1] + max[1]) / 2.0f;
    loc[2] = (min[2] + max[2]) / 2.0f;

    size[0] = (max[0] - min[0]) / 2.0f;
    size[1] = (max[1] - min[1]) / 2.0f;
    size[2] = (max[2] - min[2]) / 2.0f;
#endif
    BKE_boundbox_init_from_minmax(bb, min, max);
}
예제 #13
0
ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
	float (*co)[3], float (*color)[3], float *area, int totpoint)
{
	ScatterTree *tree;
	ScatterPoint *points, **refpoints;
	int i;

	/* allocate tree */
	tree= MEM_callocN(sizeof(ScatterTree), "ScatterTree");
	tree->scale= scale;
	tree->error= error;
	tree->totpoint= totpoint;

	tree->ss[0]= ss[0];
	tree->ss[1]= ss[1];
	tree->ss[2]= ss[2];

	points = MEM_callocN(sizeof(ScatterPoint) * totpoint, "ScatterPoints");
	refpoints = MEM_callocN(sizeof(ScatterPoint *) * totpoint, "ScatterRefPoints");

	tree->points= points;
	tree->refpoints= refpoints;

	/* build points */
	INIT_MINMAX(tree->min, tree->max);

	for (i=0; i<totpoint; i++) {
		copy_v3_v3(points[i].co, co[i]);
		copy_v3_v3(points[i].rad, color[i]);
		points[i].area= fabsf(area[i])/(tree->scale*tree->scale);
		points[i].back= (area[i] < 0.0f);

		mul_v3_fl(points[i].co, 1.0f / tree->scale);
		minmax_v3v3_v3(tree->min, tree->max, points[i].co);

		refpoints[i]= points + i;
	}

	return tree;
}
예제 #14
0
파일: occlusion.c 프로젝트: diekev/blender
static int occ_find_bbox_axis(OcclusionTree *tree, int begin, int end, float *min, float *max)
{
	float len, maxlen = -1.0f;
	int a, axis = 0;

	INIT_MINMAX(min, max);

	for (a = begin; a < end; a++) {
		minmax_v3v3_v3(min, max, tree->co[a]);
	}

	for (a = 0; a < 3; a++) {
		len = max[a] - min[a];

		if (len > maxlen) {
			maxlen = len;
			axis = a;
		}
	}

	return axis;
}
예제 #15
0
void curve_deform_verts(Scene *scene, Object *cuOb, Object *target,
                        DerivedMesh *dm, float (*vertexCos)[3],
                        int numVerts, const char *vgroup, short defaxis)
{
	Curve *cu;
	int a, flag;
	CurveDeform cd;
	int use_vgroups;
	const int is_neg_axis = (defaxis > 2);

	if (cuOb->type != OB_CURVE)
		return;

	cu = cuOb->data;
	flag = cu->flag;
	cu->flag |= (CU_PATH | CU_FOLLOW); // needed for path & bevlist

	init_curve_deform(cuOb, target, &cd);

	/* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
	if (is_neg_axis == FALSE) {
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
	}
	else {
		/* negative, these bounds give a good rest position */
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] =  0.0f;
	}
	
	/* check whether to use vertex groups (only possible if target is a Mesh)
	 * we want either a Mesh with no derived data, or derived data with
	 * deformverts
	 */
	if (target && target->type == OB_MESH) {
		/* if there's derived data without deformverts, don't use vgroups */
		if (dm) {
			use_vgroups = (dm->getVertData(dm, 0, CD_MDEFORMVERT) != NULL);
		}
		else {
			Mesh *me = target->data;
			use_vgroups = (me->dvert != NULL);
		}
	}
	else {
		use_vgroups = FALSE;
	}
	
	if (vgroup && vgroup[0] && use_vgroups) {
		Mesh *me = target->data;
		int index = defgroup_name_index(target, vgroup);

		if (index != -1 && (me->dvert || dm)) {
			MDeformVert *dvert = me->dvert;
			float vec[3];
			float weight;
	

			if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
				dvert = me->dvert;
				for (a = 0; a < numVerts; a++, dvert++) {
					if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
					weight = defvert_find_weight(dvert, index);
	
					if (weight > 0.0f) {
						mul_m4_v3(cd.curvespace, vertexCos[a]);
						copy_v3_v3(vec, vertexCos[a]);
						calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
						interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
						mul_m4_v3(cd.objectspace, vertexCos[a]);
					}
				}
			}
			else {
				/* set mesh min/max bounds */
				INIT_MINMAX(cd.dmin, cd.dmax);
	
				for (a = 0; a < numVerts; a++, dvert++) {
					if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
					
					if (defvert_find_weight(dvert, index) > 0.0f) {
						mul_m4_v3(cd.curvespace, vertexCos[a]);
						minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
					}
				}
	
				dvert = me->dvert;
				for (a = 0; a < numVerts; a++, dvert++) {
					if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
					
					weight = defvert_find_weight(dvert, index);
	
					if (weight > 0.0f) {
						/* already in 'cd.curvespace', prev for loop */
						copy_v3_v3(vec, vertexCos[a]);
						calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
						interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
						mul_m4_v3(cd.objectspace, vertexCos[a]);
					}
				}
			}
		}
	}
	else {
		if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
		else {
			/* set mesh min max bounds */
			INIT_MINMAX(cd.dmin, cd.dmax);
				
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
			}
	
			for (a = 0; a < numVerts; a++) {
				/* already in 'cd.curvespace', prev for loop */
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
	}
	cu->flag = flag;
}
예제 #16
0
static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
{
	const ScopesUpdateData *data = userdata;

	Scopes *scopes = data->scopes;
	const ImBuf *ibuf = data->ibuf;
	struct ColormanageProcessor *cm_processor = data->cm_processor;
	const unsigned char *display_buffer = data->display_buffer;
	const int ycc_mode = data->ycc_mode;

	ScopesUpdateDataChunk *data_chunk = userdata_chunk;
	unsigned int *bin_lum = data_chunk->bin_lum;
	unsigned int *bin_r = data_chunk->bin_r;
	unsigned int *bin_g = data_chunk->bin_g;
	unsigned int *bin_b = data_chunk->bin_b;
	unsigned int *bin_a = data_chunk->bin_a;
	float *min = data_chunk->min;
	float *max = data_chunk->max;

	const float *rf = NULL;
	const unsigned char *rc = NULL;
	const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
	const int savedlines = y / rows_per_sample_line;
	const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
	const bool is_float = (ibuf->rect_float != NULL);

	if (is_float)
		rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
	else {
		rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
	}

	for (int x = 0; x < ibuf->x; x++) {
		float rgba[4], ycc[3], luma;

		if (is_float) {
			switch (ibuf->channels) {
				case 4:
					copy_v4_v4(rgba, rf);
					IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
					break;
				case 3:
					copy_v3_v3(rgba, rf);
					IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
					rgba[3] = 1.0f;
					break;
				case 2:
					copy_v3_fl(rgba, rf[0]);
					rgba[3] = rf[1];
					break;
				case 1:
					copy_v3_fl(rgba, rf[0]);
					rgba[3] = 1.0f;
					break;
				default:
					BLI_assert(0);
			}
		}
		else {
			for (int c = 4; c--;)
				rgba[c] = rc[c] * INV_255;
		}

		/* we still need luma for histogram */
		luma = IMB_colormanagement_get_luminance(rgba);

		/* check for min max */
		if (ycc_mode == -1) {
			minmax_v3v3_v3(min, max, rgba);
		}
		else {
			rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
			mul_v3_fl(ycc, INV_255);
			minmax_v3v3_v3(min, max, ycc);
		}
		/* increment count for histo*/
		bin_lum[get_bin_float(luma)]++;
		bin_r[get_bin_float(rgba[0])]++;
		bin_g[get_bin_float(rgba[1])]++;
		bin_b[get_bin_float(rgba[2])]++;
		bin_a[get_bin_float(rgba[3])]++;

		/* save sample if needed */
		if (do_sample_line) {
			const float fx = (float)x / (float)ibuf->x;
			const int idx = 2 * (ibuf->x * savedlines + x);
			save_sample_line(scopes, idx, fx, rgba, ycc);
		}

		rf += ibuf->channels;
		rc += ibuf->channels;
	}
}
예제 #17
0
static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
{
	Object *obedit = CTX_data_edit_object(C);
	Scene *scene = CTX_data_scene(C);
	View3D *v3d = CTX_wm_view3d(C);
	TransVertStore tvs = {NULL};
	TransVert *tv;
	float bmat[3][3], vec[3], min[3], max[3], centroid[3];
	int count, a;

	count = 0;
	INIT_MINMAX(min, max);
	zero_v3(centroid);

	if (obedit) {

		if (ED_transverts_check_obedit(obedit))
			ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES);

		if (tvs.transverts_tot == 0) {
			return false;
		}

		copy_m3_m4(bmat, obedit->obmat);
		
		tv = tvs.transverts;
		for (a = 0; a < tvs.transverts_tot; a++, tv++) {
			copy_v3_v3(vec, tv->loc);
			mul_m3_v3(bmat, vec);
			add_v3_v3(vec, obedit->obmat[3]);
			add_v3_v3(centroid, vec);
			minmax_v3v3_v3(min, max, vec);
		}
		
		if (v3d->around == V3D_AROUND_CENTER_MEAN) {
			mul_v3_fl(centroid, 1.0f / (float)tvs.transverts_tot);
			copy_v3_v3(cursor, centroid);
		}
		else {
			mid_v3_v3v3(cursor, min, max);
		}

		ED_transverts_free(&tvs);
	}
	else {
		Object *obact = CTX_data_active_object(C);
		
		if (obact && (obact->mode & OB_MODE_POSE)) {
			bArmature *arm = obact->data;
			bPoseChannel *pchan;
			for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
				if (arm->layer & pchan->bone->layer) {
					if (pchan->bone->flag & BONE_SELECTED) {
						copy_v3_v3(vec, pchan->pose_head);
						mul_m4_v3(obact->obmat, vec);
						add_v3_v3(centroid, vec);
						minmax_v3v3_v3(min, max, vec);
						count++;
					}
				}
			}
		}
		else {
			CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
			{
				copy_v3_v3(vec, ob->obmat[3]);

				/* special case for camera -- snap to bundles */
				if (ob->type == OB_CAMERA) {
					/* snap to bundles should happen only when bundles are visible */
					if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
						bundle_midpoint(scene, ob, vec);
					}
				}

				add_v3_v3(centroid, vec);
				minmax_v3v3_v3(min, max, vec);
				count++;
			}
			CTX_DATA_END;
		}

		if (count == 0) {
			return false;
		}

		if (v3d->around == V3D_AROUND_CENTER_MEAN) {
			mul_v3_fl(centroid, 1.0f / (float)count);
			copy_v3_v3(cursor, centroid);
		}
		else {
			mid_v3_v3v3(cursor, min, max);
		}
	}
예제 #18
0
파일: lattice.c 프로젝트: dfelinto/blender
void curve_deform_verts(Object *cuOb,
                        Object *target,
                        float (*vertexCos)[3],
                        int numVerts,
                        MDeformVert *dvert,
                        const int defgrp_index,
                        short defaxis)
{
  Curve *cu;
  int a;
  CurveDeform cd;
  const bool is_neg_axis = (defaxis > 2);

  if (cuOb->type != OB_CURVE) {
    return;
  }

  cu = cuOb->data;

  init_curve_deform(cuOb, target, &cd);

  /* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
  if (is_neg_axis == false) {
    cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
    cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
  }
  else {
    /* negative, these bounds give a good rest position */
    cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
    cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
  }

  if (dvert) {
    MDeformVert *dvert_iter;
    float vec[3];

    if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
      for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
        const float weight = defvert_find_weight(dvert_iter, defgrp_index);

        if (weight > 0.0f) {
          mul_m4_v3(cd.curvespace, vertexCos[a]);
          copy_v3_v3(vec, vertexCos[a]);
          calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
          interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
          mul_m4_v3(cd.objectspace, vertexCos[a]);
        }
      }
    }
    else {
      /* set mesh min/max bounds */
      INIT_MINMAX(cd.dmin, cd.dmax);

      for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
        if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) {
          mul_m4_v3(cd.curvespace, vertexCos[a]);
          minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
        }
      }

      for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
        const float weight = defvert_find_weight(dvert_iter, defgrp_index);

        if (weight > 0.0f) {
          /* already in 'cd.curvespace', prev for loop */
          copy_v3_v3(vec, vertexCos[a]);
          calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
          interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
          mul_m4_v3(cd.objectspace, vertexCos[a]);
        }
      }
    }
  }
  else {
    if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
      for (a = 0; a < numVerts; a++) {
        mul_m4_v3(cd.curvespace, vertexCos[a]);
        calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
        mul_m4_v3(cd.objectspace, vertexCos[a]);
      }
    }
    else {
      /* set mesh min max bounds */
      INIT_MINMAX(cd.dmin, cd.dmax);

      for (a = 0; a < numVerts; a++) {
        mul_m4_v3(cd.curvespace, vertexCos[a]);
        minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
      }

      for (a = 0; a < numVerts; a++) {
        /* already in 'cd.curvespace', prev for loop */
        calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
        mul_m4_v3(cd.objectspace, vertexCos[a]);
      }
    }
  }
}
예제 #19
0
static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
{
	ParticleData *pa=NULL;
	float min[3], max[3], delta[3], d;
	MVert *mv, *mvert = dm->getVertDataArray(dm,0);
	int totvert=dm->getNumVerts(dm), from=psys->part->from;
	int i, j, k, p, res=psys->part->grid_res, size[3], axis;

	/* find bounding box of dm */
	if (totvert > 0) {
		mv=mvert;
		copy_v3_v3(min, mv->co);
		copy_v3_v3(max, mv->co);
		mv++;
		for (i = 1; i < totvert; i++, mv++) {
			minmax_v3v3_v3(min, max, mv->co);
		}
	}
	else {
		zero_v3(min);
		zero_v3(max);
	}

	sub_v3_v3v3(delta, max, min);

	/* determine major axis */
	axis = axis_dominant_v3_single(delta);

	d = delta[axis]/(float)res;

	size[axis] = res;
	size[(axis+1)%3] = (int)ceil(delta[(axis+1)%3]/d);
	size[(axis+2)%3] = (int)ceil(delta[(axis+2)%3]/d);

	/* float errors grrr.. */
	size[(axis+1)%3] = MIN2(size[(axis+1)%3],res);
	size[(axis+2)%3] = MIN2(size[(axis+2)%3],res);

	size[0] = MAX2(size[0], 1);
	size[1] = MAX2(size[1], 1);
	size[2] = MAX2(size[2], 1);

	/* no full offset for flat/thin objects */
	min[0]+= d < delta[0] ? d/2.f : delta[0]/2.f;
	min[1]+= d < delta[1] ? d/2.f : delta[1]/2.f;
	min[2]+= d < delta[2] ? d/2.f : delta[2]/2.f;

	for (i=0,p=0,pa=psys->particles; i<res; i++) {
		for (j=0; j<res; j++) {
			for (k=0; k<res; k++,p++,pa++) {
				pa->fuv[0] = min[0] + (float)i*d;
				pa->fuv[1] = min[1] + (float)j*d;
				pa->fuv[2] = min[2] + (float)k*d;
				pa->flag |= PARS_UNEXIST;
				pa->hair_index = 0; /* abused in volume calculation */
			}
		}
	}

	/* enable particles near verts/edges/faces/inside surface */
	if (from==PART_FROM_VERT) {
		float vec[3];

		pa=psys->particles;

		min[0] -= d/2.0f;
		min[1] -= d/2.0f;
		min[2] -= d/2.0f;

		for (i=0,mv=mvert; i<totvert; i++,mv++) {
			sub_v3_v3v3(vec,mv->co,min);
			vec[0]/=delta[0];
			vec[1]/=delta[1];
			vec[2]/=delta[2];
			pa[((int)(vec[0] * (size[0] - 1))  * res +
			    (int)(vec[1] * (size[1] - 1))) * res +
			    (int)(vec[2] * (size[2] - 1))].flag &= ~PARS_UNEXIST;
		}
	}
	else if (ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
		float co1[3], co2[3];

		MFace *mface= NULL, *mface_array;
		float v1[3], v2[3], v3[3], v4[4], lambda;
		int a, a1, a2, a0mul, a1mul, a2mul, totface;
		int amax= from==PART_FROM_FACE ? 3 : 1;

		totface=dm->getNumTessFaces(dm);
		mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);

		for (a=0; a<amax; a++) {
			if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
			else if (a==1) { a0mul=res; a1mul=1; a2mul=res*res; }
			else { a0mul=1; a1mul=res*res; a2mul=res; }

			for (a1=0; a1<size[(a+1)%3]; a1++) {
				for (a2=0; a2<size[(a+2)%3]; a2++) {
					mface= mface_array;

					pa = psys->particles + a1*a1mul + a2*a2mul;
					copy_v3_v3(co1, pa->fuv);
					co1[a] -= d < delta[a] ? d/2.f : delta[a]/2.f;
					copy_v3_v3(co2, co1);
					co2[a] += delta[a] + 0.001f*d;
					co1[a] -= 0.001f*d;

					struct IsectRayPrecalc isect_precalc;
					float ray_direction[3];
					sub_v3_v3v3(ray_direction, co2, co1);
					isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction);

					/* lets intersect the faces */
					for (i=0; i<totface; i++,mface++) {
						copy_v3_v3(v1, mvert[mface->v1].co);
						copy_v3_v3(v2, mvert[mface->v2].co);
						copy_v3_v3(v3, mvert[mface->v3].co);

						bool intersects_tri = isect_ray_tri_watertight_v3(co1,
						                                                  &isect_precalc,
						                                                  v1, v2, v3,
						                                                  &lambda, NULL);
						if (intersects_tri) {
							if (from==PART_FROM_FACE)
								(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
							else /* store number of intersections */
								(pa+(int)(lambda*size[a])*a0mul)->hair_index++;
						}

						if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) {
							copy_v3_v3(v4, mvert[mface->v4].co);

							if (isect_ray_tri_watertight_v3(
							            co1,
							            &isect_precalc,
							            v1, v3, v4,
							            &lambda, NULL))
							{
								if (from==PART_FROM_FACE)
									(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
								else
									(pa+(int)(lambda*size[a])*a0mul)->hair_index++;
							}
						}
					}

					if (from==PART_FROM_VOLUME) {
						int in=pa->hair_index%2;
						if (in) pa->hair_index++;
						for (i=0; i<size[0]; i++) {
							if (in || (pa+i*a0mul)->hair_index%2)
								(pa+i*a0mul)->flag &= ~PARS_UNEXIST;
							/* odd intersections == in->out / out->in */
							/* even intersections -> in stays same */
							in=(in + (pa+i*a0mul)->hair_index) % 2;
						}
					}
				}
			}
		}
	}

	if (psys->part->flag & PART_GRID_HEXAGONAL) {
		for (i=0,p=0,pa=psys->particles; i<res; i++) {
			for (j=0; j<res; j++) {
				for (k=0; k<res; k++,p++,pa++) {
					if (j%2)
						pa->fuv[0] += d/2.f;

					if (k%2) {
						pa->fuv[0] += d/2.f;
						pa->fuv[1] += d/2.f;
					}
				}
			}
		}
	}

	if (psys->part->flag & PART_GRID_INVERT) {
		for (i=0; i<size[0]; i++) {
			for (j=0; j<size[1]; j++) {
				pa=psys->particles + res*(i*res + j);
				for (k=0; k<size[2]; k++, pa++) {
					pa->flag ^= PARS_UNEXIST;
				}
			}
		}
	}

	if (psys->part->grid_rand > 0.f) {
		float rfac = d * psys->part->grid_rand;
		for (p=0,pa=psys->particles; p<psys->totpart; p++,pa++) {
			if (pa->flag & PARS_UNEXIST)
				continue;

			pa->fuv[0] += rfac * (psys_frand(psys, p + 31) - 0.5f);
			pa->fuv[1] += rfac * (psys_frand(psys, p + 32) - 0.5f);
			pa->fuv[2] += rfac * (psys_frand(psys, p + 33) - 0.5f);
		}
	}
}
예제 #20
0
파일: MOD_cast.c 프로젝트: mgschwan/blensor
static void cuboid_do(
        CastModifierData *cmd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	MDeformVert *dvert = NULL;
	Object *ctrl_ob = NULL;

	int i, defgrp_index;
	bool has_radius = false;
	short flag;
	float fac = cmd->fac;
	float facm = 1.0f - fac;
	const float fac_orig = fac;
	float min[3], max[3], bb[8][3];
	float center[3] = {0.0f, 0.0f, 0.0f};
	float mat[4][4], imat[4][4];

	flag = cmd->flag;

	ctrl_ob = cmd->object;

	/* now we check which options the user wants */

	/* 1) (flag was checked in the "if (ctrl_ob)" block above) */
	/* 2) cmd->radius > 0.0f: only the vertices within this radius from
	 * the center of the effect should be deformed */
	if (cmd->radius > FLT_EPSILON) has_radius = 1;

	/* 3) if we were given a vertex group name,
	 * only those vertices should be affected */
	modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index);

	if (ctrl_ob) {
		if (flag & MOD_CAST_USE_OB_TRANSFORM) {
			invert_m4_m4(imat, ctrl_ob->obmat);
			mul_m4_m4m4(mat, imat, ob->obmat);
			invert_m4_m4(imat, mat);
		}

		invert_m4_m4(ob->imat, ob->obmat);
		mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]);
	}

	if ((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) {
		for (i = 0; i < 3; i++) {
			min[i] = -cmd->radius;
			max[i] = cmd->radius;
		}
	}
	else if (!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) {
		for (i = 0; i < 3; i++) {
			min[i] = -cmd->size;
			max[i] = cmd->size;
		}
	}
	else {
		/* get bound box */
		/* We can't use the object's bound box because other modifiers
		 * may have changed the vertex data. */
		INIT_MINMAX(min, max);

		/* Cast's center is the ob's own center in its local space,
		 * by default, but if the user defined a control object, we use
		 * its location, transformed to ob's local space. */
		if (ctrl_ob) {
			float vec[3];

			/* let the center of the ctrl_ob be part of the bound box: */
			minmax_v3v3_v3(min, max, center);

			for (i = 0; i < numVerts; i++) {
				sub_v3_v3v3(vec, vertexCos[i], center);
				minmax_v3v3_v3(min, max, vec);
			}
		}
		else {
			for (i = 0; i < numVerts; i++) {
				minmax_v3v3_v3(min, max, vertexCos[i]);
			}
		}

		/* we want a symmetric bound box around the origin */
		if (fabsf(min[0]) > fabsf(max[0])) max[0] = fabsf(min[0]);
		if (fabsf(min[1]) > fabsf(max[1])) max[1] = fabsf(min[1]);
		if (fabsf(min[2]) > fabsf(max[2])) max[2] = fabsf(min[2]);
		min[0] = -max[0];
		min[1] = -max[1];
		min[2] = -max[2];
	}

	/* building our custom bounding box */
	bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0];
	bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0];
	bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1];
	bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1];
	bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2];
	bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2];

	/* ready to apply the effect, one vertex at a time */
	for (i = 0; i < numVerts; i++) {
		int octant, coord;
		float d[3], dmax, apex[3], fbb;
		float tmp_co[3];

		copy_v3_v3(tmp_co, vertexCos[i]);
		if (ctrl_ob) {
			if (flag & MOD_CAST_USE_OB_TRANSFORM) {
				mul_m4_v3(mat, tmp_co);
			}
			else {
				sub_v3_v3(tmp_co, center);
			}
		}

		if (has_radius) {
			if (fabsf(tmp_co[0]) > cmd->radius ||
			    fabsf(tmp_co[1]) > cmd->radius ||
			    fabsf(tmp_co[2]) > cmd->radius)
			{
				continue;
			}
		}

		if (dvert) {
			const float weight = defvert_find_weight(&dvert[i], defgrp_index);
			if (weight == 0.0f) {
				continue;
			}

			fac = fac_orig * weight;
			facm = 1.0f - fac;
		}

		/* The algo used to project the vertices to their
		 * bounding box (bb) is pretty simple:
		 * for each vertex v:
		 * 1) find in which octant v is in;
		 * 2) find which outer "wall" of that octant is closer to v;
		 * 3) calculate factor (var fbb) to project v to that wall;
		 * 4) project. */

		/* find in which octant this vertex is in */
		octant = 0;
		if (tmp_co[0] > 0.0f) octant += 1;
		if (tmp_co[1] > 0.0f) octant += 2;
		if (tmp_co[2] > 0.0f) octant += 4;

		/* apex is the bb's vertex at the chosen octant */
		copy_v3_v3(apex, bb[octant]);

		/* find which bb plane is closest to this vertex ... */
		d[0] = tmp_co[0] / apex[0];
		d[1] = tmp_co[1] / apex[1];
		d[2] = tmp_co[2] / apex[2];

		/* ... (the closest has the higher (closer to 1) d value) */
		dmax = d[0];
		coord = 0;
		if (d[1] > dmax) {
			dmax = d[1];
			coord = 1;
		}
		if (d[2] > dmax) {
			/* dmax = d[2]; */ /* commented, we don't need it */
			coord = 2;
		}

		/* ok, now we know which coordinate of the vertex to use */

		if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */
			continue;

		/* finally, this is the factor we wanted, to project the vertex
		 * to its bounding box (bb) */
		fbb = apex[coord] / tmp_co[coord];

		/* calculate the new vertex position */
		if (flag & MOD_CAST_X)
			tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
		if (flag & MOD_CAST_Y)
			tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
		if (flag & MOD_CAST_Z)
			tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;

		if (ctrl_ob) {
			if (flag & MOD_CAST_USE_OB_TRANSFORM) {
				mul_m4_v3(imat, tmp_co);
			}
			else {
				add_v3_v3(tmp_co, center);
			}
		}

		copy_v3_v3(vertexCos[i], tmp_co);
	}
}
예제 #21
0
/* 0 == do center, 1 == center new, 2 == center cursor */
void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
{
	Object *obedit = scene->obedit; // XXX get from context
	EditBone *ebone;
	bArmature *arm = ob->data;
	float cent[3];

	/* Put the armature into editmode */
	if (ob != obedit) {
		ED_armature_to_edit(ob);
		obedit = NULL; /* we cant use this so behave as if there is no obedit */
	}

	/* Find the centerpoint */
	if (centermode == 2) {
		copy_v3_v3(cent, cursor);
		invert_m4_m4(ob->imat, ob->obmat);
		mul_m4_v3(ob->imat, cent);
	}
	else {
		if (around == V3D_CENTROID) {
			int total = 0;
			zero_v3(cent);
			for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
				total += 2;
				add_v3_v3(cent, ebone->head);
				add_v3_v3(cent, ebone->tail);
			}
			if (total) {
				mul_v3_fl(cent, 1.0f / (float)total);
			}
		}
		else {
			float min[3], max[3];
			INIT_MINMAX(min, max);
			for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
				minmax_v3v3_v3(min, max, ebone->head);
				minmax_v3v3_v3(min, max, ebone->tail);
			}
			mid_v3_v3v3(cent, min, max);
		}
	}
	
	/* Do the adjustments */
	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		sub_v3_v3(ebone->head, cent);
		sub_v3_v3(ebone->tail, cent);
	}
	
	/* Turn the list into an armature */
	if (obedit == NULL) {
		ED_armature_from_edit(ob);
		ED_armature_edit_free(ob);
	}

	/* Adjust object location for new centerpoint */
	if (centermode && obedit == NULL) {
		mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
		add_v3_v3(ob->loc, cent);
	}
}
예제 #22
0
static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierData *mmd, MeshDeformBind *mdb)
{
	MDefBindInfluence *inf;
	MDefInfluence *mdinf;
	MDefCell *cell;
	float center[3], vec[3], maxwidth, totweight;
	int a, b, x, y, z, totinside, offset;

	/* compute bounding box of the cage mesh */
	INIT_MINMAX(mdb->min, mdb->max);

	for (a = 0; a < mdb->totcagevert; a++)
		minmax_v3v3_v3(mdb->min, mdb->max, mdb->cagecos[a]);

	/* allocate memory */
	mdb->size = (2 << (mmd->gridsize - 1)) + 2;
	mdb->size3 = mdb->size * mdb->size * mdb->size;
	mdb->tag = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformBindTag");
	mdb->phi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindPhi");
	mdb->totalphi = MEM_callocN(sizeof(float) * mdb->size3, "MeshDeformBindTotalPhi");
	mdb->boundisect = MEM_callocN(sizeof(*mdb->boundisect) * mdb->size3, "MDefBoundIsect");
	mdb->semibound = MEM_callocN(sizeof(int) * mdb->size3, "MDefSemiBound");
	mdb->bvhtree = bvhtree_from_mesh_looptri(&mdb->bvhdata, mdb->cagedm, FLT_EPSILON * 100, 4, 6);
	mdb->inside = MEM_callocN(sizeof(int) * mdb->totvert, "MDefInside");

	if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
		mdb->dyngrid = MEM_callocN(sizeof(MDefBindInfluence *) * mdb->size3, "MDefDynGrid");
	else
		mdb->weights = MEM_callocN(sizeof(float) * mdb->totvert * mdb->totcagevert, "MDefWeights");

	mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");
	BLI_memarena_use_calloc(mdb->memarena);

	/* initialize data from 'cagedm' for reuse */
	{
		DerivedMesh *dm = mdb->cagedm;
		mdb->cagedm_cache.mpoly = dm->getPolyArray(dm);
		mdb->cagedm_cache.mloop = dm->getLoopArray(dm);
		mdb->cagedm_cache.looptri = dm->getLoopTriArray(dm);
		mdb->cagedm_cache.poly_nors = dm->getPolyDataArray(dm, CD_NORMAL);  /* can be NULL */
	}

	/* make bounding box equal size in all directions, add padding, and compute
	 * width of the cells */
	maxwidth = -1.0f;
	for (a = 0; a < 3; a++)
		if (mdb->max[a] - mdb->min[a] > maxwidth)
			maxwidth = mdb->max[a] - mdb->min[a];

	for (a = 0; a < 3; a++) {
		center[a] = (mdb->min[a] + mdb->max[a]) * 0.5f;
		mdb->min[a] = center[a] - maxwidth * 0.5f;
		mdb->max[a] = center[a] + maxwidth * 0.5f;

		mdb->width[a] = (mdb->max[a] - mdb->min[a]) / (mdb->size - 4);
		mdb->min[a] -= 2.1f * mdb->width[a];
		mdb->max[a] += 2.1f * mdb->width[a];

		mdb->width[a] = (mdb->max[a] - mdb->min[a]) / mdb->size;
		mdb->halfwidth[a] = mdb->width[a] * 0.5f;
	}

	progress_bar(0, "Setting up mesh deform system");

	totinside = 0;
	for (a = 0; a < mdb->totvert; a++) {
		copy_v3_v3(vec, mdb->vertexcos[a]);
		mdb->inside[a] = meshdeform_inside_cage(mdb, vec);
		if (mdb->inside[a])
			totinside++;
	}

	/* free temporary MDefBoundIsects */
	BLI_memarena_free(mdb->memarena);
	mdb->memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "harmonic coords arena");

	/* start with all cells untyped */
	for (a = 0; a < mdb->size3; a++)
		mdb->tag[a] = MESHDEFORM_TAG_UNTYPED;
	
	/* detect intersections and tag boundary cells */
	for (z = 0; z < mdb->size; z++)
		for (y = 0; y < mdb->size; y++)
			for (x = 0; x < mdb->size; x++)
				meshdeform_add_intersections(mdb, x, y, z);

	/* compute exterior and interior tags */
	meshdeform_bind_floodfill(mdb);

	for (z = 0; z < mdb->size; z++)
		for (y = 0; y < mdb->size; y++)
			for (x = 0; x < mdb->size; x++)
				meshdeform_check_semibound(mdb, x, y, z);

	/* solve */
	meshdeform_matrix_solve(mmd, mdb);

	/* assign results */
	if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
		mmd->totinfluence = 0;
		for (a = 0; a < mdb->size3; a++)
			for (inf = mdb->dyngrid[a]; inf; inf = inf->next)
				mmd->totinfluence++;

		/* convert MDefBindInfluences to smaller MDefInfluences */
		mmd->dyngrid = MEM_callocN(sizeof(MDefCell) * mdb->size3, "MDefDynGrid");
		mmd->dyninfluences = MEM_callocN(sizeof(MDefInfluence) * mmd->totinfluence, "MDefInfluence");
		offset = 0;
		for (a = 0; a < mdb->size3; a++) {
			cell = &mmd->dyngrid[a];
			cell->offset = offset;

			totweight = 0.0f;
			mdinf = mmd->dyninfluences + cell->offset;
			for (inf = mdb->dyngrid[a]; inf; inf = inf->next, mdinf++) {
				mdinf->weight = inf->weight;
				mdinf->vertex = inf->vertex;
				totweight += mdinf->weight;
				cell->totinfluence++;
			}

			if (totweight > 0.0f) {
				mdinf = mmd->dyninfluences + cell->offset;
				for (b = 0; b < cell->totinfluence; b++, mdinf++)
					mdinf->weight /= totweight;
			}

			offset += cell->totinfluence;
		}

		mmd->dynverts = mdb->inside;
		mmd->dyngridsize = mdb->size;
		copy_v3_v3(mmd->dyncellmin, mdb->min);
		mmd->dyncellwidth = mdb->width[0];
		MEM_freeN(mdb->dyngrid);
	}
	else {
		mmd->bindweights = mdb->weights;
		MEM_freeN(mdb->inside);
	}

	MEM_freeN(mdb->tag);
	MEM_freeN(mdb->phi);
	MEM_freeN(mdb->totalphi);
	MEM_freeN(mdb->boundisect);
	MEM_freeN(mdb->semibound);
	BLI_memarena_free(mdb->memarena);
	free_bvhtree_from_mesh(&mdb->bvhdata);
}
예제 #23
0
void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr)
{
	while (nbr--) {
		minmax_v3v3_v3(r_min, r_max, *vec_arr++);
	}
}
예제 #24
0
void curve_deform_verts(
        Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
        int numVerts, const char *vgroup, short defaxis)
{
	Curve *cu;
	int a;
	CurveDeform cd;
	MDeformVert *dvert = NULL;
	int defgrp_index = -1;
	const bool is_neg_axis = (defaxis > 2);

	if (cuOb->type != OB_CURVE)
		return;

	cu = cuOb->data;

	init_curve_deform(cuOb, target, &cd);

	/* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
	if (is_neg_axis == false) {
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
	}
	else {
		/* negative, these bounds give a good rest position */
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] =  0.0f;
	}
	
	/* Check whether to use vertex groups (only possible if target is a Mesh or Lattice).
	 * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
	 */
	if (vgroup && vgroup[0] && ELEM(target->type, OB_MESH, OB_LATTICE)) {
		defgrp_index = defgroup_name_index(target, vgroup);

		if (defgrp_index != -1) {
			/* if there's derived data without deformverts, don't use vgroups */
			if (dm) {
				dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
			}
			else if (target->type == OB_LATTICE) {
				dvert = ((Lattice *)target->data)->dvert;
			}
			else {
				dvert = ((Mesh *)target->data)->dvert;
			}
		}
	}

	if (dvert) {
		MDeformVert *dvert_iter;
		float vec[3];

		if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
			for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
				const float weight = defvert_find_weight(dvert_iter, defgrp_index);

				if (weight > 0.0f) {
					mul_m4_v3(cd.curvespace, vertexCos[a]);
					copy_v3_v3(vec, vertexCos[a]);
					calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
					interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
					mul_m4_v3(cd.objectspace, vertexCos[a]);
				}
			}
		}
		else {
			/* set mesh min/max bounds */
			INIT_MINMAX(cd.dmin, cd.dmax);

			for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
				if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) {
					mul_m4_v3(cd.curvespace, vertexCos[a]);
					minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
				}
			}

			for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
				const float weight = defvert_find_weight(dvert_iter, defgrp_index);

				if (weight > 0.0f) {
					/* already in 'cd.curvespace', prev for loop */
					copy_v3_v3(vec, vertexCos[a]);
					calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
					interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
					mul_m4_v3(cd.objectspace, vertexCos[a]);
				}
			}
		}
	}
	else {
		if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
		else {
			/* set mesh min max bounds */
			INIT_MINMAX(cd.dmin, cd.dmax);
				
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
			}
	
			for (a = 0; a < numVerts; a++) {
				/* already in 'cd.curvespace', prev for loop */
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
	}
}
예제 #25
0
static DerivedMesh *arrayModifier_doArray(
        ArrayModifierData *amd,
        Scene *scene, Object *ob, DerivedMesh *dm,
        ModifierApplyFlag flag)
{
	const float eps = 1e-6f;
	const MVert *src_mvert;
	MVert *mv, *mv_prev, *result_dm_verts;

	MEdge *me;
	MLoop *ml;
	MPoly *mp;
	int i, j, c, count;
	float length = amd->length;
	/* offset matrix */
	float offset[4][4];
	float scale[3];
	bool offset_has_scale;
	float current_offset[4][4];
	float final_offset[4][4];
	int *full_doubles_map = NULL;
	int tot_doubles;

	const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0;
	const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge;
	const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob);

	int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
	int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0;
	int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0;
	int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys;
	int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;

	DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL;

	int *vgroup_start_cap_remap = NULL;
	int vgroup_start_cap_remap_len = 0;
	int *vgroup_end_cap_remap = NULL;
	int vgroup_end_cap_remap_len = 0;

	chunk_nverts = dm->getNumVerts(dm);
	chunk_nedges = dm->getNumEdges(dm);
	chunk_nloops = dm->getNumLoops(dm);
	chunk_npolys = dm->getNumPolys(dm);

	count = amd->count;

	if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) {
		vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(amd->start_cap, ob, &vgroup_start_cap_remap_len);

		start_cap_dm = get_dm_for_modifier(amd->start_cap, flag);
		if (start_cap_dm) {
			start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm);
			start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm);
			start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm);
			start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm);
		}
	}
	if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) {
		vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(amd->end_cap, ob, &vgroup_end_cap_remap_len);

		end_cap_dm = get_dm_for_modifier(amd->end_cap, flag);
		if (end_cap_dm) {
			end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm);
			end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm);
			end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm);
			end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm);
		}
	}

	/* Build up offset array, cumulating all settings options */

	unit_m4(offset);
	src_mvert = dm->getVertArray(dm);

	if (amd->offset_type & MOD_ARR_OFF_CONST) {
		add_v3_v3(offset[3], amd->offset);
	}

	if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
		float min[3], max[3];
		const MVert *src_mv;

		INIT_MINMAX(min, max);
		for (src_mv = src_mvert, j = chunk_nverts; j--; src_mv++) {
			minmax_v3v3_v3(min, max, src_mv->co);
		}

		for (j = 3; j--; ) {
			offset[3][j] += amd->scale[j] * (max[j] - min[j]);
		}
	}

	if (use_offset_ob) {
		float obinv[4][4];
		float result_mat[4][4];

		if (ob)
			invert_m4_m4(obinv, ob->obmat);
		else
			unit_m4(obinv);

		mul_m4_series(result_mat, offset,
		              obinv, amd->offset_ob->obmat);
		copy_m4_m4(offset, result_mat);
	}

	/* Check if there is some scaling.  If scaling, then we will not translate mapping */
	mat4_to_size(scale, offset);
	offset_has_scale = !is_one_v3(scale);

	if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
		Curve *cu = amd->curve_ob->data;
		if (cu) {
#ifdef CYCLIC_DEPENDENCY_WORKAROUND
			if (amd->curve_ob->curve_cache == NULL) {
				BKE_displist_make_curveTypes(scene, amd->curve_ob, false);
			}
#endif

			if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) {
				float scale_fac = mat4_to_scale(amd->curve_ob->obmat);
				length = scale_fac * amd->curve_ob->curve_cache->path->totdist;
			}
		}
	}

	/* calculate the maximum number of copies which will fit within the
	 * prescribed length */
	if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) {
		float dist = len_v3(offset[3]);

		if (dist > eps) {
			/* this gives length = first copy start to last copy end
			 * add a tiny offset for floating point rounding errors */
			count = (length + eps) / dist + 1;
		}
		else {
			/* if the offset has no translation, just make one copy */
			count = 1;
		}
	}

	if (count < 1)
		count = 1;

	/* The number of verts, edges, loops, polys, before eventually merging doubles */
	result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts;
	result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges;
	result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops;
	result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys;

	/* Initialize a result dm */
	result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys);
	result_dm_verts = CDDM_get_verts(result);

	if (use_merge) {
		/* Will need full_doubles_map for handling merge */
		full_doubles_map = MEM_malloc_arrayN(result_nverts, sizeof(int), "mod array doubles map");
		copy_vn_i(full_doubles_map, result_nverts, -1);
	}

	/* copy customdata to original geometry */
	DM_copy_vert_data(dm, result, 0, 0, chunk_nverts);
	DM_copy_edge_data(dm, result, 0, 0, chunk_nedges);
	DM_copy_loop_data(dm, result, 0, 0, chunk_nloops);
	DM_copy_poly_data(dm, result, 0, 0, chunk_npolys);

	/* Subsurf for eg won't have mesh data in the custom data arrays.
	 * now add mvert/medge/mpoly layers. */

	if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) {
		dm->copyVertArray(dm, result_dm_verts);
	}
	if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) {
		dm->copyEdgeArray(dm, CDDM_get_edges(result));
	}
	if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) {
		dm->copyLoopArray(dm, CDDM_get_loops(result));
		dm->copyPolyArray(dm, CDDM_get_polys(result));
	}

	/* Remember first chunk, in case of cap merge */
	first_chunk_start = 0;
	first_chunk_nverts = chunk_nverts;

	unit_m4(current_offset);
	for (c = 1; c < count; c++) {
		/* copy customdata to new geometry */
		DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts);
		DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges);
		DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops);
		DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys);

		mv_prev = result_dm_verts;
		mv = mv_prev + c * chunk_nverts;

		/* recalculate cumulative offset here */
		mul_m4_m4m4(current_offset, current_offset, offset);

		/* apply offset to all new verts */
		for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
			mul_m4_v3(current_offset, mv->co);

			/* We have to correct normals too, if we do not tag them as dirty! */
			if (!use_recalc_normals) {
				float no[3];
				normal_short_to_float_v3(no, mv->no);
				mul_mat3_m4_v3(current_offset, no);
				normalize_v3(no);
				normal_float_to_short_v3(mv->no, no);
			}
		}

		/* adjust edge vertex indices */
		me = CDDM_get_edges(result) + c * chunk_nedges;
		for (i = 0; i < chunk_nedges; i++, me++) {
			me->v1 += c * chunk_nverts;
			me->v2 += c * chunk_nverts;
		}

		mp = CDDM_get_polys(result) + c * chunk_npolys;
		for (i = 0; i < chunk_npolys; i++, mp++) {
			mp->loopstart += c * chunk_nloops;
		}

		/* adjust loop vertex and edge indices */
		ml = CDDM_get_loops(result) + c * chunk_nloops;
		for (i = 0; i < chunk_nloops; i++, ml++) {
			ml->v += c * chunk_nverts;
			ml->e += c * chunk_nedges;
		}

		/* Handle merge between chunk n and n-1 */
		if (use_merge && (c >= 1)) {
			if (!offset_has_scale && (c >= 2)) {
				/* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1
				 * ... that is except if scaling makes the distance grow */
				int k;
				int this_chunk_index = c * chunk_nverts;
				int prev_chunk_index = (c - 1) * chunk_nverts;
				for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) {
					int target = full_doubles_map[prev_chunk_index];
					if (target != -1) {
						target += chunk_nverts; /* translate mapping */
						while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) {
							/* If target is already mapped, we only follow that mapping if final target remains
							 * close enough from current vert (otherwise no mapping at all). */
							if (compare_len_v3v3(result_dm_verts[this_chunk_index].co,
							                     result_dm_verts[full_doubles_map[target]].co,
							                     amd->merge_dist))
							{
								target = full_doubles_map[target];
							}
							else {
								target = -1;
							}
						}
					}
					full_doubles_map[this_chunk_index] = target;
				}
			}
			else {
				dm_mvert_map_doubles(
				        full_doubles_map,
				        result_dm_verts,
				        (c - 1) * chunk_nverts,
				        chunk_nverts,
				        c * chunk_nverts,
				        chunk_nverts,
				        amd->merge_dist);
			}
		}
	}

	/* handle UVs */
	if (chunk_nloops > 0 && is_zero_v2(amd->uv_offset) == false) {
		const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
		for (i = 0; i < totuv; i++) {
			MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, i);
			dmloopuv += chunk_nloops;
			for (c = 1; c < count; c++) {
				const float uv_offset[2] = {
					amd->uv_offset[0] * (float)c,
					amd->uv_offset[1] * (float)c,
				};
				int l_index = chunk_nloops;
				for (; l_index-- != 0; dmloopuv++) {
					dmloopuv->uv[0] += uv_offset[0];
					dmloopuv->uv[1] += uv_offset[1];
				}
			}
		}
	}

	last_chunk_start = (count - 1) * chunk_nverts;
	last_chunk_nverts = chunk_nverts;

	copy_m4_m4(final_offset, current_offset);

	if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) {
		/* Merge first and last copies */
		dm_mvert_map_doubles(
		        full_doubles_map,
		        result_dm_verts,
		        last_chunk_start,
		        last_chunk_nverts,
		        first_chunk_start,
		        first_chunk_nverts,
		        amd->merge_dist);
	}

	/* start capping */
	if (start_cap_dm) {
		float start_offset[4][4];
		int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts;
		invert_m4_m4(start_offset, offset);
		dm_merge_transform(
		        result, start_cap_dm, start_offset,
		        result_nverts - start_cap_nverts - end_cap_nverts,
		        result_nedges - start_cap_nedges - end_cap_nedges,
		        result_nloops - start_cap_nloops - end_cap_nloops,
		        result_npolys - start_cap_npolys - end_cap_npolys,
		        start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys,
		        vgroup_start_cap_remap, vgroup_start_cap_remap_len);
		/* Identify doubles with first chunk */
		if (use_merge) {
			dm_mvert_map_doubles(
			        full_doubles_map,
			        result_dm_verts,
			        first_chunk_start,
			        first_chunk_nverts,
			        start_cap_start,
			        start_cap_nverts,
			        amd->merge_dist);
		}
	}

	if (end_cap_dm) {
		float end_offset[4][4];
		int end_cap_start = result_nverts - end_cap_nverts;
		mul_m4_m4m4(end_offset, current_offset, offset);
		dm_merge_transform(
		        result, end_cap_dm, end_offset,
		        result_nverts - end_cap_nverts,
		        result_nedges - end_cap_nedges,
		        result_nloops - end_cap_nloops,
		        result_npolys - end_cap_npolys,
		        end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys,
		        vgroup_end_cap_remap, vgroup_end_cap_remap_len);
		/* Identify doubles with last chunk */
		if (use_merge) {
			dm_mvert_map_doubles(
			        full_doubles_map,
			        result_dm_verts,
			        last_chunk_start,
			        last_chunk_nverts,
			        end_cap_start,
			        end_cap_nverts,
			        amd->merge_dist);
		}
	}
	/* done capping */

	/* Handle merging */
	tot_doubles = 0;
	if (use_merge) {
		for (i = 0; i < result_nverts; i++) {
			int new_i = full_doubles_map[i];
			if (new_i != -1) {
				/* We have to follow chains of doubles (merge start/end especially is likely to create some),
				 * those are not supported at all by CDDM_merge_verts! */
				while (!ELEM(full_doubles_map[new_i], -1, new_i)) {
					new_i = full_doubles_map[new_i];
				}
				if (i == new_i) {
					full_doubles_map[i] = -1;
				}
				else {
					full_doubles_map[i] = new_i;
					tot_doubles++;
				}
			}
		}
		if (tot_doubles > 0) {
			result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL);
		}
		MEM_freeN(full_doubles_map);
	}

	/* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm!
	 * TODO: we may need to set other dirty flags as well?
	 */
	if (use_recalc_normals) {
		result->dirty |= DM_DIRTY_NORMALS;
	}

	if (vgroup_start_cap_remap) {
		MEM_freeN(vgroup_start_cap_remap);
	}
	if (vgroup_end_cap_remap) {
		MEM_freeN(vgroup_end_cap_remap);
	}

	return result;
}