Example #1
0
/* Raytracing for vertex to bone/vertex visibility */
static void heat_ray_tree_create(LaplacianSystem *sys)
{
	MFace *mface = sys->heat.mface;
	float (*verts)[3] = sys->heat.verts;
	int totface = sys->heat.totface;
	int totvert = sys->heat.totvert;
	int a;

	sys->heat.bvhtree = BLI_bvhtree_new(totface, 0.0f, 4, 6);
	sys->heat.vface = MEM_callocN(sizeof(MFace*)*totvert, "HeatVFaces");

	for(a=0; a<totface; a++) {
		MFace *mf = mface+a;
		float bb[6];

		INIT_MINMAX(bb, bb+3);
		DO_MINMAX(verts[mf->v1], bb, bb+3);
		DO_MINMAX(verts[mf->v2], bb, bb+3);
		DO_MINMAX(verts[mf->v3], bb, bb+3);
		if(mf->v4) {
			DO_MINMAX(verts[mf->v4], bb, bb+3);
		}

		BLI_bvhtree_insert(sys->heat.bvhtree, a, bb, 2);
		
		//Setup inverse pointers to use on isect.orig
		sys->heat.vface[mf->v1]= mf;
		sys->heat.vface[mf->v2]= mf;
		sys->heat.vface[mf->v3]= mf;
		if(mf->v4) sys->heat.vface[mf->v4]= mf;
	}

	BLI_bvhtree_balance(sys->heat.bvhtree); 
}
Example #2
0
/* find the bounding box of an objectinstance in global space */
void global_bounds_obi(Render *re, ObjectInstanceRen *obi, float *bbmin, float *bbmax)
{
	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);
		
		DO_MINMAX(co, vp->bbmin, vp->bbmax);
	}
Example #3
0
/* if end, ob can be NULL */
intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
{
	MocNode **bt;
	
	if(mode=='u') {		/* use table */
		if(MeshOctree.table==NULL)
			mesh_octree_table(ob, em, NULL, 's');
	   
		if(MeshOctree.table) {
			Mesh *me= ob->data;
			bt= MeshOctree.table + mesh_octree_get_base_offs(co, MeshOctree.offs, MeshOctree.div);
			if(em)
				return mesh_octree_find_index(bt, NULL, co);
			else
				return mesh_octree_find_index(bt, me->mvert, co);
		}
		return -1;
	}
	else if(mode=='s') {	/* start table */
		Mesh *me= ob->data;
		float min[3], max[3];

		/* we compute own bounding box and don't reuse ob->bb because
		 * we are using the undeformed coordinates*/
		INIT_MINMAX(min, max);

		if(em && me->edit_mesh==em) {
			EditVert *eve;
			
			for(eve= em->verts.first; eve; eve= eve->next)
				DO_MINMAX(eve->co, min, max)
		}
Example #4
0
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;
}
Example #5
0
void rtbuild_add(RTBuilder *b, RayObject *o)
{
	float bb[6];

	assert(b->primitives.begin + b->primitives.maxsize != b->primitives.end);

	INIT_MINMAX(bb, bb + 3);
	RE_rayobject_merge_bb(o, bb, bb + 3);

	/* skip objects with invalid bounding boxes, nan causes DO_MINMAX
	 * to do nothing, so we get these invalid values. this shouldn't
	 * happen usually, but bugs earlier in the pipeline can cause it. */
	if (bb[0] > bb[3] || bb[1] > bb[4] || bb[2] > bb[5])
		return;
	/* skip objects with inf bounding boxes */
	if (!finite(bb[0]) || !finite(bb[1]) || !finite(bb[2]))
		return;
	if (!finite(bb[3]) || !finite(bb[4]) || !finite(bb[5]))
		return;
	/* skip objects with zero bounding box, they are of no use, and
	 * will give problems in rtbuild_heuristic_object_split later */
	if (bb[0] == bb[3] && bb[1] == bb[4] && bb[2] == bb[5])
		return;
	
	copy_v3_v3(b->primitives.end->bb, bb);
	copy_v3_v3(b->primitives.end->bb + 3, bb + 3);
	b->primitives.end->obj = o;
	b->primitives.end->cost = RE_rayobject_cost(o);
	
	for (int i = 0; i < 3; i++) {
		*(b->sorted_end[i]) = b->primitives.end;
		b->sorted_end[i]++;
	}
	b->primitives.end++;
}
Example #6
0
void BKE_mesh_boundbox_calc(Mesh *me, float r_loc[3], float r_size[3])
{
	BoundBox *bb;
	float min[3], max[3];
	float mloc[3], msize[3];
	
	if (me->bb == NULL) me->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
	bb = me->bb;

	if (!r_loc) r_loc = mloc;
	if (!r_size) r_size = msize;
	
	INIT_MINMAX(min, max);
	if (!BKE_mesh_minmax(me, min, max)) {
		min[0] = min[1] = min[2] = -1.0f;
		max[0] = max[1] = max[2] = 1.0f;
	}

	mid_v3_v3v3(r_loc, min, max);
		
	r_size[0] = (max[0] - min[0]) / 2.0f;
	r_size[1] = (max[1] - min[1]) / 2.0f;
	r_size[2] = (max[2] - min[2]) / 2.0f;
	
	BKE_boundbox_init_from_minmax(bb, min, max);

	bb->flag &= ~BOUNDBOX_DIRTY;
}
Example #7
0
void boundbox_mesh(Mesh *me, float *loc, float *size)
{
	BoundBox *bb;
	float min[3], max[3];
	float mloc[3], msize[3];
	
	if(me->bb==NULL) me->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
	bb= me->bb;

	if (!loc) loc= mloc;
	if (!size) size= msize;
	
	INIT_MINMAX(min, max);
	if(!minmax_mesh(me, min, max)) {
		min[0] = min[1] = min[2] = -1.0f;
		max[0] = max[1] = max[2] = 1.0f;
	}

	mid_v3_v3v3(loc, min, max);
		
	size[0]= (max[0]-min[0])/2.0f;
	size[1]= (max[1]-min[1])/2.0f;
	size[2]= (max[2]-min[2])/2.0f;
	
	boundbox_set_from_min_max(bb, min, max);
}
Example #8
0
static void generate_vert_coordinates(
        DerivedMesh *dm, Object *ob, Object *ob_center, const float offset[3],
        const int num_verts, float (*r_cos)[3], float r_size[3])
{
	float min_co[3], max_co[3];
	float diff[3];
	bool do_diff = false;

	INIT_MINMAX(min_co, max_co);

	dm->getVertCos(dm, r_cos);

	/* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */
	if (ob_center) {
		/* Not we are not interested in signs here - they are even troublesome actually, due to security clamping! */
		abs_v3_v3(r_size, ob_center->size);
	}
	else {
		minmax_v3v3_v3_array(min_co, max_co, r_cos, num_verts);
		/* Set size. */
		sub_v3_v3v3(r_size, max_co, min_co);
	}

	/* Error checks - we do not want one or more of our sizes to be null! */
	if (is_zero_v3(r_size)) {
		r_size[0] = r_size[1] = r_size[2] = 1.0f;
	}
	else {
		CLAMP_MIN(r_size[0], FLT_EPSILON);
		CLAMP_MIN(r_size[1], FLT_EPSILON);
		CLAMP_MIN(r_size[2], FLT_EPSILON);
	}

	if (ob_center) {
		float inv_obmat[4][4];

		/* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
		/* Get ob_center (world) coordinates in ob local coordinates.
		 * No need to take into account ob_center's space here, see T44027. */
		invert_m4_m4(inv_obmat, ob->obmat);
		mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]);
		negate_v3(diff);

		do_diff = true;
	}
	else if (!is_zero_v3(offset)) {
		negate_v3_v3(diff, offset);

		do_diff = true;
	}
	/* Else, no need to change coordinates! */

	if (do_diff) {
		int i = num_verts;
		while (i--) {
			add_v3_v3(r_cos[i], diff);
		}
	}
}
void BKE_lattice_center_bounds(Lattice *lt, float cent[3])
{
	float min[3], max[3];

	INIT_MINMAX(min, max);

	BKE_lattice_minmax(lt, min, max);
	mid_v3_v3v3(cent, min, max);
}
bool BL_ModifierDeformer::Update(void)
{
	bool bShapeUpdate = BL_ShapeDeformer::Update();

	if (bShapeUpdate || m_lastModifierUpdate != m_gameobj->GetLastFrame()) {
		// static derived mesh are not updated
		if (m_dm == NULL || m_bDynamic) {
			/* execute the modifiers */
			Object* blendobj = m_gameobj->GetBlendObject();
			/* hack: the modifiers require that the mesh is attached to the object
			 * It may not be the case here because of replace mesh actuator */
			Mesh *oldmesh = (Mesh*)blendobj->data;
			blendobj->data = m_bmesh;
			/* execute the modifiers */
			DerivedMesh *dm = mesh_create_derived_no_virtual(m_scene, blendobj, m_transverts, CD_MASK_MESH);
			/* restore object data */
			blendobj->data = oldmesh;
			/* free the current derived mesh and replace, (dm should never be NULL) */
			if (m_dm != NULL) {
				// HACK! use deformedOnly as a user counter
				if (--m_dm->deformedOnly == 0) {
					m_dm->needsFree = 1;
					m_dm->release(m_dm);
				}
			}
			m_dm = dm;
			// get rid of temporary data
			m_dm->needsFree = 0;
			m_dm->release(m_dm);
			// HACK! use deformedOnly as a user counter
			m_dm->deformedOnly = 1;
			DM_update_materials(m_dm, blendobj);
			/* update the graphic controller */
			PHY_IGraphicController *ctrl = m_gameobj->GetGraphicController();
			if (ctrl) {
				float min[3], max[3];
				INIT_MINMAX(min, max);
				m_dm->getMinMax(m_dm, min, max);
				ctrl->SetLocalAabb(min, max);
			}
		}
		m_lastModifierUpdate=m_gameobj->GetLastFrame();
		bShapeUpdate = true;

		int nmat = m_pMeshObject->NumMaterials();
		for (int imat=0; imat<nmat; imat++) {
			RAS_MeshMaterial *mmat = m_pMeshObject->GetMeshMaterial(imat);
			RAS_MeshSlot **slot = mmat->m_slots[(void*)m_gameobj];
			if (!slot || !*slot)
				continue;
			(*slot)->m_pDerivedMesh = m_dm;
		}
	}
	return bShapeUpdate;
}
Example #11
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);
}
Example #12
0
RayObject *RE_rayobject_blibvh_create(int size)
{
	BVHObject *obj= (BVHObject*)MEM_callocN(sizeof(BVHObject), "BVHObject");
	assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */	
	
	obj->rayobj.api = &bvh_api;
	obj->bvh = BLI_bvhtree_new(size, 0.0, 4, 6);
	obj->next_leaf = obj->leafs = (RayObject**)MEM_callocN(size*sizeof(RayObject*), "BVHObject leafs");
	
	INIT_MINMAX(obj->bb[0], obj->bb[1]);
	return RE_rayobject_unalignRayAPI((RayObject*) obj);
}
Example #13
0
/* 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);
}
Example #14
0
static void RE_rayobject_blibvh_add(RayObject *o, RayObject *ob)
{
	BVHObject *obj = (BVHObject*)o;
	float min_max[6];
	INIT_MINMAX(min_max, min_max+3);
	RE_rayobject_merge_bb(ob, min_max, min_max+3);

	DO_MIN(min_max,     obj->bb[0]);
	DO_MAX(min_max + 3, obj->bb[1]);
	
	BLI_bvhtree_insert(obj->bvh, obj->next_leaf - obj->leafs, min_max, 2);	
	*(obj->next_leaf++) = ob;
}
/**
 * Recursively builds a BVH, dividing elements along the middle of the longest axis of allbox.
 */
static void build_bvh_spatial(
        PROCESS *process, MetaballBVHNode *node,
        unsigned int start, unsigned int end, const Box *allbox)
{
	unsigned int part, j, s;
	float dim[3], div;

	/* Maximum bvh queue size is number of nodes which are made, equals calls to this function. */
	process->bvh_queue_size++;

	dim[0] = allbox->max[0] - allbox->min[0];
	dim[1] = allbox->max[1] - allbox->min[1];
	dim[2] = allbox->max[2] - allbox->min[2];

	s = 0;
	if (dim[1] > dim[0] && dim[1] > dim[2]) s = 1;
	else if (dim[2] > dim[1] && dim[2] > dim[0]) s = 2;

	div = allbox->min[s] + (dim[s] / 2.0f);

	part = partition_mainb(process->mainb, start, end, s, div);

	make_box_from_metaelem(&node->bb[0], process->mainb[start]);
	node->child[0] = NULL;

	if (part > start + 1) {
		for (j = start; j < part; j++) {
			make_box_union(process->mainb[j]->bb, &node->bb[0], &node->bb[0]);
		}

		node->child[0] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
		build_bvh_spatial(process, node->child[0], start, part, &node->bb[0]);
	}

	node->child[1] = NULL;
	if (part < end) {
		make_box_from_metaelem(&node->bb[1], process->mainb[part]);

		if (part < end - 1) {
			for (j = part; j < end; j++) {
				make_box_union(process->mainb[j]->bb, &node->bb[1], &node->bb[1]);
			}

			node->child[1] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode));
			build_bvh_spatial(process, node->child[1], part, end, &node->bb[1]);
		}
	}
	else {
		INIT_MINMAX(node->bb[1].min, node->bb[1].max);
	}
}
Example #16
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);
	}
}
Example #17
0
static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3])
{
	Cloth *cloth = clmd->clothObject;
	Implicit_Data *data = cloth->implicit;
	unsigned int mvert_num = cloth->mvert_num;
	int i;
	
	INIT_MINMAX(gmin, gmax);
	for (i = 0; i < mvert_num; i++) {
		float x[3];
		BPH_mass_spring_get_motion_state(data, i, x, NULL);
		DO_MINMAX(x, gmin, gmax);
	}
}
Example #18
0
static void init_dualcon_mesh(DualConInput *mesh, DerivedMesh *dm)
{
	memset(mesh, 0, sizeof(DualConInput));

	mesh->co = (void *)dm->getVertArray(dm);
	mesh->co_stride = sizeof(MVert);
	mesh->totco = dm->getNumVerts(dm);

	mesh->faces = (void *)dm->getTessFaceArray(dm);
	mesh->face_stride = sizeof(MFace);
	mesh->totface = dm->getNumTessFaces(dm);

	INIT_MINMAX(mesh->min, mesh->max);
	dm->getMinMax(dm, mesh->min, mesh->max);
}
Example #19
0
static void rtbuild_init(RTBuilder *b)
{
	b->split_axis = -1;
	b->primitives.begin   = NULL;
	b->primitives.end     = NULL;
	b->primitives.maxsize = 0;
	
	for (int i = 0; i < RTBUILD_MAX_CHILDS; i++)
		b->child_offset[i] = 0;

	for (int i = 0; i < 3; i++)
		b->sorted_begin[i] = b->sorted_end[i] = NULL;
		
	INIT_MINMAX(b->bb, b->bb + 3);
}
static void boundbox_lattice(Object *ob)
{
	BoundBox *bb;
	Lattice *lt;
	float min[3], max[3];

	if (ob->bb == NULL)
		ob->bb = MEM_mallocN(sizeof(BoundBox), "Lattice boundbox");

	bb = ob->bb;
	lt = ob->data;

	INIT_MINMAX(min, max);
	BKE_lattice_minmax_dl(ob, lt, min, max);
	BKE_boundbox_init_from_minmax(bb, min, max);
}
static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
{
    //TODO:
    // *better bb.. calculated without rotations of bb
    // *maybe cache that better-fitted-BB at the InstanceRayObject
    InstanceRayObject *obj = (InstanceRayObject *)o;

    float m[3], M[3], t[3];
    int i, j;
    INIT_MINMAX(m, M);
    RE_rayobject_merge_bb(obj->target, m, M);

    //There must be a faster way than rotating all the 8 vertexs of the BB
    for (i = 0; i < 8; i++) {
        for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j];
        mul_m4_v3(obj->target2global, t);
        DO_MINMAX(t, min, max);
    }
}
Example #22
0
static void init_dualcon_mesh(DualConInput *input, Mesh *mesh)
{
  memset(input, 0, sizeof(DualConInput));

  input->co = (void *)mesh->mvert;
  input->co_stride = sizeof(MVert);
  input->totco = mesh->totvert;

  input->mloop = (void *)mesh->mloop;
  input->loop_stride = sizeof(MLoop);

  BKE_mesh_runtime_looptri_ensure(mesh);
  input->looptri = (void *)mesh->runtime.looptris.array;
  input->tri_stride = sizeof(MLoopTri);
  input->tottri = mesh->runtime.looptris.len;

  INIT_MINMAX(input->min, input->max);
  BKE_mesh_minmax(mesh, input->min, input->max);
}
Example #23
0
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++)
		DO_MINMAX(tree->co[a], min, max)

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

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

	return axis;
}
Example #24
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;
}
/* 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); 
}
Example #26
0
File: mesh.c Project: jinjoh/NOOR
void boundbox_mesh(Mesh *me, float *loc, float *size)
{
	MVert *mvert;
	BoundBox *bb;
	float min[3], max[3];
	float mloc[3], msize[3];
	int a;
	
	if(me->bb==0) me->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
	bb= me->bb;
	
	INIT_MINMAX(min, max);

	if (!loc) loc= mloc;
	if (!size) size= msize;
	
	mvert= me->mvert;
	for(a=0; a<me->totvert; a++, mvert++) {
		DO_MINMAX(mvert->co, min, max);
	}

	if(!me->totvert) {
		min[0] = min[1] = min[2] = -1.0f;
		max[0] = max[1] = max[2] = 1.0f;
	}

	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;
	
	boundbox_set_from_min_max(bb, min, max);
}
Example #27
0
static DerivedMesh * applyModifier(ModifierData *md, Object *ob,
						DerivedMesh *derivedData,
						int UNUSED(useRenderParams),
						int UNUSED(isFinalCalc))
{
	DerivedMesh *dm = derivedData, *result;
	ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md;
	ParticleSimulationData sim;
	ParticleSystem *psys= NULL;
	ParticleData *pa= NULL, *pars= NULL;
	MFace *mface, *orig_mface;
	MVert *mvert, *orig_mvert;
	int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0;
	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) {
		int p;
		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);
			}
		}
	}

	pars=psys->particles;

	totvert=dm->getNumVerts(dm);
	totface=dm->getNumFaces(dm);

	maxvert=totvert*totpart;
	maxface=totface*totpart;

	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,dm->getNumEdges(dm)*totpart,maxface);

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

	for(i=0; i<maxvert; i++){
		MVert *inMV;
		MVert *mv = mvert + i;
		ParticleKey state;

		inMV = orig_mvert + i%totvert;
		DM_copy_vert_data(dm, result, i%totvert, i, 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];

		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) {
				BLI_srandom(psys->seed + (i/totvert)%totpart);
				ran = pimd->random_position * BLI_frand();
			}

			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 + i/totvert, &state,1);

			normalize_v3(state.vel);

			/* TODO: incremental rotations somehow */
			if(state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
				state.rot[0] = 1;
				state.rot[1] = state.rot[2] = state.rot[3] = 0.0f;
			}
			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 + i/totvert, &state,1);
		}

		mul_qt_v3(state.rot,mv->co);
		if(pimd->flag & eParticleInstanceFlag_UseSize)
			mul_v3_fl(mv->co, size[i/totvert]);
		VECADD(mv->co,mv->co,state.co);
	}

	mface=result->getFaceArray(result);
	orig_mface=dm->getFaceArray(dm);

	for(i=0; i<maxface; i++){
		MFace *inMF;
		MFace *mf = mface + i;

		if(pimd->flag & eParticleInstanceFlag_Parents){
			if(i/totface>=psys->totpart){
				if(psys->part->childtype==PART_CHILD_PARTICLES)
					pa=psys->particles+(psys->child+i/totface-psys->totpart)->parent;
				else
					pa= NULL;
			}
			else
				pa=pars+i/totface;
		}
		else{
			if(psys->part->childtype==PART_CHILD_PARTICLES)
				pa=psys->particles+(psys->child+i/totface)->parent;
			else
				pa= NULL;
		}

		if(pa){
			if(pa->alive==PARS_UNBORN && (pimd->flag&eParticleInstanceFlag_Unborn)==0) continue;
			if(pa->alive==PARS_ALIVE && (pimd->flag&eParticleInstanceFlag_Alive)==0) continue;
			if(pa->alive==PARS_DEAD && (pimd->flag&eParticleInstanceFlag_Dead)==0) continue;
		}

		inMF = orig_mface + i%totface;
		DM_copy_face_data(dm, result, i%totface, i, 1);
		*mf = *inMF;

		mf->v1+=(i/totface)*totvert;
		mf->v2+=(i/totface)*totvert;
		mf->v3+=(i/totface)*totvert;
		if(mf->v4)
			mf->v4+=(i/totface)*totvert;
	}

	CDDM_calc_edges(result);
	CDDM_calc_normals(result);

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

	if(size)
		MEM_freeN(size);

	return result;
}
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);
}
Example #29
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;
}
Example #30
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);
		}
	}