Exemplo n.º 1
0
/* note: this function could be optimized by some spatial structure */
static PyObject *M_Geometry_points_in_planes(PyObject *UNUSED(self), PyObject *args)
{
	PyObject *py_planes;
	float (*planes)[4];
	unsigned int planes_len;

	if (!PyArg_ParseTuple(args, "O:points_in_planes",
	                      &py_planes))
	{
		return NULL;
	}

	if ((planes_len = mathutils_array_parse_alloc_v((float **)&planes, 4, py_planes, "points_in_planes")) == -1) {
		return NULL;
	}
	else {
		/* note, this could be refactored into plain C easy - py bits are noted */
		const float eps = 0.0001f;
		const unsigned int len = (unsigned int)planes_len;
		unsigned int i, j, k, l;

		float n1n2[3], n2n3[3], n3n1[3];
		float potentialVertex[3];
		char *planes_used = MEM_callocN(sizeof(char) * len, __func__);

		/* python */
		PyObject *py_verts = PyList_New(0);
		PyObject *py_plene_index = PyList_New(0);

		for (i = 0; i < len; i++) {
			const float *N1 = planes[i];
			for (j = i + 1; j < len; j++) {
				const float *N2 = planes[j];
				cross_v3_v3v3(n1n2, N1, N2);
				if (len_squared_v3(n1n2) > eps) {
					for (k = j + 1; k < len; k++) {
						const float *N3 = planes[k];
						cross_v3_v3v3(n2n3, N2, N3);
						if (len_squared_v3(n2n3) > eps) {
							cross_v3_v3v3(n3n1, N3, N1);
							if (len_squared_v3(n3n1) > eps) {
								const float quotient = dot_v3v3(N1, n2n3);
								if (fabsf(quotient) > eps) {
									/* potentialVertex = (n2n3 * N1[3] + n3n1 * N2[3] + n1n2 * N3[3]) * (-1.0 / quotient); */
									const float quotient_ninv = -1.0f / quotient;
									potentialVertex[0] = ((n2n3[0] * N1[3]) + (n3n1[0] * N2[3]) + (n1n2[0] * N3[3])) * quotient_ninv;
									potentialVertex[1] = ((n2n3[1] * N1[3]) + (n3n1[1] * N2[3]) + (n1n2[1] * N3[3])) * quotient_ninv;
									potentialVertex[2] = ((n2n3[2] * N1[3]) + (n3n1[2] * N2[3]) + (n1n2[2] * N3[3])) * quotient_ninv;
									for (l = 0; l < len; l++) {
										const float *NP = planes[l];
										if ((dot_v3v3(NP, potentialVertex) + NP[3]) > 0.000001f) {
											break;
										}
									}

									if (l == len) { /* ok */
										/* python */
										PyObject *item = Vector_CreatePyObject(potentialVertex, 3, Py_NEW, NULL);
										PyList_Append(py_verts, item);
										Py_DECREF(item);

										planes_used[i] = planes_used[j] = planes_used[k] = TRUE;
									}
								}
							}
						}
					}
				}
			}
		}

		PyMem_Free(planes);

		/* now make a list of used planes */
		for (i = 0; i < len; i++) {
			if (planes_used[i]) {
				PyObject *item = PyLong_FromLong(i);
				PyList_Append(py_plene_index, item);
				Py_DECREF(item);
			}
		}
		MEM_freeN(planes_used);

		{
			PyObject *ret = PyTuple_New(2);
			PyTuple_SET_ITEM(ret, 0, py_verts);
			PyTuple_SET_ITEM(ret, 1, py_plene_index);
			return ret;
		}
	}
}
Exemplo n.º 2
0
/**
 * Makes an NGon from an un-ordered set of verts
 *
 * assumes...
 * - that verts are only once in the list.
 * - that the verts have roughly planer bounds
 * - that the verts are roughly circular
 * there can be concave areas but overlapping folds from the center point will fail.
 *
 * a brief explanation of the method used
 * - find the center point
 * - find the normal of the vcloud
 * - order the verts around the face based on their angle to the normal vector at the center point.
 *
 * \note Since this is a vcloud there is no direction.
 */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
	struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
	BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);

	float totv_inv = 1.0f / (float)len;
	int i = 0;

	float cent[3], nor[3];

	const float *far = NULL, *far_cross = NULL;

	float far_vec[3];
	float far_cross_vec[3];
	float sign_vec[3]; /* work out if we are pos/neg angle */

	float far_dist_sq, far_dist_max_sq;
	float far_cross_dist, far_cross_best = 0.0f;

	/* get the center point and collect vector array since we loop over these a lot */
	zero_v3(cent);
	for (i = 0; i < len; i++) {
		madd_v3_v3fl(cent, vert_arr[i]->co, totv_inv);
	}


	/* find the far point from cent */
	far_dist_max_sq = 0.0f;
	for (i = 0; i < len; i++) {
		far_dist_sq = len_squared_v3v3(vert_arr[i]->co, cent);
		if (far_dist_sq > far_dist_max_sq || far == NULL) {
			far = vert_arr[i]->co;
			far_dist_max_sq = far_dist_sq;
		}
	}

	sub_v3_v3v3(far_vec, far, cent);
	// far_dist = len_v3(far_vec); /* real dist */ /* UNUSED */

	/* --- */

	/* find a point 90deg about to compare with */
	far_cross_best = 0.0f;
	for (i = 0; i < len; i++) {

		if (far == vert_arr[i]->co) {
			continue;
		}

		sub_v3_v3v3(far_cross_vec, vert_arr[i]->co, cent);
		far_cross_dist = normalize_v3(far_cross_vec);

		/* more of a weight then a distance */
		far_cross_dist = (/* first we want to have a value close to zero mapped to 1 */
		                  1.0f - fabsf(dot_v3v3(far_vec, far_cross_vec)) *

		                  /* second  we multiply by the distance
		                   * so points close to the center are not preferred */
		                  far_cross_dist);

		if (far_cross_dist > far_cross_best || far_cross == NULL) {
			far_cross = vert_arr[i]->co;
			far_cross_best = far_cross_dist;
		}
	}

	sub_v3_v3v3(far_cross_vec, far_cross, cent);

	/* --- */

	/* now we have 2 vectors we can have a cross product */
	cross_v3_v3v3(nor, far_vec, far_cross_vec);
	normalize_v3(nor);
	cross_v3_v3v3(sign_vec, far_vec, nor); /* this vector should match 'far_cross_vec' closely */

	/* --- */

	/* now calculate every points angle around the normal (signed) */
	for (i = 0; i < len; i++) {
		vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor);
		vang[i].data = i;
		vert_arr_map[i] = vert_arr[i];
	}

	/* sort by angle and magic! - we have our ngon */
	qsort(vang, len, sizeof(*vang), BLI_sortutil_cmp_float);

	/* --- */

	for (i = 0; i < len; i++) {
		vert_arr[i] = vert_arr_map[vang[i].data];
	}
}
Exemplo n.º 3
0
int nextLengthSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float head[3], float p[3])
{
	float lengthLimit = toolsettings->skgen_length_limit;
	int same = 1;
	int i;
	
	i = start + 1;
	while (i <= end)
	{
		float *vec0;
		float *vec1;
		
		IT_peek(iter, i - 1);
		vec0 = iter->p;

		IT_peek(iter, i);
		vec1 = iter->p;
		
		/* If lengthLimit hits the current segment */
		if (len_v3v3(vec1, head) > lengthLimit)
		{
			if (same == 0)
			{
				float dv[3], off[3];
				float a, b, c, f;
				
				/* Solve quadratic distance equation */
				sub_v3_v3v3(dv, vec1, vec0);
				a = dot_v3v3(dv, dv);
				
				sub_v3_v3v3(off, vec0, head);
				b = 2 * dot_v3v3(dv, off);
				
				c = dot_v3v3(off, off) - (lengthLimit * lengthLimit);
				
				f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a);
				
				//printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
				
				if (isnan(f) == 0 && f < 1.0f)
				{
					VECCOPY(p, dv);
					mul_v3_fl(p, f);
					add_v3_v3(p, vec0);
				}
				else
				{
					VECCOPY(p, vec1);
				}
			}
			else
			{
				float dv[3];
				
				sub_v3_v3v3(dv, vec1, vec0);
				normalize_v3(dv);
				 
				VECCOPY(p, dv);
				mul_v3_fl(p, lengthLimit);
				add_v3_v3(p, head);
			}
			
			return i - 1; /* restart at lower bound */
		}
		else
		{
			i++;
			same = 0; // Reset same
		}
	}
	
	return -1;
}
Exemplo n.º 4
0
/*
 * Function adapted from David Eberly's distance tools (LGPL)
 * http://www.geometrictools.com/LibFoundation/Distance/Distance.html
 */
float nearest_point_in_tri_surface(const float v0[3], const float v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3])
{
	float diff[3];
	float e0[3];
	float e1[3];
	float A00;
	float A01;
	float A11;
	float B0;
	float B1;
	float C;
	float Det;
	float S;
	float T;
	float sqrDist;
	int lv = -1, le = -1;
	
	sub_v3_v3v3(diff, v0, p);
	sub_v3_v3v3(e0, v1, v0);
	sub_v3_v3v3(e1, v2, v0);
	
	A00 = dot_v3v3(e0, e0);
	A01 = dot_v3v3(e0, e1);
	A11 = dot_v3v3(e1, e1);
	B0 = dot_v3v3(diff, e0);
	B1 = dot_v3v3(diff, e1);
	C = dot_v3v3(diff, diff);
	Det = fabs(A00 * A11 - A01 * A01);
	S = A01 * B1 - A11 * B0;
	T = A01 * B0 - A00 * B1;

	if (S + T <= Det) {
		if (S < 0.0f) {
			if (T < 0.0f) { /* Region 4 */
				if (B0 < 0.0f) {
					T = 0.0f;
					if (-B0 >= A00) {
						S = 1.0f;
						sqrDist = A00 + 2.0f * B0 + C;
						lv = 1;
					}
					else {
						if (fabsf(A00) > FLT_EPSILON)
							S = -B0 / A00;
						else
							S = 0.0f;
						sqrDist = B0 * S + C;
						le = 0;
					}
				}
				else {
					S = 0.0f;
					if (B1 >= 0.0f) {
						T = 0.0f;
						sqrDist = C;
						lv = 0;
					}
					else if (-B1 >= A11) {
						T = 1.0f;
						sqrDist = A11 + 2.0f * B1 + C;
						lv = 2;
					}
					else {
						if (fabsf(A11) > FLT_EPSILON)
							T = -B1 / A11;
						else
							T = 0.0f;
						sqrDist = B1 * T + C;
						le = 1;
					}
				}
			}
			else { /* Region 3 */
				S = 0.0f;
				if (B1 >= 0.0f) {
					T = 0.0f;
					sqrDist = C;
					lv = 0;
				}
				else if (-B1 >= A11) {
					T = 1.0f;
					sqrDist = A11 + 2.0f * B1 + C;
					lv = 2;
				}
				else {
					if (fabsf(A11) > FLT_EPSILON)
						T = -B1 / A11;
					else
						T = 0.0;
					sqrDist = B1 * T + C;
					le = 1;
				}
			}
		}
		else if (T < 0.0f) { /* Region 5 */
			T = 0.0f;
			if (B0 >= 0.0f) {
				S = 0.0f;
				sqrDist = C;
				lv = 0;
			}
			else if (-B0 >= A00) {
				S = 1.0f;
				sqrDist = A00 + 2.0f * B0 + C;
				lv = 1;
			}
			else {
				if (fabsf(A00) > FLT_EPSILON)
					S = -B0 / A00;
				else
					S = 0.0f;
				sqrDist = B0 * S + C;
				le = 0;
			}
		}
		else { /* Region 0 */
			/* Minimum at interior lv */
			float invDet;
			if (fabsf(Det) > FLT_EPSILON)
				invDet = 1.0f / Det;
			else
				invDet = 0.0f;
			S *= invDet;
			T *= invDet;
			sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
			          T * (A01 * S + A11 * T + 2.0f * B1) + C;
		}
	}
	else {
		float tmp0, tmp1, numer, denom;

		if (S < 0.0f) { /* Region 2 */
			tmp0 = A01 + B0;
			tmp1 = A11 + B1;
			if (tmp1 > tmp0) {
				numer = tmp1 - tmp0;
				denom = A00 - 2.0f * A01 + A11;
				if (numer >= denom) {
					S = 1.0f;
					T = 0.0f;
					sqrDist = A00 + 2.0f * B0 + C;
					lv = 1;
				}
				else {
					if (fabsf(denom) > FLT_EPSILON)
						S = numer / denom;
					else
						S = 0.0f;
					T = 1.0f - S;
					sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
					          T * (A01 * S + A11 * T + 2.0f * B1) + C;
					le = 2;
				}
			}
			else {
				S = 0.0f;
				if (tmp1 <= 0.0f) {
					T = 1.0f;
					sqrDist = A11 + 2.0f * B1 + C;
					lv = 2;
				}
				else if (B1 >= 0.0f) {
					T = 0.0f;
					sqrDist = C;
					lv = 0;
				}
				else {
					if (fabsf(A11) > FLT_EPSILON)
						T = -B1 / A11;
					else
						T = 0.0f;
					sqrDist = B1 * T + C;
					le = 1;
				}
			}
		}
		else if (T < 0.0f) { /* Region 6 */
			tmp0 = A01 + B1;
			tmp1 = A00 + B0;
			if (tmp1 > tmp0) {
				numer = tmp1 - tmp0;
				denom = A00 - 2.0f * A01 + A11;
				if (numer >= denom) {
					T = 1.0f;
					S = 0.0f;
					sqrDist = A11 + 2.0f * B1 + C;
					lv = 2;
				}
				else {
					if (fabsf(denom) > FLT_EPSILON)
						T = numer / denom;
					else
						T = 0.0f;
					S = 1.0f - T;
					sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
					          T * (A01 * S + A11 * T + 2.0f * B1) + C;
					le = 2;
				}
			}
			else {
				T = 0.0f;
				if (tmp1 <= 0.0f) {
					S = 1.0f;
					sqrDist = A00 + 2.0f * B0 + C;
					lv = 1;
				}
				else if (B0 >= 0.0f) {
					S = 0.0f;
					sqrDist = C;
					lv = 0;
				}
				else {
					if (fabsf(A00) > FLT_EPSILON)
						S = -B0 / A00;
					else
						S = 0.0f;
					sqrDist = B0 * S + C;
					le = 0;
				}
			}
		}
		else { /* Region 1 */
			numer = A11 + B1 - A01 - B0;
			if (numer <= 0.0f) {
				S = 0.0f;
				T = 1.0f;
				sqrDist = A11 + 2.0f * B1 + C;
				lv = 2;
			}
			else {
				denom = A00 - 2.0f * A01 + A11;
				if (numer >= denom) {
					S = 1.0f;
					T = 0.0f;
					sqrDist = A00 + 2.0f * B0 + C;
					lv = 1;
				}
				else {
					if (fabsf(denom) > FLT_EPSILON)
						S = numer / denom;
					else
						S = 0.0f;
					T = 1.0f - S;
					sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
					          T * (A01 * S + A11 * T + 2.0f * B1) + C;
					le = 2;
				}
			}
		}
	}

	/* Account for numerical round-off error */
	if (sqrDist < FLT_EPSILON)
		sqrDist = 0.0f;
	
	{
		float w[3], x[3], y[3], z[3];
		copy_v3_v3(w, v0);
		copy_v3_v3(x, e0);
		mul_v3_fl(x, S);
		copy_v3_v3(y, e1);
		mul_v3_fl(y, T);
		add_v3_v3v3(z, w, x);
		add_v3_v3v3(z, z, y);
		//sub_v3_v3v3(d, p, z);
		copy_v3_v3(nearest, z);
		//d = p - ( v0 + S * e0 + T * e1 );
	}
	*v = lv;
	*e = le;

	return sqrDist;
}
Exemplo n.º 5
0
static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
	float norm[3], vec[3], factor, angle;
	float t_con_center[3];

	if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f)
		return;

	copy_v3_v3(t_con_center, t->con.center);

	/* checks for center being too close to the view center */
	viewAxisCorrectCenter(t, t_con_center);
	
	angle = fabsf(angle_v3v3(axis, t->viewinv[2]));
	if (angle > (float)M_PI / 2.0f) {
		angle = (float)M_PI - angle;
	}
	angle = RAD2DEGF(angle);

	/* For when view is parallel to constraint... will cause NaNs otherwise
	   So we take vertical motion in 3D space and apply it to the
	   constraint axis. Nice for camera grab + MMB */
	if(angle < 5.0f) {
		project_v3_v3v3(vec, in, t->viewinv[1]);
		factor = dot_v3v3(t->viewinv[1], vec) * 2.0f;
		/* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
		if(factor<0.0f) factor*= -factor;
		else factor*= factor;

		VECCOPY(out, axis);
		normalize_v3(out);
		mul_v3_fl(out, -factor);	/* -factor makes move down going backwards */
	}
	else {
		float v[3], i1[3], i2[3];
		float v2[3], v4[3];
		float norm_center[3];
		float plane[3];

		getViewVector(t, t_con_center, norm_center);
		cross_v3_v3v3(plane, norm_center, axis);

		project_v3_v3v3(vec, in, plane);
		sub_v3_v3v3(vec, in, vec);
		
		add_v3_v3v3(v, vec, t_con_center);
		getViewVector(t, v, norm);

		/* give arbitrary large value if projection is impossible */
		factor = dot_v3v3(axis, norm);
		if (1.0f - fabsf(factor) < 0.0002f) {
			VECCOPY(out, axis);
			if (factor > 0) {
				mul_v3_fl(out, 1000000000.0f);
			} else {
				mul_v3_fl(out, -1000000000.0f);
			}
		} else {
			add_v3_v3v3(v2, t_con_center, axis);
			add_v3_v3v3(v4, v, norm);
			
			isect_line_line_v3(t_con_center, v2, v, v4, i1, i2);
			
			sub_v3_v3v3(v, i2, v);
	
			sub_v3_v3v3(out, i1, t_con_center);

			/* possible some values become nan when
			 * viewpoint and object are both zero */
			if(!finite(out[0])) out[0]= 0.0f;
			if(!finite(out[1])) out[1]= 0.0f;
			if(!finite(out[2])) out[2]= 0.0f;
		}
	}
}
Exemplo n.º 6
0
static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
	BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule;
	KDTreeNearest *ptn = NULL;
	ParticleTarget *pt;
	BoidParticle *bpa = pa->boid;
	ColliderCache *coll;
	float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
	float co1[3], vel1[3], co2[3], vel2[3];
	float  len, t, inp, t_min = 2.0f;
	int n, neighbors = 0, nearest = 0;
	int ret = 0;

	//check deflector objects first
	if (acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
		ParticleCollision col;
		BVHTreeRayHit hit;
		float radius = val->personal_space * pa->size, ray_dir[3];

		memset(&col, 0, sizeof(ParticleCollision));

		copy_v3_v3(col.co1, pa->prev_state.co);
		add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel);
		sub_v3_v3v3(ray_dir, col.co2, col.co1);
		mul_v3_fl(ray_dir, acbr->look_ahead);
		col.f = 0.0f;
		hit.index = -1;
		hit.dist = col.original_ray_length = len_v3(ray_dir);

		/* find out closest deflector object */
		for (coll = bbd->sim->colliders->first; coll; coll=coll->next) {
			/* don't check with current ground object */
			if (coll->ob == bpa->ground)
				continue;

			col.current = coll->ob;
			col.md = coll->collmd;

			if (col.md && col.md->bvhtree)
				BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col);
		}
		/* then avoid that object */
		if (hit.index>=0) {
			t = hit.dist/col.original_ray_length;

			/* avoid head-on collision */
			if (dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) {
				/* don't know why, but uneven range [0.0, 1.0] */
				/* works much better than even [-1.0, 1.0] */
				bbd->wanted_co[0] = BLI_rng_get_float(bbd->rng);
				bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng);
				bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng);
			}
			else {
				copy_v3_v3(bbd->wanted_co, col.pce.nor);
			}

			mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size);

			bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel);
			bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed);

			return 1;
		}
	}

	//check boids in own system
	if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
		neighbors = BLI_kdtree_range_search__normal(
		        bbd->sim->psys->tree, pa->prev_state.co, pa->prev_state.ave,
		        &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel));
		if (neighbors > 1) for (n=1; n<neighbors; n++) {
			copy_v3_v3(co1, pa->prev_state.co);
			copy_v3_v3(vel1, pa->prev_state.vel);
			copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co);
			copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel);

			sub_v3_v3v3(loc, co1, co2);

			sub_v3_v3v3(vec, vel1, vel2);
			
			inp = dot_v3v3(vec, vec);

			/* velocities not parallel */
			if (inp != 0.0f) {
				t = -dot_v3v3(loc, vec)/inp;
				/* cpa is not too far in the future so investigate further */
				if (t > 0.0f && t < t_min) {
					madd_v3_v3fl(co1, vel1, t);
					madd_v3_v3fl(co2, vel2, t);
					
					sub_v3_v3v3(vec, co2, co1);

					len = normalize_v3(vec);

					/* distance of cpa is close enough */
					if (len < 2.0f * val->personal_space * pa->size) {
						t_min = t;

						mul_v3_fl(vec, len_v3(vel1));
						mul_v3_fl(vec, (2.0f - t)/2.0f);
						sub_v3_v3v3(bbd->wanted_co, vel1, vec);
						bbd->wanted_speed = len_v3(bbd->wanted_co);
						ret = 1;
					}
				}
			}
		}
	}
	if (ptn) { MEM_freeN(ptn); ptn=NULL; }

	/* check boids in other systems */
	for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
		ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);

		if (epsys) {
			neighbors = BLI_kdtree_range_search__normal(
			        epsys->tree, pa->prev_state.co, pa->prev_state.ave,
			        &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel));

			if (neighbors > 0) for (n=0; n<neighbors; n++) {
				copy_v3_v3(co1, pa->prev_state.co);
				copy_v3_v3(vel1, pa->prev_state.vel);
				copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co);
				copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel);

				sub_v3_v3v3(loc, co1, co2);

				sub_v3_v3v3(vec, vel1, vel2);
				
				inp = dot_v3v3(vec, vec);

				/* velocities not parallel */
				if (inp != 0.0f) {
					t = -dot_v3v3(loc, vec)/inp;
					/* cpa is not too far in the future so investigate further */
					if (t > 0.0f && t < t_min) {
						madd_v3_v3fl(co1, vel1, t);
						madd_v3_v3fl(co2, vel2, t);
						
						sub_v3_v3v3(vec, co2, co1);

						len = normalize_v3(vec);

						/* distance of cpa is close enough */
						if (len < 2.0f * val->personal_space * pa->size) {
							t_min = t;

							mul_v3_fl(vec, len_v3(vel1));
							mul_v3_fl(vec, (2.0f - t)/2.0f);
							sub_v3_v3v3(bbd->wanted_co, vel1, vec);
							bbd->wanted_speed = len_v3(bbd->wanted_co);
							ret = 1;
						}
					}
				}
			}

			if (ptn) { MEM_freeN(ptn); ptn=NULL; }
		}
	}


	if (ptn && nearest==0)
		MEM_freeN(ptn);

	return ret;
}
Exemplo n.º 7
0
static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
	BoidRuleFight *fbr = (BoidRuleFight*)rule;
	KDTreeNearest *ptn = NULL;
	ParticleTarget *pt;
	ParticleData *epars;
	ParticleData *enemy_pa = NULL;
	BoidParticle *bpa;
	/* friends & enemies */
	float closest_enemy[3] = {0.0f, 0.0f, 0.0f};
	float closest_dist = fbr->distance + 1.0f;
	float f_strength = 0.0f, e_strength = 0.0f;
	float health = 0.0f;
	int n, ret = 0;

	/* calculate own group strength */
	int neighbors = BLI_kdtree_range_search(
	            bbd->sim->psys->tree, pa->prev_state.co,
	            &ptn, fbr->distance);
	for (n=0; n<neighbors; n++) {
		bpa = bbd->sim->psys->particles[ptn[n].index].boid;
		health += bpa->data.health;
	}

	f_strength += bbd->part->boids->strength * health;

	if (ptn) { MEM_freeN(ptn); ptn=NULL; }

	/* add other friendlies and calculate enemy strength and find closest enemy */
	for (pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
		ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
		if (epsys) {
			epars = epsys->particles;

			neighbors = BLI_kdtree_range_search(
			        epsys->tree, pa->prev_state.co,
			        &ptn, fbr->distance);
			
			health = 0.0f;

			for (n=0; n<neighbors; n++) {
				bpa = epars[ptn[n].index].boid;
				health += bpa->data.health;

				if (n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
					copy_v3_v3(closest_enemy, ptn[n].co);
					closest_dist = ptn[n].dist;
					enemy_pa = epars + ptn[n].index;
				}
			}
			if (pt->mode==PTARGET_MODE_ENEMY)
				e_strength += epsys->part->boids->strength * health;
			else if (pt->mode==PTARGET_MODE_FRIEND)
				f_strength += epsys->part->boids->strength * health;

			if (ptn) { MEM_freeN(ptn); ptn=NULL; }
		}
	}
	/* decide action if enemy presence found */
	if (e_strength > 0.0f) {
		sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);

		/* attack if in range */
		if (closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
			float damage = BLI_rng_get_float(bbd->rng);
			float enemy_dir[3];

			normalize_v3_v3(enemy_dir, bbd->wanted_co);

			/* fight mode */
			bbd->wanted_speed = 0.0f;

			/* must face enemy to fight */
			if (dot_v3v3(pa->prev_state.ave, enemy_dir)>0.5f) {
				bpa = enemy_pa->boid;
				bpa->data.health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy);
			}
		}
		else {
			/* approach mode */
			bbd->wanted_speed = val->max_speed;
		}

		/* check if boid doesn't want to fight */
		bpa = pa->boid;
		if (bpa->data.health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) {
			/* decide to flee */
			if (closest_dist < fbr->flee_distance * fbr->distance) {
				negate_v3(bbd->wanted_co);
				bbd->wanted_speed = val->max_speed;
			}
			else { /* wait for better odds */
				bbd->wanted_speed = 0.0f;
			}
		}

		ret = 1;
	}

	return ret;
}
Exemplo n.º 8
0
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
                       GPUTexture *tex, float min[3], float max[3],
                       int res[3], float dx, float UNUSED(base_scale), float viewnormal[3],
                       GPUTexture *tex_shadow, GPUTexture *tex_flame)
{
	int i, j, k, n, good_index;
	float d /*, d0 */ /* UNUSED */, dd, ds;
	float *points = NULL;
	int numpoints = 0;
	float cor[3] = {1.0f, 1.0f, 1.0f};
	int gl_depth = 0, gl_blend = 0;

	/* draw slices of smoke is adapted from c++ code authored
	 * by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */
	float cv[][3] = {
		{1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
		{1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
	};

	/* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */
	float edges[12][2][3] = {
		{{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},

		{{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},

		{{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
	};

	unsigned char *spec_data;
	float *spec_pixels;
	GPUTexture *tex_spec;

	/* Fragment program to calculate the view3d of smoke */
	/* using 4 textures, density, shadow, flame and flame spectrum */
	const char *shader_basic =
	        "!!ARBfp1.0\n"
	        "PARAM dx = program.local[0];\n"
	        "PARAM darkness = program.local[1];\n"
	        "PARAM render = program.local[2];\n"
	        "PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
	        "TEMP temp, shadow, flame, spec, value;\n"
	        "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
	        "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
	        "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
	        "TEX spec, flame.r, texture[3], 1D;\n"
	        /* calculate shading factor from density */
	        "MUL value.r, temp.a, darkness.a;\n"
	        "MUL value.r, value.r, dx.r;\n"
	        "MUL value.r, value.r, f.r;\n"
	        "EX2 temp, -value.r;\n"
	        /* alpha */
	        "SUB temp.a, 1.0, temp.r;\n"
	        /* shade colors */
	        "MUL temp.r, temp.r, shadow.r;\n"
	        "MUL temp.g, temp.g, shadow.r;\n"
	        "MUL temp.b, temp.b, shadow.r;\n"
	        "MUL temp.r, temp.r, darkness.r;\n"
	        "MUL temp.g, temp.g, darkness.g;\n"
	        "MUL temp.b, temp.b, darkness.b;\n"
	        /* for now this just replace smoke shading if rendering fire */
	        "CMP result.color, render.r, temp, spec;\n"
	        "END\n";

	/* color shader */
	const char *shader_color =
	        "!!ARBfp1.0\n"
	        "PARAM dx = program.local[0];\n"
	        "PARAM darkness = program.local[1];\n"
	        "PARAM render = program.local[2];\n"
	        "PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};\n"
	        "TEMP temp, shadow, flame, spec, value;\n"
	        "TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
	        "TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
	        "TEX flame, fragment.texcoord[0], texture[2], 3D;\n"
	        "TEX spec, flame.r, texture[3], 1D;\n"
	        /* unpremultiply volume texture */
	        "RCP value.r, temp.a;\n"
	        "MUL temp.r, temp.r, value.r;\n"
	        "MUL temp.g, temp.g, value.r;\n"
	        "MUL temp.b, temp.b, value.r;\n"
	        /* calculate shading factor from density */
	        "MUL value.r, temp.a, darkness.a;\n"
	        "MUL value.r, value.r, dx.r;\n"
	        "MUL value.r, value.r, f.r;\n"
	        "EX2 value.r, -value.r;\n"
	        /* alpha */
	        "SUB temp.a, 1.0, value.r;\n"
	        /* shade colors */
	        "MUL temp.r, temp.r, shadow.r;\n"
	        "MUL temp.g, temp.g, shadow.r;\n"
	        "MUL temp.b, temp.b, shadow.r;\n"
	        "MUL temp.r, temp.r, value.r;\n"
	        "MUL temp.g, temp.g, value.r;\n"
	        "MUL temp.b, temp.b, value.r;\n"
	        /* for now this just replace smoke shading if rendering fire */
	        "CMP result.color, render.r, temp, spec;\n"
	        "END\n";

	GLuint prog;

	
	float size[3];

	if (!tex) {
		printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
		return;
	}

#ifdef DEBUG_DRAW_TIME
	TIMEIT_START(draw);
#endif

	/* generate flame spectrum texture */
	#define SPEC_WIDTH 256
	#define FIRE_THRESH 7
	#define MAX_FIRE_ALPHA 0.06f
	#define FULL_ON_FIRE 100
	spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char));
	flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000);
	spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float));
	for (i = 0; i < 16; i++) {
		for (j = 0; j < 16; j++) {
			for (k = 0; k < SPEC_WIDTH; k++) {
				int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
				if (k >= FIRE_THRESH) {
					spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f;
					spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f;
					spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f;
					spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
					        (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
				}
				else {
					spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f;
				}
			}
		}
	}

	tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);

	sub_v3_v3v3(size, max, min);

	/* maxx, maxy, maxz */
	cv[0][0] = max[0];
	cv[0][1] = max[1];
	cv[0][2] = max[2];
	/* minx, maxy, maxz */
	cv[1][0] = min[0];
	cv[1][1] = max[1];
	cv[1][2] = max[2];
	/* minx, miny, maxz */
	cv[2][0] = min[0];
	cv[2][1] = min[1];
	cv[2][2] = max[2];
	/* maxx, miny, maxz */
	cv[3][0] = max[0];
	cv[3][1] = min[1];
	cv[3][2] = max[2];

	/* maxx, maxy, minz */
	cv[4][0] = max[0];
	cv[4][1] = max[1];
	cv[4][2] = min[2];
	/* minx, maxy, minz */
	cv[5][0] = min[0];
	cv[5][1] = max[1];
	cv[5][2] = min[2];
	/* minx, miny, minz */
	cv[6][0] = min[0];
	cv[6][1] = min[1];
	cv[6][2] = min[2];
	/* maxx, miny, minz */
	cv[7][0] = max[0];
	cv[7][1] = min[1];
	cv[7][2] = min[2];

	copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */
	copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */
	copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */

	copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */
	copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */
	copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */

	copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */
	copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */
	copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */
	copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */

	// printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
	// printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);

	edges[0][1][2] = size[2];
	edges[1][1][2] = size[2];
	edges[2][1][2] = size[2];
	edges[3][1][2] = size[2];

	edges[4][1][1] = size[1];
	edges[5][1][1] = size[1];
	edges[6][1][1] = size[1];
	edges[7][1][1] = size[1];

	edges[8][1][0] = size[0];
	edges[9][1][0] = size[0];
	edges[10][1][0] = size[0];
	edges[11][1][0] = size[0];

	glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
	glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);

	glDepthMask(GL_FALSE);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);

	/* find cube vertex that is closest to the viewer */
	for (i = 0; i < 8; i++) {
		float x, y, z;

		x = cv[i][0] - viewnormal[0] * size[0] * 0.5f;
		y = cv[i][1] - viewnormal[1] * size[1] * 0.5f;
		z = cv[i][2] - viewnormal[2] * size[2] * 0.5f;

		if ((x >= min[0]) && (x <= max[0]) &&
		    (y >= min[1]) && (y <= max[1]) &&
		    (z >= min[2]) && (z <= max[2]))
		{
			break;
		}
	}

	if (i >= 8) {
		/* fallback, avoid using buffer over-run */
		i = 0;
	}

	// printf("i: %d\n", i);
	// printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);

	if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program")) {
		glEnable(GL_FRAGMENT_PROGRAM_ARB);
		glGenProgramsARB(1, &prog);

		glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
		/* set shader */
		if (sds->active_fields & SM_ACTIVE_COLORS)
			glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_color), shader_color);
		else
			glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(shader_basic), shader_basic);

		/* cell spacing */
		glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
		/* custom parameter for smoke style (higher = thicker) */
		if (sds->active_fields & SM_ACTIVE_COLORS)
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 1.0, 1.0, 1.0, 10.0);
		else
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
	}
	else
		printf("Your gfx card does not support 3D View smoke drawing.\n");

	GPU_texture_bind(tex, 0);
	if (tex_shadow)
		GPU_texture_bind(tex_shadow, 1);
	else
		printf("No volume shadow\n");

	if (tex_flame) {
		GPU_texture_bind(tex_flame, 2);
		GPU_texture_bind(tex_spec, 3);
	}

	if (!GPU_non_power_of_two_support()) {
		cor[0] = (float)res[0] / (float)power_of_2_max_i(res[0]);
		cor[1] = (float)res[1] / (float)power_of_2_max_i(res[1]);
		cor[2] = (float)res[2] / (float)power_of_2_max_i(res[2]);
	}

	/* our slices are defined by the plane equation a*x + b*y +c*z + d = 0
	 * (a,b,c), the plane normal, are given by viewdir
	 * d is the parameter along the view direction. the first d is given by
	 * inserting previously found vertex into the plane equation */

	/* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
	ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]);
	dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f;
	n = 0;
	good_index = i;

	// printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);

	points = MEM_callocN(sizeof(float) * 12 * 3, "smoke_points_preview");

	while (1) {
		float p0[3];
		float tmp_point[3], tmp_point2[3];

		if (dd * (float)n > ds)
			break;

		copy_v3_v3(tmp_point, viewnormal);
		mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n));
		add_v3_v3v3(tmp_point2, cv[good_index], tmp_point);
		d = dot_v3v3(tmp_point2, viewnormal);

		// printf("my d: %f\n", d);

		/* intersect_edges returns the intersection points of all cube edges with
		 * the given plane that lie within the cube */
		numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);

		// printf("points: %d\n", numpoints);

		if (numpoints > 2) {
			copy_v3_v3(p0, points);

			/* sort points to get a convex polygon */
			for (i = 1; i < numpoints - 1; i++) {
				for (j = i + 1; j < numpoints; j++) {
					if (!convex(p0, viewnormal, &points[j * 3], &points[i * 3])) {
						float tmp2[3];
						copy_v3_v3(tmp2, &points[j * 3]);
						copy_v3_v3(&points[j * 3], &points[i * 3]);
						copy_v3_v3(&points[i * 3], tmp2);
					}
				}
			}

			/* render fire slice */
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, 1.0, 0.0, 0.0, 0.0);
			glBegin(GL_POLYGON);
			glColor3f(1.0, 1.0, 1.0);
			for (i = 0; i < numpoints; i++) {
				glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
				             (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
				             (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
				glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]),
				           points[i * 3 + 1] / fabsf(ob->size[1]),
				           points[i * 3 + 2] / fabsf(ob->size[2]));
			}
			glEnd();

			/* render smoke slice */
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, -1.0, 0.0, 0.0, 0.0);
			glBegin(GL_POLYGON);
			glColor3f(1.0, 1.0, 1.0);
			for (i = 0; i < numpoints; i++) {
				glTexCoord3d((points[i * 3 + 0] - min[0]) * cor[0] / size[0],
				             (points[i * 3 + 1] - min[1]) * cor[1] / size[1],
				             (points[i * 3 + 2] - min[2]) * cor[2] / size[2]);
				glVertex3f(points[i * 3 + 0] / fabsf(ob->size[0]),
				           points[i * 3 + 1] / fabsf(ob->size[1]),
				           points[i * 3 + 2] / fabsf(ob->size[2]));
			}
			glEnd();
		}
		n++;
	}

#ifdef DEBUG_DRAW_TIME
	printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
	TIMEIT_END(draw);
#endif

	if (tex_shadow)
		GPU_texture_unbind(tex_shadow);
	GPU_texture_unbind(tex);
	if (tex_flame) {
		GPU_texture_unbind(tex_flame);
		GPU_texture_unbind(tex_spec);
	}
	GPU_texture_free(tex_spec);

	free(spec_data);
	free(spec_pixels);

	if (GLEW_ARB_fragment_program) {
		glDisable(GL_FRAGMENT_PROGRAM_ARB);
		glDeleteProgramsARB(1, &prog);
	}


	MEM_freeN(points);

	if (!gl_blend) {
		glDisable(GL_BLEND);
	}

	if (gl_depth) {
		glEnable(GL_DEPTH_TEST);
		glDepthMask(GL_TRUE);
	}
}
Exemplo n.º 9
0
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
{
	ViewContext vc;
	EditVert *eve;
	float min[3], max[3];
	int done= 0;
	short use_proj;

	em_setup_viewcontext(C, &vc);

	use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) &&	(vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE);
	
	invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); 
	
	INIT_MINMAX(min, max);
	
	for(eve= vc.em->verts.first; eve; eve= eve->next) {
		if(eve->f & SELECT) {
			DO_MINMAX(eve->co, min, max);
			done= 1;
		}
	}

	/* call extrude? */
	if(done) {
		const short rot_src= RNA_boolean_get(op->ptr, "rotate_source");
		EditEdge *eed;
		float vec[3], cent[3], mat[3][3];
		float nor[3]= {0.0, 0.0, 0.0};
		
		/* 2D normal calc */
		float mval_f[2];

		mval_f[0]= (float)event->mval[0];
		mval_f[1]= (float)event->mval[1];

		done= 0;

		/* calculate the normal for selected edges */
		for(eed= vc.em->edges.first; eed; eed= eed->next) {
			if(eed->f & SELECT) {
				float co1[3], co2[3];
				mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co);
				mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co);
				project_float_noclip(vc.ar, co1, co1);
				project_float_noclip(vc.ar, co2, co2);
				
				/* 2D rotate by 90d while adding.
				 *  (x, y) = (y, -x)
				 *
				 * accumulate the screenspace normal in 2D,
				 * with screenspace edge length weighting the result. */
				if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
					nor[0] +=  (co1[1] - co2[1]);
					nor[1] += -(co1[0] - co2[0]);
				}
				else {
					nor[0] +=  (co2[1] - co1[1]);
					nor[1] += -(co2[0] - co1[0]);
				}
				done= 1;
			}
		}

		if(done) {
			float view_vec[3], cross[3];

			/* convert the 2D nomal into 3D */
			mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
			mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
			
			/* correct the normal to be aligned on the view plane */
			copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
			mul_mat3_m4_v3(vc.obedit->imat, view_vec);
			cross_v3_v3v3(cross, nor, view_vec);
			cross_v3_v3v3(nor, view_vec, cross);
			normalize_v3(nor);
		}
		
		/* center */
		mid_v3_v3v3(cent, min, max);
		copy_v3_v3(min, cent);
		
		mul_m4_v3(vc.obedit->obmat, min);	// view space
		view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
		mul_m4_v3(vc.obedit->imat, min); // back in object space
		
		sub_v3_v3(min, cent);
		
		/* calculate rotation */
		unit_m3(mat);
		if(done) {
			float dot;
			
			copy_v3_v3(vec, min);
			normalize_v3(vec);
			dot= dot_v3v3(vec, nor);

			if( fabs(dot)<0.999) {
				float cross[3], si, q1[4];
				
				cross_v3_v3v3(cross, nor, vec);
				normalize_v3(cross);
				dot= 0.5f*saacos(dot);
				
				/* halve the rotation if its applied twice */
				if(rot_src) dot *= 0.5f;
				
				si= (float)sin(dot);
				q1[0]= (float)cos(dot);
				q1[1]= cross[0]*si;
				q1[2]= cross[1]*si;
				q1[3]= cross[2]*si;				
				quat_to_mat3( mat,q1);
			}
		}
		
		if(rot_src) {
			rotateflag(vc.em, SELECT, cent, mat);
			/* also project the source, for retopo workflow */
			if(use_proj)
				EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
		}
		
		extrudeflag(vc.obedit, vc.em, SELECT, nor, 0);
		rotateflag(vc.em, SELECT, cent, mat);
		translateflag(vc.em, SELECT, min);
		
		recalc_editnormals(vc.em);
	}
	else if(vc.em->selectmode & SCE_SELECT_VERTEX) {

		float imat[4][4];
		const float *curs= give_cursor(vc.scene, vc.v3d);
		
		copy_v3_v3(min, curs);
		view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);

		eve= addvertlist(vc.em, 0, NULL);

		invert_m4_m4(imat, vc.obedit->obmat);
		mul_v3_m4v3(eve->co, imat, min);
		
		eve->f= SELECT;
	}

	if(use_proj)
		EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);

	WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); 
	DAG_id_tag_update(vc.obedit->data, 0);
	
	return OPERATOR_FINISHED;
}
Exemplo n.º 10
0
MINLINE float len_v3(const float a[3])
{
	return sqrtf(dot_v3v3(a, a));
}
static void rotateDifferentialCoordinates(LaplacianSystem *sys)
{
	float alpha, beta, gamma;
	float pj[3], ni[3], di[3];
	float uij[3], dun[3], e2[3], pi[3], fni[3], vn[4][3];
	int i, j, lvin, num_fni, k, fi;
	int *fidn;

	for (i = 0; i < sys->total_verts; i++) {
		copy_v3_v3(pi, sys->co[i]);
		copy_v3_v3(ni, sys->no[i]);
		k = sys->unit_verts[i];
		copy_v3_v3(pj, sys->co[k]);
		sub_v3_v3v3(uij, pj, pi);
		mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
		sub_v3_v3(uij, dun);
		normalize_v3(uij);
		cross_v3_v3v3(e2, ni, uij);
		copy_v3_v3(di, sys->delta[i]);
		alpha = dot_v3v3(ni, di);
		beta = dot_v3v3(uij, di);
		gamma = dot_v3v3(e2, di);

		pi[0] = nlGetVariable(0, i);
		pi[1] = nlGetVariable(1, i);
		pi[2] = nlGetVariable(2, i);
		zero_v3(ni);
		num_fni = 0;
		num_fni = sys->ringf_map[i].count;
		for (fi = 0; fi < num_fni; fi++) {
			const unsigned int *vin;
			fidn = sys->ringf_map[i].indices;
			vin = sys->faces[fidn[fi]];
			lvin = vin[3] ? 4 : 3;
			for (j = 0; j < lvin; j++) {
				vn[j][0] = nlGetVariable(0, vin[j]);
				vn[j][1] = nlGetVariable(1, vin[j]);
				vn[j][2] = nlGetVariable(2, vin[j]);
				if (vin[j] == sys->unit_verts[i]) {
					copy_v3_v3(pj, vn[j]);
				}
			}

			if (lvin == 3) {
				normal_tri_v3(fni, vn[0], vn[1], vn[2]);
			}
			else if (lvin == 4) {
				normal_quad_v3(fni, vn[0], vn[1], vn[2], vn[3]);
			}
			add_v3_v3(ni, fni);
		}

		normalize_v3(ni);
		sub_v3_v3v3(uij, pj, pi);
		mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
		sub_v3_v3(uij, dun);
		normalize_v3(uij);
		cross_v3_v3v3(e2, ni, uij);
		fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0];
		fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1];
		fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2];

		if (len_squared_v3(fni) > FLT_EPSILON) {
			nlRightHandSideSet(0, i, fni[0]);
			nlRightHandSideSet(1, i, fni[1]);
			nlRightHandSideSet(2, i, fni[2]);
		}
		else {
			nlRightHandSideSet(0, i, sys->delta[i][0]);
			nlRightHandSideSet(1, i, sys->delta[i][1]);
			nlRightHandSideSet(2, i, sys->delta[i][2]);
		}
	}
}
Exemplo n.º 12
0
/**
 * AtmospherePixleShader:
 * this function apply atmosphere effect on a pixle color `rgb' at distance `s'
 * parameters:
 * sunSky, contains information about sun parameters and user values
 * view, is camera view vector
 * s, is distance 
 * rgb, contains rendered color value for a pixle
 * */
void AtmospherePixleShader( struct SunSky* sunSky, float view[3], float s, float rgb[3])
{
	float costheta;
	float Phase_1;
	float Phase_2;
	float sunColor[3];
	
	float E[3];
	float E1[3];
	
	
	float I[3];
	float fTemp;
	float vTemp1[3], vTemp2[3];

	float sunDirection[3];
	
	s *= sunSky->atm_DistanceMultiplier;
	
	sunDirection[0] = sunSky->toSun[0];
	sunDirection[1] = sunSky->toSun[1];
	sunDirection[2] = sunSky->toSun[2];
	
	costheta = dot_v3v3(view, sunDirection); // cos(theta)
	Phase_1 = 1 + (costheta * costheta); // Phase_1
	
	vec3opf(sunSky->atm_BetaRay, sunSky->atm_BetaRay, *, sunSky->atm_BetaRayMultiplier);
	vec3opf(sunSky->atm_BetaMie, sunSky->atm_BetaMie, *, sunSky->atm_BetaMieMultiplier);
	vec3opv(sunSky->atm_BetaRM, sunSky->atm_BetaRay, +, sunSky->atm_BetaMie);
	
	//e^(-(beta_1 + beta_2) * s) = E1
	vec3opf(E1, sunSky->atm_BetaRM, *, -s/(float)M_LN2);
	E1[0] = exp(E1[0]);
	E1[1] = exp(E1[1]);
	E1[2] = exp(E1[2]);

	copy_v3_v3(E, E1);
		
	//Phase2(theta) = (1-g^2)/(1+g-2g*cos(theta))^(3/2)
	fTemp = 1 + sunSky->atm_HGg - 2 * sunSky->atm_HGg * costheta;
	fTemp = fTemp * sqrtf(fTemp);
	Phase_2 = (1 - sunSky->atm_HGg * sunSky->atm_HGg)/fTemp;
	
	vec3opf(vTemp1, sunSky->atm_BetaDashRay, *, Phase_1);
	vec3opf(vTemp2, sunSky->atm_BetaDashMie, *, Phase_2);	

	vec3opv(vTemp1, vTemp1, +, vTemp2);
	fopvec3(vTemp2, 1.0f, -, E1);
	vec3opv(vTemp1, vTemp1, *, vTemp2);

	fopvec3(vTemp2, 1.0f, / , sunSky->atm_BetaRM);

	vec3opv(I, vTemp1, *, vTemp2);
		
	vec3opf(I, I, *, sunSky->atm_InscatteringMultiplier);
	vec3opf(E, E, *, sunSky->atm_ExtinctionMultiplier);
		
	//scale to color sun
	ComputeAttenuatedSunlight(sunSky->theta, sunSky->turbidity, sunColor);
	vec3opv(E, E, *, sunColor);

	vec3opf(I, I, *, sunSky->atm_SunIntensity);

	vec3opv(rgb, rgb, *, E);
	vec3opv(rgb, rgb, +, I);
}
Exemplo n.º 13
0
/* only valid for perspective cameras */
bool BKE_camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3])
{
	float shift[2];
	float plane_tx[4][3];
	float rot_obmat[3][3];
	const float zero[3] = {0, 0, 0};
	CameraViewFrameData data_cb;

	unsigned int i;

	BKE_camera_view_frame(scene, camera_ob->data, data_cb.frame_tx);

	copy_m3_m4(rot_obmat, camera_ob->obmat);
	normalize_m3(rot_obmat);

	for (i = 0; i < 4; i++) {
		/* normalize so Z is always 1.0f*/
		mul_v3_fl(data_cb.frame_tx[i], 1.0f / data_cb.frame_tx[i][2]);
	}

	/* get the shift back out of the frame */
	shift[0] = (data_cb.frame_tx[0][0] +
	            data_cb.frame_tx[1][0] +
	            data_cb.frame_tx[2][0] +
	            data_cb.frame_tx[3][0]) / 4.0f;
	shift[1] = (data_cb.frame_tx[0][1] +
	            data_cb.frame_tx[1][1] +
	            data_cb.frame_tx[2][1] +
	            data_cb.frame_tx[3][1]) / 4.0f;

	for (i = 0; i < 4; i++) {
		mul_m3_v3(rot_obmat, data_cb.frame_tx[i]);
	}

	for (i = 0; i < 4; i++) {
		normal_tri_v3(data_cb.normal_tx[i], zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]);
		plane_from_point_normal_v3(data_cb.plane_tx[i], data_cb.frame_tx[i], data_cb.normal_tx[i]);
	}

	/* initialize callback data */
	copy_v4_fl(data_cb.dist_vals_sq, FLT_MAX);
	data_cb.tot = 0;
	/* run callback on all visible points */
	BKE_scene_foreach_display_point(scene, v3d, BA_SELECT,
	                                camera_to_frame_view_cb, &data_cb);

	if (data_cb.tot <= 1) {
		return false;
	}
	else {
		float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3];
		float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3];

		float plane_isect_pt_1[3], plane_isect_pt_2[3];

		/* apply the dist-from-plane's to the transformed plane points */
		for (i = 0; i < 4; i++) {
			mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], sqrtf_signed(data_cb.dist_vals_sq[i]));
		}

		if ((!isect_plane_plane_v3(plane_isect_1, plane_isect_1_no,
		                           plane_tx[0], data_cb.normal_tx[0],
		                           plane_tx[2], data_cb.normal_tx[2])) ||
		    (!isect_plane_plane_v3(plane_isect_2, plane_isect_2_no,
		                           plane_tx[1], data_cb.normal_tx[1],
		                           plane_tx[3], data_cb.normal_tx[3])))
		{
			return false;
		}

		add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
		add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);

		if (isect_line_line_v3(plane_isect_1, plane_isect_1_other,
		                       plane_isect_2, plane_isect_2_other,
		                       plane_isect_pt_1, plane_isect_pt_2) == 0)
		{
			return false;
		}
		else {
			float cam_plane_no[3] = {0.0f, 0.0f, -1.0f};
			float plane_isect_delta[3];
			float plane_isect_delta_len;

			mul_m3_v3(rot_obmat, cam_plane_no);

			sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1);
			plane_isect_delta_len = len_v3(plane_isect_delta);

			if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) {
				copy_v3_v3(r_co, plane_isect_pt_1);

				/* offset shift */
				normalize_v3(plane_isect_1_no);
				madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len);
			}
			else {
				copy_v3_v3(r_co, plane_isect_pt_2);

				/* offset shift */
				normalize_v3(plane_isect_2_no);
				madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len);
			}


			return true;
		}
	}
}
float IMB_colormanagement_get_luminance(const float rgb[3])
{
	return dot_v3v3(imbuf_luma_coefficients, rgb);
}
Exemplo n.º 15
0
MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
{
    float co1[3], co2[3], co3[3], co4[3];
    float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1;
    int quad;

    quad= RE_rayface_isQuad(face);

    copy_v3_v3(co1, face->v1);
    copy_v3_v3(co2, face->v2);
    copy_v3_v3(co3, face->v3);

    negate_v3_v3(r, dir); /* note, different than above function */

    /* intersect triangle */
    sub_v3_v3v3(t0, co3, co2);
    sub_v3_v3v3(t1, co3, co1);

    cross_v3_v3v3(x, r, t1);
    divdet= dot_v3v3(t0, x);

    sub_v3_v3v3(m, start, co3);
    det1= dot_v3v3(m, x);

    if(divdet != 0.0f) {
        divdet= 1.0f/divdet;
        v= det1*divdet;

        if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
            float cros[3];

            cross_v3_v3v3(cros, m, t0);
            u= divdet*dot_v3v3(cros, r);

            if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON))
                return 1;
        }
    }

    /* intersect second triangle in quad */
    if(quad) {
        copy_v3_v3(co4, face->v4);
        sub_v3_v3v3(t0, co3, co4);
        divdet= dot_v3v3(t0, x);

        if(divdet != 0.0f) {
            divdet= 1.0f/divdet;
            v = det1*divdet;

            if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
                float cros[3];

                cross_v3_v3v3(cros, m, t0);
                u= divdet*dot_v3v3(cros, r);

                if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON))
                    return 2;
            }
        }
    }

    return 0;
}
Exemplo n.º 16
0
static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force)
{
	TexResult result[4];
	float tex_co[3], strength, force[3];
	float nabla = eff->pd->tex_nabla;
	int hasrgb;
	short mode = eff->pd->tex_mode;

	if (!eff->pd->tex)
		return;

	result[0].nor = result[1].nor = result[2].nor = result[3].nor = NULL;

	strength= eff->pd->f_strength * efd->falloff;

	copy_v3_v3(tex_co, point->loc);

	if (eff->pd->flag & PFIELD_TEX_2D) {
		float fac=-dot_v3v3(tex_co, efd->nor);
		madd_v3_v3fl(tex_co, efd->nor, fac);
	}

	if (eff->pd->flag & PFIELD_TEX_OBJECT) {
		mul_m4_v3(eff->ob->imat, tex_co);
	}

	hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, NULL);

	if (hasrgb && mode==PFIELD_TEX_RGB) {
		force[0] = (0.5f - result->tr) * strength;
		force[1] = (0.5f - result->tg) * strength;
		force[2] = (0.5f - result->tb) * strength;
	}
	else {
		strength/=nabla;

		tex_co[0] += nabla;
		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, NULL);

		tex_co[0] -= nabla;
		tex_co[1] += nabla;
		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, NULL);

		tex_co[1] -= nabla;
		tex_co[2] += nabla;
		multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, NULL);

		if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */
			/* generate intensity if texture only has rgb value */
			if (hasrgb & TEX_RGB) {
				int i;
				for (i=0; i<4; i++)
					result[i].tin = (1.0f / 3.0f) * (result[i].tr + result[i].tg + result[i].tb);
			}
			force[0] = (result[0].tin - result[1].tin) * strength;
			force[1] = (result[0].tin - result[2].tin) * strength;
			force[2] = (result[0].tin - result[3].tin) * strength;
		}
		else { /*PFIELD_TEX_CURL*/
			float dbdy, dgdz, drdz, dbdx, dgdx, drdy;

			dbdy = result[2].tb - result[0].tb;
			dgdz = result[3].tg - result[0].tg;
			drdz = result[3].tr - result[0].tr;
			dbdx = result[1].tb - result[0].tb;
			dgdx = result[1].tg - result[0].tg;
			drdy = result[2].tr - result[0].tr;

			force[0] = (dbdy - dgdz) * strength;
			force[1] = (drdz - dbdx) * strength;
			force[2] = (dgdx - drdy) * strength;
		}
	}

	if (eff->pd->flag & PFIELD_TEX_2D) {
		float fac = -dot_v3v3(force, efd->nor);
		madd_v3_v3fl(force, efd->nor, fac);
	}

	add_v3_v3(total_force, force);
}
Exemplo n.º 17
0
/* tries to realize the wanted velocity taking all constraints into account */
void boid_body(BoidBrainData *bbd, ParticleData *pa)
{
	BoidSettings *boids = bbd->part->boids;
	BoidParticle *bpa = pa->boid;
	BoidValues val;
	EffectedPoint epoint;
	float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
	float dvec[3], bvec[3];
	float new_dir[3], new_speed;
	float old_dir[3], old_speed;
	float wanted_dir[3];
	float q[4], mat[3][3]; /* rotation */
	float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
	float force[3] = {0.0f, 0.0f, 0.0f};
	float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;

	set_boid_values(&val, boids, pa);

	/* make sure there's something in new velocity, location & rotation */
	copy_particle_key(&pa->state, &pa->prev_state, 0);

	if (bbd->part->flag & PART_SIZEMASS)
		pa_mass*=pa->size;

	/* if boids can't fly they fall to the ground */
	if ((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim))
		bpa->data.mode = eBoidMode_Falling;

	if (bpa->data.mode == eBoidMode_Falling) {
		/* Falling boids are only effected by gravity. */
		acc[2] = bbd->sim->scene->physics_settings.gravity[2];
	}
	else {
		/* figure out acceleration */
		float landing_level = 2.0f;
		float level = landing_level + 1.0f;
		float new_vel[3];

		if (bpa->data.mode == eBoidMode_Liftoff) {
			bpa->data.mode = eBoidMode_InAir;
			bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
		}
		else if (bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
			/* auto-leveling & landing if close to ground */

			bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
			
			/* level = how many particle sizes above ground */
			level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f;

			landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;

			if (pa->prev_state.vel[2] < 0.0f) {
				if (level < 1.0f) {
					bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
					bbd->wanted_speed = 0.0f;
					bpa->data.mode = eBoidMode_Falling;
				}
				else if (level < landing_level) {
					bbd->wanted_speed *= (level - 1.0f)/landing_level;
					bbd->wanted_co[2] *= (level - 1.0f)/landing_level;
				}
			}
		}

		copy_v3_v3(old_dir, pa->prev_state.ave);
		new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);

		/* first check if we have valid direction we want to go towards */
		if (new_speed == 0.0f) {
			copy_v3_v3(new_dir, old_dir);
		}
		else {
			float old_dir2[2], wanted_dir2[2], nor[3], angle;
			copy_v2_v2(old_dir2, old_dir);
			normalize_v2(old_dir2);
			copy_v2_v2(wanted_dir2, wanted_dir);
			normalize_v2(wanted_dir2);

			/* choose random direction to turn if wanted velocity */
			/* is directly behind regardless of z-coordinate */
			if (dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
				wanted_dir[0] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
				wanted_dir[1] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
				wanted_dir[2] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng));
				normalize_v3(wanted_dir);
			}

			/* constrain direction with maximum angular velocity */
			angle = saacos(dot_v3v3(old_dir, wanted_dir));
			angle = min_ff(angle, val.max_ave);

			cross_v3_v3v3(nor, old_dir, wanted_dir);
			axis_angle_to_quat(q, nor, angle);
			copy_v3_v3(new_dir, old_dir);
			mul_qt_v3(q, new_dir);
			normalize_v3(new_dir);

			/* save direction in case resulting velocity too small */
			axis_angle_to_quat(q, nor, angle*dtime);
			copy_v3_v3(pa->state.ave, old_dir);
			mul_qt_v3(q, pa->state.ave);
			normalize_v3(pa->state.ave);
		}

		/* constrain speed with maximum acceleration */
		old_speed = len_v3(pa->prev_state.vel);
		
		if (bbd->wanted_speed < old_speed)
			new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
		else
			new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);

		/* combine direction and speed */
		copy_v3_v3(new_vel, new_dir);
		mul_v3_fl(new_vel, new_speed);

		/* maintain minimum flying velocity if not landing */
		if (level >= landing_level) {
			float len2 = dot_v2v2(new_vel, new_vel);
			float root;

			len2 = MAX2(len2, val.min_speed*val.min_speed);
			root = sasqrt(new_speed*new_speed - len2);

			new_vel[2] = new_vel[2] < 0.0f ? -root : root;

			normalize_v2(new_vel);
			mul_v2_fl(new_vel, sasqrt(len2));
		}

		/* finally constrain speed to max speed */
		new_speed = normalize_v3(new_vel);
		mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed));

		/* get acceleration from difference of velocities */
		sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);

		/* break acceleration to components */
		project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
		sub_v3_v3v3(nor_acc, acc, tan_acc);
	}

	/* account for effectors */
	pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
	pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);

	if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
		float length = normalize_v3(force);

		length = MAX2(0.0f, length - boids->land_stick_force);

		mul_v3_fl(force, length);
	}
	
	add_v3_v3(acc, force);

	/* store smoothed acceleration for nice banking etc. */
	madd_v3_v3fl(bpa->data.acc, acc, dtime);
	mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime));

	/* integrate new location & velocity */

	/* by regarding the acceleration as a force at this stage we*/
	/* can get better control allthough it's a bit unphysical	*/
	mul_v3_fl(acc, 1.0f/pa_mass);

	copy_v3_v3(dvec, acc);
	mul_v3_fl(dvec, dtime*dtime*0.5f);
	
	copy_v3_v3(bvec, pa->prev_state.vel);
	mul_v3_fl(bvec, dtime);
	add_v3_v3(dvec, bvec);
	add_v3_v3(pa->state.co, dvec);

	madd_v3_v3fl(pa->state.vel, acc, dtime);

	//if (bpa->data.mode != eBoidMode_InAir)
	bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);

	/* change modes, constrain movement & keep track of down vector */
	switch (bpa->data.mode) {
		case eBoidMode_InAir:
		{
			float grav[3];

			grav[0] = 0.0f;
			grav[1] = 0.0f;
			grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;

			/* don't take forward acceleration into account (better banking) */
			if (dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) {
				project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
				sub_v3_v3v3(dvec, bpa->data.acc, dvec);
			}
			else {
				copy_v3_v3(dvec, bpa->data.acc);
			}

			/* gather apparent gravity */
			madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
			normalize_v3(bpa->gravity);

			/* stick boid on goal when close enough */
			if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
				bpa->data.mode = eBoidMode_Climbing;
				bpa->ground = bbd->goal_ob;
				boid_find_ground(bbd, pa, ground_co, ground_nor);
				boid_climb(boids, pa, ground_co, ground_nor);
			}
			else if (pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
				/* land boid when below ground */
				if (boids->options & BOID_ALLOW_LAND) {
					pa->state.co[2] = ground_co[2] + pa->size * boids->height;
					pa->state.vel[2] = 0.0f;
					bpa->data.mode = eBoidMode_OnLand;
				}
				/* fly above ground */
				else if (bpa->ground) {
					pa->state.co[2] = ground_co[2] + pa->size * boids->height;
					pa->state.vel[2] = 0.0f;
				}
			}
			break;
		}
		case eBoidMode_Falling:
		{
			float grav[3];

			grav[0] = 0.0f;
			grav[1] = 0.0f;
			grav[2] = bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;


			/* gather apparent gravity */
			madd_v3_v3fl(bpa->gravity, grav, dtime);
			normalize_v3(bpa->gravity);

			if (boids->options & BOID_ALLOW_LAND) {
				/* stick boid on goal when close enough */
				if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
					bpa->data.mode = eBoidMode_Climbing;
					bpa->ground = bbd->goal_ob;
					boid_find_ground(bbd, pa, ground_co, ground_nor);
					boid_climb(boids, pa, ground_co, ground_nor);
				}
				/* land boid when really near ground */
				else if (pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height) {
					pa->state.co[2] = ground_co[2] + pa->size * boids->height;
					pa->state.vel[2] = 0.0f;
					bpa->data.mode = eBoidMode_OnLand;
				}
				/* if we're falling, can fly and want to go upwards lets fly */
				else if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f)
					bpa->data.mode = eBoidMode_InAir;
			}
			else
				bpa->data.mode = eBoidMode_InAir;
			break;
		}
		case eBoidMode_Climbing:
		{
			boid_climb(boids, pa, ground_co, ground_nor);
			//float nor[3];
			//copy_v3_v3(nor, ground_nor);

			///* gather apparent gravity to r_ve */
			//madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
			//normalize_v3(pa->r_ve);

			///* raise boid it's size from surface */
			//mul_v3_fl(nor, pa->size * boids->height);
			//add_v3_v3v3(pa->state.co, ground_co, nor);

			///* remove normal component from velocity */
			//project_v3_v3v3(v, pa->state.vel, ground_nor);
			//sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
			break;
		}
		case eBoidMode_OnLand:
		{
			/* stick boid on goal when close enough */
			if (bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
				bpa->data.mode = eBoidMode_Climbing;
				bpa->ground = bbd->goal_ob;
				boid_find_ground(bbd, pa, ground_co, ground_nor);
				boid_climb(boids, pa, ground_co, ground_nor);
			}
			/* ground is too far away so boid falls */
			else if (pa->state.co[2]-ground_co[2] > 1.1f * pa->size * boids->height)
				bpa->data.mode = eBoidMode_Falling;
			else {
				/* constrain to surface */
				pa->state.co[2] = ground_co[2] + pa->size * boids->height;
				pa->state.vel[2] = 0.0f;
			}

			if (boids->banking > 0.0f) {
				float grav[3];
				/* Don't take gravity's strength in to account, */
				/* otherwise amount of banking is hard to control. */
				negate_v3_v3(grav, ground_nor);

				project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
				sub_v3_v3v3(dvec, bpa->data.acc, dvec);

				/* gather apparent gravity */
				madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
				normalize_v3(bpa->gravity);
			}
			else {
				/* gather negative surface normal */
				madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f);
				normalize_v3(bpa->gravity);
			}
			break;
		}
	}

	/* save direction to state.ave unless the boid is falling */
	/* (boids can't effect their direction when falling) */
	if (bpa->data.mode!=eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f*pa->size) {
		copy_v3_v3(pa->state.ave, pa->state.vel);
		pa->state.ave[2] *= bbd->part->boids->pitch;
		normalize_v3(pa->state.ave);
	}

	/* apply damping */
	if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing))
		mul_v3_fl(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac);

	/* calculate rotation matrix based on forward & down vectors */
	if (bpa->data.mode == eBoidMode_InAir) {
		copy_v3_v3(mat[0], pa->state.ave);

		project_v3_v3v3(dvec, bpa->gravity, pa->state.ave);
		sub_v3_v3v3(mat[2], bpa->gravity, dvec);
		normalize_v3(mat[2]);
	}
	else {
		project_v3_v3v3(dvec, pa->state.ave, bpa->gravity);
		sub_v3_v3v3(mat[0], pa->state.ave, dvec);
		normalize_v3(mat[0]);

		copy_v3_v3(mat[2], bpa->gravity);
	}
	negate_v3(mat[2]);
	cross_v3_v3v3(mat[1], mat[2], mat[0]);
	
	/* apply rotation */
	mat3_to_quat_is_ok(q, mat);
	copy_qt_qt(pa->state.rot, q);
}
Exemplo n.º 18
0
/**
 * This function populates pixel_array and returns TRUE if things are correct
 */
static bool cast_ray_highpoly(
        BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly,
        const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly,
        const float du_dx, const float du_dy, const float dv_dx, const float dv_dy)
{
	int i;
	int primitive_id = -1;
	float uv[2];
	int hit_mesh = -1;
	float hit_distance = FLT_MAX;

	BVHTreeRayHit *hits;
	hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays");

	for (i = 0; i < tot_highpoly; i++) {
		float co_high[3], dir_high[3];

		hits[i].index = -1;
		/* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
		hits[i].dist = 10000.0f;

		/* transform the ray from the world space to the highpoly space */
		mul_v3_m4v3(co_high, highpoly[i].imat, co);

		/* rotates */
		mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir);
		normalize_v3(dir_high);

		/* cast ray */
		if (treeData[i].tree) {
			BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir_high, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]);
		}

		if (hits[i].index != -1) {
			/* cull backface */
			const float dot = dot_v3v3(dir_high, hits[i].no);
			if (dot < 0.0f) {
				float distance;
				float hit_world[3];

				/* distance comparison in world space */
				mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
				distance = len_squared_v3v3(hit_world, co);

				if (distance < hit_distance) {
					hit_mesh = i;
					hit_distance = distance;
				}
			}
		}
	}

	if (hit_mesh != -1) {
		calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv);
		pixel_array[pixel_id].primitive_id = primitive_id;
		pixel_array[pixel_id].object_id = hit_mesh;
		copy_v2_v2(pixel_array[pixel_id].uv, uv);

		/* the differentials are relative to the UV/image space, so the highpoly differentials
		 * are the same as the low poly differentials */
		pixel_array[pixel_id].du_dx = du_dx;
		pixel_array[pixel_id].du_dy = du_dy;
		pixel_array[pixel_id].dv_dx = dv_dx;
		pixel_array[pixel_id].dv_dy = dv_dy;
	}
	else {
		pixel_array[pixel_id].primitive_id = -1;
		pixel_array[pixel_id].object_id = -1;
	}

	MEM_freeN(hits);
	return hit_mesh != -1;
}
Exemplo n.º 19
0
static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
	BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule;
	float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
	float mul, len;
	int n = (flbr->queue_size <= 1) ? bbd->sim->psys->totpart : flbr->queue_size;
	int i, ret = 0, p = pa - bbd->sim->psys->particles;

	if (flbr->ob) {
		float vec2[3], t;

		/* first check we're not blocking the leader */
		sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
		mul_v3_fl(vec, 1.0f/bbd->timestep);

		sub_v3_v3v3(loc, pa->prev_state.co, flbr->oloc);

		mul = dot_v3v3(vec, vec);

		/* leader is not moving */
		if (mul < 0.01f) {
			len = len_v3(loc);
			/* too close to leader */
			if (len < 2.0f * val->personal_space * pa->size) {
				copy_v3_v3(bbd->wanted_co, loc);
				bbd->wanted_speed = val->max_speed;
				return 1;
			}
		}
		else {
			t = dot_v3v3(loc, vec)/mul;

			/* possible blocking of leader in near future */
			if (t > 0.0f && t < 3.0f) {
				copy_v3_v3(vec2, vec);
				mul_v3_fl(vec2, t);

				sub_v3_v3v3(vec2, loc, vec2);

				len = len_v3(vec2);

				if (len < 2.0f * val->personal_space * pa->size) {
					copy_v3_v3(bbd->wanted_co, vec2);
					bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
					return 1;
				}
			}
		}

		/* not blocking so try to follow leader */
		if (p && flbr->options & BRULE_LEADER_IN_LINE) {
			copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
			copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
		}
		else {
			copy_v3_v3(loc, flbr->oloc);
			sub_v3_v3v3(vec, flbr->loc, flbr->oloc);
			mul_v3_fl(vec, 1.0f/bbd->timestep);
		}
		
		/* fac is seconds behind leader */
		madd_v3_v3fl(loc, vec, -flbr->distance);

		sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
		bbd->wanted_speed = len_v3(bbd->wanted_co);
			
		ret = 1;
	}
	else if (p % n) {
		float vec2[3], t, t_min = 3.0f;

		/* first check we're not blocking any leaders */
		for (i = 0; i< bbd->sim->psys->totpart; i+=n) {
			copy_v3_v3(vec, bbd->sim->psys->particles[i].prev_state.vel);

			sub_v3_v3v3(loc, pa->prev_state.co, bbd->sim->psys->particles[i].prev_state.co);

			mul = dot_v3v3(vec, vec);

			/* leader is not moving */
			if (mul < 0.01f) {
				len = len_v3(loc);
				/* too close to leader */
				if (len < 2.0f * val->personal_space * pa->size) {
					copy_v3_v3(bbd->wanted_co, loc);
					bbd->wanted_speed = val->max_speed;
					return 1;
				}
			}
			else {
				t = dot_v3v3(loc, vec)/mul;

				/* possible blocking of leader in near future */
				if (t > 0.0f && t < t_min) {
					copy_v3_v3(vec2, vec);
					mul_v3_fl(vec2, t);

					sub_v3_v3v3(vec2, loc, vec2);

					len = len_v3(vec2);

					if (len < 2.0f * val->personal_space * pa->size) {
						t_min = t;
						copy_v3_v3(bbd->wanted_co, loc);
						bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f;
						ret = 1;
					}
				}
			}
		}

		if (ret) return 1;

		/* not blocking so try to follow leader */
		if (flbr->options & BRULE_LEADER_IN_LINE) {
			copy_v3_v3(vec, bbd->sim->psys->particles[p-1].prev_state.vel);
			copy_v3_v3(loc, bbd->sim->psys->particles[p-1].prev_state.co);
		}
		else {
			copy_v3_v3(vec, bbd->sim->psys->particles[p - p%n].prev_state.vel);
			copy_v3_v3(loc, bbd->sim->psys->particles[p - p%n].prev_state.co);
		}
		
		/* fac is seconds behind leader */
		madd_v3_v3fl(loc, vec, -flbr->distance);

		sub_v3_v3v3(bbd->wanted_co, loc, pa->prev_state.co);
		bbd->wanted_speed = len_v3(bbd->wanted_co);
		
		ret = 1;
	}

	return ret;
}
static void rotateDifferentialCoordinates(LaplacianSystem *sys)
{
	float alpha, beta, gamma;
	float pj[3], ni[3], di[3];
	float uij[3], dun[3], e2[3], pi[3], fni[3], vn[3][3];
	int i, j, num_fni, k, fi;
	int *fidn;

	for (i = 0; i < sys->total_verts; i++) {
		copy_v3_v3(pi, sys->co[i]);
		copy_v3_v3(ni, sys->no[i]);
		k = sys->unit_verts[i];
		copy_v3_v3(pj, sys->co[k]);
		sub_v3_v3v3(uij, pj, pi);
		mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
		sub_v3_v3(uij, dun);
		normalize_v3(uij);
		cross_v3_v3v3(e2, ni, uij);
		copy_v3_v3(di, sys->delta[i]);
		alpha = dot_v3v3(ni, di);
		beta = dot_v3v3(uij, di);
		gamma = dot_v3v3(e2, di);

		pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i);
		pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i);
		pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i);
		zero_v3(ni);
		num_fni = sys->ringf_map[i].count;
		for (fi = 0; fi < num_fni; fi++) {
			const unsigned int *vin;
			fidn = sys->ringf_map[i].indices;
			vin = sys->tris[fidn[fi]];
			for (j = 0; j < 3; j++) {
				vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]);
				vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]);
				vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]);
				if (vin[j] == sys->unit_verts[i]) {
					copy_v3_v3(pj, vn[j]);
				}
			}

			normal_tri_v3(fni, UNPACK3(vn));
			add_v3_v3(ni, fni);
		}

		normalize_v3(ni);
		sub_v3_v3v3(uij, pj, pi);
		mul_v3_v3fl(dun, ni, dot_v3v3(uij, ni));
		sub_v3_v3(uij, dun);
		normalize_v3(uij);
		cross_v3_v3v3(e2, ni, uij);
		fni[0] = alpha * ni[0] + beta * uij[0] + gamma * e2[0];
		fni[1] = alpha * ni[1] + beta * uij[1] + gamma * e2[1];
		fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2];

		if (len_squared_v3(fni) > FLT_EPSILON) {
			EIG_linear_solver_right_hand_side_add(sys->context, 0, i, fni[0]);
			EIG_linear_solver_right_hand_side_add(sys->context, 1, i, fni[1]);
			EIG_linear_solver_right_hand_side_add(sys->context, 2, i, fni[2]);
		}
		else {
			EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
			EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
			EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
		}
	}
}
Exemplo n.º 21
0
static void testRadialSymmetry(BGraph *graph, BNode *root_node, RadialArc *ring, int total, float axis[3], float limit, int group)
{
	const float limit_sq = limit * limit;
	int symmetric = 1;
	int i;
	
	/* sort ring by angle */
	for (i = 0; i < total - 1; i++) {
		float minAngle = FLT_MAX;
		int minIndex = -1;
		int j;

		for (j = i + 1; j < total; j++) {
			float angle = dot_v3v3(ring[i].n, ring[j].n);

			/* map negative values to 1..2 */
			if (angle < 0) {
				angle = 1 - angle;
			}

			if (angle < minAngle) {
				minIndex = j;
				minAngle = angle;
			}
		}

		/* swap if needed */
		if (minIndex != i + 1) {
			RadialArc tmp;
			tmp = ring[i + 1];
			ring[i + 1] = ring[minIndex];
			ring[minIndex] = tmp;
		}
	}

	for (i = 0; i < total && symmetric; i++) {
		BNode *node1, *node2;
		float tangent[3];
		float normal[3];
		float p[3];
		int j = (i + 1) % total; /* next arc in the circular list */

		add_v3_v3v3(tangent, ring[i].n, ring[j].n);
		cross_v3_v3v3(normal, tangent, axis);
		
		node1 = BLI_otherNode(ring[i].arc, root_node);
		node2 = BLI_otherNode(ring[j].arc, root_node);

		copy_v3_v3(p, node2->p);
		BLI_mirrorAlongAxis(p, root_node->p, normal);
		
		/* check if it's within limit before continuing */
		if (len_squared_v3v3(node1->p, p) > limit_sq) {
			symmetric = 0;
		}

	}

	if (symmetric) {
		/* mark node as symmetric physically */
		copy_v3_v3(root_node->symmetry_axis, axis);
		root_node->symmetry_flag |= SYM_PHYSICAL;
		root_node->symmetry_flag |= SYM_RADIAL;
		
		/* FLAG SYMMETRY GROUP */
		for (i = 0; i < total; i++) {
			ring[i].arc->symmetry_group = group;
			ring[i].arc->symmetry_flag = SYM_SIDE_RADIAL + i;
		}

		if (graph->radial_symmetry) {
			graph->radial_symmetry(root_node, ring, total);
		}
	}
}
Exemplo n.º 22
0
int BLI_edgefill_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedup, const float nor_proj[3])
{
	/*
	 * - fill works with its own lists, so create that first (no faces!)
	 * - for vertices, put in ->tmp.v the old pointer
	 * - struct elements xs en ys are not used here: don't hide stuff in it
	 * - edge flag ->f becomes 2 when it's a new edge
	 * - mode: & 1 is check for crossings, then create edges (TO DO )
	 * - returns number of triangle faces added.
	 */
	ListBase tempve, temped;
	ScanFillVert *eve;
	ScanFillEdge *eed, *nexted;
	PolyFill *pflist, *pf;
	float *min_xy_p, *max_xy_p;
	short a, c, poly = 0, ok = 0, toggle = 0;
	int totfaces = 0; /* total faces added */
	int co_x, co_y;

	/* reset variables */
	eve = sf_ctx->fillvertbase.first;
	a = 0;
	while (eve) {
		eve->f = 0;
		eve->poly_nr = 0;
		eve->h = 0;
		eve = eve->next;
		a += 1;
	}

	if (do_quad_tri_speedup && (a == 3)) {
		eve = sf_ctx->fillvertbase.first;

		addfillface(sf_ctx, eve, eve->next, eve->next->next);
		return 1;
	}
	else if (do_quad_tri_speedup && (a == 4)) {
		float vec1[3], vec2[3];

		eve = sf_ctx->fillvertbase.first;
		/* no need to check 'eve->next->next->next' is valid, already counted */
		/* use shortest diagonal for quad */
		sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
		sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);

		if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) {
			addfillface(sf_ctx, eve, eve->next, eve->next->next);
			addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve);
		}
		else {
			addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next);
			addfillface(sf_ctx, eve->next->next->next, eve, eve->next);
		}
		return 2;
	}

	/* first test vertices if they are in edges */
	/* including resetting of flags */
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		eed->poly_nr = 0;
		eed->v1->f = SF_VERT_UNKNOWN;
		eed->v2->f = SF_VERT_UNKNOWN;

		eed = eed->next;
	}

	eve = sf_ctx->fillvertbase.first;
	while (eve) {
		if (eve->f & SF_VERT_UNKNOWN) {
			ok = 1;
			break;
		}
		eve = eve->next;
	}

	if (ok == 0) {
		return 0;
	}
	else {
		float n[3];

		if (nor_proj) {
			copy_v3_v3(n, nor_proj);
		}
		else {
			/* define projection: with 'best' normal */
			/* Newell's Method */
			/* Similar code used elsewhere, but this checks for double ups
			 * which historically this function supports so better not change */
			float *v_prev;

			zero_v3(n);
			eve = sf_ctx->fillvertbase.last;
			v_prev = eve->co;

			for (eve = sf_ctx->fillvertbase.first; eve; eve = eve->next) {
				if (LIKELY(!compare_v3v3(v_prev, eve->co, SF_EPSILON))) {
					add_newell_cross_v3_v3v3(n, v_prev, eve->co);
					v_prev = eve->co;
				}
			}
		}

		if (UNLIKELY(normalize_v3(n) == 0.0f)) {
			return 0;
		}

		axis_dominant_v3(&co_x, &co_y, n);
	}


	/* STEP 1: COUNT POLYS */
	eve = sf_ctx->fillvertbase.first;
	while (eve) {
		eve->xy[0] = eve->co[co_x];
		eve->xy[1] = eve->co[co_y];

		/* get first vertex with no poly number */
		if (eve->poly_nr == 0) {
			poly++;
			/* now a sort of select connected */
			ok = 1;
			eve->poly_nr = poly;
			
			while (ok) {
				
				ok = 0;
				toggle++;
				if (toggle & 1) eed = sf_ctx->filledgebase.first;
				else eed = sf_ctx->filledgebase.last;

				while (eed) {
					if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) {
						eed->v1->poly_nr = poly;
						eed->poly_nr = poly;
						ok = 1;
					}
					else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) {
						eed->v2->poly_nr = poly;
						eed->poly_nr = poly;
						ok = 1;
					}
					else if (eed->poly_nr == 0) {
						if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) {
							eed->poly_nr = poly;
							ok = 1;
						}
					}
					if (toggle & 1) eed = eed->next;
					else eed = eed->prev;
				}
			}
		}
		eve = eve->next;
	}
	/* printf("amount of poly's: %d\n",poly); */

	/* STEP 2: remove loose edges and strings of edges */
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		if (eed->v1->h++ > 250) break;
		if (eed->v2->h++ > 250) break;
		eed = eed->next;
	}
	if (eed) {
		/* otherwise it's impossible to be sure you can clear vertices */
		callLocalErrorCallBack("No vertices with 250 edges allowed!");
		return 0;
	}
	
	/* does it only for vertices with ->h==1 */
	testvertexnearedge(sf_ctx);

	ok = 1;
	while (ok) {
		ok = 0;
		toggle++;
		if (toggle & 1) eed = sf_ctx->filledgebase.first;
		else eed = sf_ctx->filledgebase.last;
		while (eed) {
			if (toggle & 1) nexted = eed->next;
			else nexted = eed->prev;
			if (eed->v1->h == 1) {
				eed->v2->h--;
				BLI_remlink(&sf_ctx->fillvertbase, eed->v1);
				BLI_remlink(&sf_ctx->filledgebase, eed);
				ok = 1;
			}
			else if (eed->v2->h == 1) {
				eed->v1->h--;
				BLI_remlink(&sf_ctx->fillvertbase, eed->v2);
				BLI_remlink(&sf_ctx->filledgebase, eed);
				ok = 1;
			}
			eed = nexted;
		}
	}
	if (sf_ctx->filledgebase.first == 0) {
		/* printf("All edges removed\n"); */
		return 0;
	}


	/* CURRENT STATUS:
	 * - eve->f       :1= availalble in edges
	 * - eve->xs      :polynumber
	 * - eve->h       :amount of edges connected to vertex
	 * - eve->tmp.v   :store! original vertex number
	 * 
	 * - eed->f       :1= boundary edge (optionally set by caller)
	 * - eed->poly_nr :poly number
	 */


	/* STEP 3: MAKE POLYFILL STRUCT */
	pflist = (PolyFill *)MEM_callocN(poly * sizeof(PolyFill), "edgefill");
	pf = pflist;
	for (a = 1; a <= poly; a++) {
		pf->nr = a;
		pf->min_xy[0] = pf->min_xy[1] =  1.0e20;
		pf->max_xy[0] = pf->max_xy[1] = -1.0e20;
		pf++;
	}
	eed = sf_ctx->filledgebase.first;
	while (eed) {
		pflist[eed->poly_nr - 1].edges++;
		eed = eed->next;
	}

	eve = sf_ctx->fillvertbase.first;
	while (eve) {
		pflist[eve->poly_nr - 1].verts++;
		min_xy_p = pflist[eve->poly_nr - 1].min_xy;
		max_xy_p = pflist[eve->poly_nr - 1].max_xy;

		min_xy_p[0] = (min_xy_p[0]) < (eve->xy[0]) ? (min_xy_p[0]) : (eve->xy[0]);
		min_xy_p[1] = (min_xy_p[1]) < (eve->xy[1]) ? (min_xy_p[1]) : (eve->xy[1]);
		max_xy_p[0] = (max_xy_p[0]) > (eve->xy[0]) ? (max_xy_p[0]) : (eve->xy[0]);
		max_xy_p[1] = (max_xy_p[1]) > (eve->xy[1]) ? (max_xy_p[1]) : (eve->xy[1]);
		if (eve->h > 2) pflist[eve->poly_nr - 1].f = 1;

		eve = eve->next;
	}

	/* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM
	 *  ( bounds just to divide it in pieces for optimization, 
	 *    the edgefill itself has good auto-hole detection)
	 * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */
	
	if (poly > 1) {
		short *polycache, *pc;

		/* so, sort first */
		qsort(pflist, poly, sizeof(PolyFill), vergpoly);

#if 0
		pf = pflist;
		for (a = 1; a <= poly; a++) {
			printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f);
			PRINT2(f, f, pf->min[0], pf->min[1]);
			pf++;
		}
#endif
	
		polycache = pc = MEM_callocN(sizeof(short) * poly, "polycache");
		pf = pflist;
		for (a = 0; a < poly; a++, pf++) {
			for (c = a + 1; c < poly; c++) {
				
				/* if 'a' inside 'c': join (bbox too)
				 * Careful: 'a' can also be inside another poly.
				 */
				if (boundisect(pf, pflist + c)) {
					*pc = c;
					pc++;
				}
				/* only for optimize! */
				/* else if (pf->max_xy[0] < (pflist+c)->min[cox]) break; */
				
			}
			while (pc != polycache) {
				pc--;
				mergepolysSimp(sf_ctx, pf, pflist + *pc);
			}
		}
		MEM_freeN(polycache);
	}

#if 0
	printf("after merge\n");
	pf = pflist;
	for (a = 1; a <= poly; a++) {
		printf("poly:%d edges:%d verts:%d flag: %d\n", a, pf->edges, pf->verts, pf->f);
		pf++;
	}
#endif

	/* STEP 5: MAKE TRIANGLES */

	tempve.first = sf_ctx->fillvertbase.first;
	tempve.last = sf_ctx->fillvertbase.last;
	temped.first = sf_ctx->filledgebase.first;
	temped.last = sf_ctx->filledgebase.last;
	sf_ctx->fillvertbase.first = sf_ctx->fillvertbase.last = NULL;
	sf_ctx->filledgebase.first = sf_ctx->filledgebase.last = NULL;

	pf = pflist;
	for (a = 0; a < poly; a++) {
		if (pf->edges > 1) {
			splitlist(sf_ctx, &tempve, &temped, pf->nr);
			totfaces += scanfill(sf_ctx, pf);
		}
		pf++;
	}
	BLI_movelisttolist(&sf_ctx->fillvertbase, &tempve);
	BLI_movelisttolist(&sf_ctx->filledgebase, &temped);

	/* FREE */

	MEM_freeN(pflist);

	return totfaces;
}
Exemplo n.º 23
0
/**
 * \return a face index in \a faces and set \a r_is_flip
 * if the face is flipped away from the center.
 */
static int recalc_face_normals_find_index(BMesh *bm,
                                          BMFace **faces,
                                          const int faces_len,
                                          bool *r_is_flip)
{
  const float eps = FLT_EPSILON;
  float cent_area_accum = 0.0f;
  float cent[3];
  const float cent_fac = 1.0f / (float)faces_len;

  bool is_flip = false;
  int f_start_index;
  int i;

  /** Search for the best loop. Members are compared in-order defined here. */
  struct {
    /**
     * Squared distance from the center to the loops vertex 'l->v'.
     * The normalized direction between the center and this vertex
     * is also used for the dot-products below.
     */
    float dist_sq;
    /**
     * Signed dot product using the normalized edge vector,
     * (best of 'l->prev->v' or 'l->next->v').
     */
    float edge_dot;
    /**
     * Unsigned dot product using the loop-normal
     * (sign is used to check if we need to flip).
     */
    float loop_dot;
  } best, test;

  UNUSED_VARS_NDEBUG(bm);

  zero_v3(cent);

  /* first calculate the center */
  for (i = 0; i < faces_len; i++) {
    float f_cent[3];
    const float f_area = BM_face_calc_area(faces[i]);
    BM_face_calc_center_median_weighted(faces[i], f_cent);
    madd_v3_v3fl(cent, f_cent, cent_fac * f_area);
    cent_area_accum += f_area;

    BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0);
    BLI_assert(BM_face_is_normal_valid(faces[i]));
  }

  if (cent_area_accum != 0.0f) {
    mul_v3_fl(cent, 1.0f / cent_area_accum);
  }

  /* Distances must start above zero,
   * or we can't do meaningful calculations based on the direction to the center */
  best.dist_sq = eps;
  best.edge_dot = best.loop_dot = -FLT_MAX;

  /* used in degenerate cases only */
  f_start_index = 0;

  /**
   * Find the outer-most vertex, comparing distance to the center,
   * then the outer-most loop attached to that vertex.
   *
   * Important this is correctly detected,
   * where casting a ray from the center wont hit any loops past this one.
   * Otherwise the result may be incorrect.
   */
  for (i = 0; i < faces_len; i++) {
    BMLoop *l_iter, *l_first;

    l_iter = l_first = BM_FACE_FIRST_LOOP(faces[i]);
    do {
      bool is_best_dist_sq;
      float dir[3];
      sub_v3_v3v3(dir, l_iter->v->co, cent);
      test.dist_sq = len_squared_v3(dir);
      is_best_dist_sq = (test.dist_sq > best.dist_sq);
      if (is_best_dist_sq || (test.dist_sq == best.dist_sq)) {
        float edge_dir_pair[2][3];
        mul_v3_fl(dir, 1.0f / sqrtf(test.dist_sq));

        sub_v3_v3v3(edge_dir_pair[0], l_iter->next->v->co, l_iter->v->co);
        sub_v3_v3v3(edge_dir_pair[1], l_iter->prev->v->co, l_iter->v->co);

        if ((normalize_v3(edge_dir_pair[0]) > eps) && (normalize_v3(edge_dir_pair[1]) > eps)) {
          bool is_best_edge_dot;
          test.edge_dot = max_ff(dot_v3v3(dir, edge_dir_pair[0]), dot_v3v3(dir, edge_dir_pair[1]));
          is_best_edge_dot = (test.edge_dot > best.edge_dot);
          if (is_best_dist_sq || is_best_edge_dot || (test.edge_dot == best.edge_dot)) {
            float loop_dir[3];
            cross_v3_v3v3(loop_dir, edge_dir_pair[0], edge_dir_pair[1]);
            if (normalize_v3(loop_dir) > eps) {
              float loop_dir_dot;
              /* Highly unlikely the furthest loop is also the concave part of an ngon,
               * but it can be contrived with _very_ non-planar faces - so better check. */
              if (UNLIKELY(dot_v3v3(loop_dir, l_iter->f->no) < 0.0f)) {
                negate_v3(loop_dir);
              }
              loop_dir_dot = dot_v3v3(dir, loop_dir);
              test.loop_dot = fabsf(loop_dir_dot);
              if (is_best_dist_sq || is_best_edge_dot || (test.loop_dot > best.loop_dot)) {
                best = test;
                f_start_index = i;
                is_flip = (loop_dir_dot < 0.0f);
              }
            }
          }
        }
      }
    } while ((l_iter = l_iter->next) != l_first);
  }

  *r_is_flip = is_flip;
  return f_start_index;
}
Exemplo n.º 24
0
static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
                                         Object *ob, DerivedMesh *dm)
{
	float (*coords)[3], (*co)[3];
	MLoopUV *mloop_uv;
	MTexPoly *mtexpoly, *mt = NULL;
	int i, numVerts, numPolys, numLoops;
	Image *image = umd->image;
	MPoly *mpoly, *mp;
	MLoop *mloop;
	const bool override_image = (umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0;
	Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
	int num_projectors = 0;
	char uvname[MAX_CUSTOMDATA_LAYER_NAME];
	float aspx = umd->aspectx ? umd->aspectx : 1.0f;
	float aspy = umd->aspecty ? umd->aspecty : 1.0f;
	float scax = umd->scalex ? umd->scalex : 1.0f;
	float scay = umd->scaley ? umd->scaley : 1.0f;
	int free_uci = 0;

	for (i = 0; i < umd->num_projectors; ++i)
		if (umd->projectors[i])
			projectors[num_projectors++].ob = umd->projectors[i];

	if (num_projectors == 0) return dm;

	/* make sure there are UV Maps available */

	if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) return dm;

	/* make sure we're using an existing layer */
	CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, umd->uvlayer_name, uvname);

	/* calculate a projection matrix and normal for each projector */
	for (i = 0; i < num_projectors; ++i) {
		float tmpmat[4][4];
		float offsetmat[4][4];
		Camera *cam = NULL;
		/* calculate projection matrix */
		invert_m4_m4(projectors[i].projmat, projectors[i].ob->obmat);

		projectors[i].uci = NULL;

		if (projectors[i].ob->type == OB_CAMERA) {
			
			cam = (Camera *)projectors[i].ob->data;
			if (cam->type == CAM_PANO) {
				projectors[i].uci = BLI_uvproject_camera_info(projectors[i].ob, NULL, aspx, aspy);
				BLI_uvproject_camera_info_scale(projectors[i].uci, scax, scay);
				free_uci = 1;
			}
			else {
				CameraParams params;

				/* setup parameters */
				BKE_camera_params_init(&params);
				BKE_camera_params_from_object(&params, projectors[i].ob);

				/* compute matrix, viewplane, .. */
				BKE_camera_params_compute_viewplane(&params, 1, 1, aspx, aspy);

				/* scale the view-plane */
				params.viewplane.xmin *= scax;
				params.viewplane.xmax *= scax;
				params.viewplane.ymin *= scay;
				params.viewplane.ymax *= scay;

				BKE_camera_params_compute_matrix(&params);
				mul_m4_m4m4(tmpmat, params.winmat, projectors[i].projmat);
			}
		}
		else {
			copy_m4_m4(tmpmat, projectors[i].projmat);
		}

		unit_m4(offsetmat);
		mul_mat3_m4_fl(offsetmat, 0.5);
		offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;

		mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat);

		/* calculate worldspace projector normal (for best projector test) */
		projectors[i].normal[0] = 0;
		projectors[i].normal[1] = 0;
		projectors[i].normal[2] = 1;
		mul_mat3_m4_v3(projectors[i].ob->obmat, projectors[i].normal);
	}

	numPolys = dm->getNumPolys(dm);
	numLoops = dm->getNumLoops(dm);

	/* make sure we are not modifying the original UV map */
	mloop_uv = CustomData_duplicate_referenced_layer_named(&dm->loopData,
	                                                       CD_MLOOPUV, uvname, numLoops);

	/* can be NULL */
	mt = mtexpoly = CustomData_duplicate_referenced_layer_named(&dm->polyData,
	                                                            CD_MTEXPOLY, uvname, numPolys);

	numVerts = dm->getNumVerts(dm);

	coords = MEM_mallocN(sizeof(*coords) * numVerts,
	                     "uvprojectModifier_do coords");
	dm->getVertCos(dm, coords);

	/* convert coords to world space */
	for (i = 0, co = coords; i < numVerts; ++i, ++co)
		mul_m4_v3(ob->obmat, *co);
	
	/* if only one projector, project coords to UVs */
	if (num_projectors == 1 && projectors[0].uci == NULL)
		for (i = 0, co = coords; i < numVerts; ++i, ++co)
			mul_project_m4_v3(projectors[0].projmat, *co);

	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);

	/* apply coords as UVs, and apply image if tfaces are new */
	for (i = 0, mp = mpoly; i < numPolys; ++i, ++mp, ++mt) {
		if (override_image || !image || (mtexpoly == NULL || mt->tpage == image)) {
			if (num_projectors == 1) {
				if (projectors[0].uci) {
					unsigned int fidx = mp->totloop - 1;
					do {
						unsigned int lidx = mp->loopstart + fidx;
						unsigned int vidx = mloop[lidx].v;
						BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], projectors[0].uci);
					} while (fidx--);
				}
				else {
					/* apply transformed coords as UVs */
					unsigned int fidx = mp->totloop - 1;
					do {
						unsigned int lidx = mp->loopstart + fidx;
						unsigned int vidx = mloop[lidx].v;
						copy_v2_v2(mloop_uv[lidx].uv, coords[vidx]);
					} while (fidx--);
				}
			}
			else {
				/* multiple projectors, select the closest to face normal direction */
				float face_no[3];
				int j;
				Projector *best_projector;
				float best_dot;

				/* get the untransformed face normal */
				BKE_mesh_calc_poly_normal_coords(mp, mloop + mp->loopstart, (const float (*)[3])coords, face_no);

				/* find the projector which the face points at most directly
				 * (projector normal with largest dot product is best)
				 */
				best_dot = dot_v3v3(projectors[0].normal, face_no);
				best_projector = &projectors[0];

				for (j = 1; j < num_projectors; ++j) {
					float tmp_dot = dot_v3v3(projectors[j].normal,
					                         face_no);
					if (tmp_dot > best_dot) {
						best_dot = tmp_dot;
						best_projector = &projectors[j];
					}
				}

				if (best_projector->uci) {
					unsigned int fidx = mp->totloop - 1;
					do {
						unsigned int lidx = mp->loopstart + fidx;
						unsigned int vidx = mloop[lidx].v;
						BLI_uvproject_from_camera(mloop_uv[lidx].uv, coords[vidx], best_projector->uci);
					} while (fidx--);
				}
				else {
					unsigned int fidx = mp->totloop - 1;
					do {
						unsigned int lidx = mp->loopstart + fidx;
						unsigned int vidx = mloop[lidx].v;
						mul_v2_project_m4_v3(mloop_uv[lidx].uv, best_projector->projmat, coords[vidx]);
					} while (fidx--);
				}
			}
		}

		if (override_image && mtexpoly) {
			mt->tpage = image;
		}
	}

	MEM_freeN(coords);
	
	if (free_uci) {
		int j;
		for (j = 0; j < num_projectors; ++j) {
			if (projectors[j].uci) {
				MEM_freeN(projectors[j].uci);
			}
		}
	}

	/* Mark tessellated CD layers as dirty. */
	dm->dirty |= DM_DIRTY_TESS_CDLAYERS;

	return dm;
}
Exemplo n.º 25
0
/* MultiresBake callback for heights baking
 * general idea:
 *   - find coord of point with specified UV in hi-res mesh (let's call it p1)
 *   - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res
 *     mesh to make texture smoother) let's call this point p0 and n.
 *   - height wound be dot(n, p1-p0) */
static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data_v, void *bake_data,
                                   ImBuf *ibuf, const int face_index, const int lvl, const float st[2],
                                   float UNUSED(tangmat[3][3]), const int x, const int y)
{
	MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
	MFace mface;
	MHeightBakeData *height_data = (MHeightBakeData *)bake_data;
	MultiresBakeThread *thread_data = (MultiresBakeThread *) thread_data_v;
	float uv[2], *st0, *st1, *st2, *st3;
	int pixel = ibuf->x * y + x;
	float vec[3], p0[3], p1[3], n[3], len;

	lores_dm->getTessFace(lores_dm, face_index, &mface);

	st0 = mtface[face_index].uv[0];
	st1 = mtface[face_index].uv[1];
	st2 = mtface[face_index].uv[2];

	if (mface.v4) {
		st3 = mtface[face_index].uv[3];
		resolve_quad_uv(uv, st, st0, st1, st2, st3);
	}
	else
		resolve_tri_uv(uv, st, st0, st1, st2);

	CLAMP(uv[0], 0.0f, 1.0f);
	CLAMP(uv[1], 0.0f, 1.0f);

	get_ccgdm_data(lores_dm, hires_dm,
	               height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig,
	               lvl, face_index, uv[0], uv[1], p1, NULL);

	if (height_data->ssdm) {
		get_ccgdm_data(lores_dm, height_data->ssdm,
		               height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig,
		               0, face_index, uv[0], uv[1], p0, n);
	}
	else {
		lores_dm->getTessFace(lores_dm, face_index, &mface);

		if (mface.v4) {
			interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
			interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
		}
		else {
			interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
			interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
		}
	}

	sub_v3_v3v3(vec, p1, p0);
	len = dot_v3v3(n, vec);

	height_data->heights[pixel] = len;

	thread_data->height_min = min_ff(thread_data->height_min, len);
	thread_data->height_max = max_ff(thread_data->height_max, len);

	if (ibuf->rect_float) {
		float *rrgbf = ibuf->rect_float + pixel * 4;
		rrgbf[0] = rrgbf[1] = rrgbf[2] = len;
		rrgbf[3] = 1.0f;
	}
	else {
		char *rrgb = (char *)ibuf->rect + pixel * 4;
		rrgb[0] = rrgb[1] = rrgb[2] = FTOCHAR(len);
		rrgb[3] = 255;
	}
}
Exemplo n.º 26
0
/* MultiresBake callback for heights baking
   general idea:
     - find coord of point with specified UV in hi-res mesh (let's call it p1)
     - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res
       mesh to make texture smoother) let's call this point p0 and n.
     - height wound be dot(n, p1-p0) */
static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
                                   const int face_index, const int lvl, const float st[2],
                                   float UNUSED(tangmat[3][3]), const int x, const int y)
{
	MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
	MFace mface;
	Image *ima= mtface[face_index].tpage;
	ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
	MHeightBakeData *height_data= (MHeightBakeData*)bake_data;
	float uv[2], *st0, *st1, *st2, *st3;
	int pixel= ibuf->x*y + x;
	float vec[3], p0[3], p1[3], n[3], len;

	lores_dm->getFace(lores_dm, face_index, &mface);

	st0= mtface[face_index].uv[0];
	st1= mtface[face_index].uv[1];
	st2= mtface[face_index].uv[2];

	if(mface.v4) {
		st3= mtface[face_index].uv[3];
		resolve_quad_uv(uv, st, st0, st1, st2, st3);
	} else
		resolve_tri_uv(uv, st, st0, st1, st2);

	CLAMP(uv[0], 0.0f, 1.0f);
	CLAMP(uv[1], 0.0f, 1.0f);

	get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], p1, 0);

	if(height_data->ssdm) {
		//get_ccgdm_data_ss(lores_dm, height_data->ssdm, lvl, face_index, uv[0], uv[1], p0, n);
		get_ccgdm_data(lores_dm, height_data->ssdm, 0, face_index, uv[0], uv[1], p0, n);
	} else {
		MFace mface;
		lores_dm->getFace(lores_dm, face_index, &mface);

		if(mface.v4) {
			interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
			interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
		} else {
			interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
			interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
		}
	}

	sub_v3_v3v3(vec, p1, p0);
	//len= len_v3(vec);
	len= dot_v3v3(n, vec);

	height_data->heights[pixel]= len;
	if(len<height_data->height_min) height_data->height_min= len;
	if(len>height_data->height_max) height_data->height_max= len;

	if(ibuf->rect_float) {
		float *rrgbf= ibuf->rect_float + pixel*4;
		rrgbf[3]= 1.0f;

		ibuf->userflags= IB_RECT_INVALID;
	} else {
		char *rrgb= (char*)ibuf->rect + pixel*4;
		rrgb[3]= 255;
	}
}
Exemplo n.º 27
0
void draw_volume(ARegion *ar, GPUTexture *tex, float *min, float *max, int res[3], float dx, GPUTexture *tex_shadow)
{
	RegionView3D *rv3d= ar->regiondata;

	float viewnormal[3];
	int i, j, n, good_index;
	float d /*, d0 */ /* UNUSED */, dd, ds;
	float *points = NULL;
	int numpoints = 0;
	float cor[3] = {1.,1.,1.};
	int gl_depth = 0, gl_blend = 0;

	/* draw slices of smoke is adapted from c++ code authored by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */
	float cv[][3] = {
		{1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
		{1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
	};

	// edges have the form edges[n][0][xyz] + t*edges[n][1][xyz]
	float edges[12][2][3] = {
		{{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},

		{{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
		{{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},

		{{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
		{{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
	};

	/* Fragment program to calculate the view3d of smoke */
	/* using 2 textures, density and shadow */
	const char *text = "!!ARBfp1.0\n"
					"PARAM dx = program.local[0];\n"
					"PARAM darkness = program.local[1];\n"
					"PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};\n"
					"TEMP temp, shadow, value;\n"
					"TEX temp, fragment.texcoord[0], texture[0], 3D;\n"
					"TEX shadow, fragment.texcoord[0], texture[1], 3D;\n"
					"MUL value, temp, darkness;\n"
					"MUL value, value, dx;\n"
					"MUL value, value, f;\n"
					"EX2 temp, -value.r;\n"
					"SUB temp.a, 1.0, temp.r;\n"
					"MUL temp.r, temp.r, shadow.r;\n"
					"MUL temp.g, temp.g, shadow.r;\n"
					"MUL temp.b, temp.b, shadow.r;\n"
					"MOV result.color, temp;\n"
					"END\n";
	GLuint prog;

	
	float size[3];

	if(!tex) {
		printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
		return;
	}

	tstart();

	sub_v3_v3v3(size, max, min);

	// maxx, maxy, maxz
	cv[0][0] = max[0];
	cv[0][1] = max[1];
	cv[0][2] = max[2];
	// minx, maxy, maxz
	cv[1][0] = min[0];
	cv[1][1] = max[1];
	cv[1][2] = max[2];
	// minx, miny, maxz
	cv[2][0] = min[0];
	cv[2][1] = min[1];
	cv[2][2] = max[2];
	// maxx, miny, maxz
	cv[3][0] = max[0];
	cv[3][1] = min[1];
	cv[3][2] = max[2];

	// maxx, maxy, minz
	cv[4][0] = max[0];
	cv[4][1] = max[1];
	cv[4][2] = min[2];
	// minx, maxy, minz
	cv[5][0] = min[0];
	cv[5][1] = max[1];
	cv[5][2] = min[2];
	// minx, miny, minz
	cv[6][0] = min[0];
	cv[6][1] = min[1];
	cv[6][2] = min[2];
	// maxx, miny, minz
	cv[7][0] = max[0];
	cv[7][1] = min[1];
	cv[7][2] = min[2];

	copy_v3_v3(edges[0][0], cv[4]); // maxx, maxy, minz
	copy_v3_v3(edges[1][0], cv[5]); // minx, maxy, minz
	copy_v3_v3(edges[2][0], cv[6]); // minx, miny, minz
	copy_v3_v3(edges[3][0], cv[7]); // maxx, miny, minz

	copy_v3_v3(edges[4][0], cv[3]); // maxx, miny, maxz
	copy_v3_v3(edges[5][0], cv[2]); // minx, miny, maxz
	copy_v3_v3(edges[6][0], cv[6]); // minx, miny, minz
	copy_v3_v3(edges[7][0], cv[7]); // maxx, miny, minz

	copy_v3_v3(edges[8][0], cv[1]); // minx, maxy, maxz
	copy_v3_v3(edges[9][0], cv[2]); // minx, miny, maxz
	copy_v3_v3(edges[10][0], cv[6]); // minx, miny, minz
	copy_v3_v3(edges[11][0], cv[5]); // minx, maxy, minz

	// printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
	// printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);

	edges[0][1][2] = size[2];
	edges[1][1][2] = size[2];
	edges[2][1][2] = size[2];
	edges[3][1][2] = size[2];

	edges[4][1][1] = size[1];
	edges[5][1][1] = size[1];
	edges[6][1][1] = size[1];
	edges[7][1][1] = size[1];

	edges[8][1][0] = size[0];
	edges[9][1][0] = size[0];
	edges[10][1][0] = size[0];
	edges[11][1][0] = size[0];

	glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
	glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);

	glLoadMatrixf(rv3d->viewmat);
	// glMultMatrixf(ob->obmat);	

	glDepthMask(GL_FALSE);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	/*
	printf("Viewinv:\n");
	printf("%f, %f, %f\n", rv3d->viewinv[0][0], rv3d->viewinv[0][1], rv3d->viewinv[0][2]);
	printf("%f, %f, %f\n", rv3d->viewinv[1][0], rv3d->viewinv[1][1], rv3d->viewinv[1][2]);
	printf("%f, %f, %f\n", rv3d->viewinv[2][0], rv3d->viewinv[2][1], rv3d->viewinv[2][2]);
	*/

	// get view vector
	copy_v3_v3(viewnormal, rv3d->viewinv[2]);
	normalize_v3(viewnormal);

	// find cube vertex that is closest to the viewer
	for (i=0; i<8; i++) {
		float x,y,z;

		x = cv[i][0] - viewnormal[0];
		y = cv[i][1] - viewnormal[1];
		z = cv[i][2] - viewnormal[2];

		if ((x>=min[0])&&(x<=max[0])
			&&(y>=min[1])&&(y<=max[1])
			&&(z>=min[2])&&(z<=max[2])) {
			break;
		}
	}

	if(i >= 8) {
		/* fallback, avoid using buffer over-run */
		i= 0;
	}

	// printf("i: %d\n", i);
	// printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);

	if (GL_TRUE == glewIsSupported("GL_ARB_fragment_program"))
	{
		glEnable(GL_FRAGMENT_PROGRAM_ARB);
		glGenProgramsARB(1, &prog);

		glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, prog);
		glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(text), text);

		// cell spacing
		glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, dx, dx, dx, 1.0);
		// custom parameter for smoke style (higher = thicker)
		glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 1, 7.0, 7.0, 7.0, 1.0);
	}
	else
		printf("Your gfx card does not support 3D View smoke drawing.\n");

	GPU_texture_bind(tex, 0);
	if(tex_shadow)
		GPU_texture_bind(tex_shadow, 1);
	else
		printf("No volume shadow\n");

	if (!GPU_non_power_of_two_support()) {
		cor[0] = (float)res[0]/(float)larger_pow2(res[0]);
		cor[1] = (float)res[1]/(float)larger_pow2(res[1]);
		cor[2] = (float)res[2]/(float)larger_pow2(res[2]);
	}

	// our slices are defined by the plane equation a*x + b*y +c*z + d = 0
	// (a,b,c), the plane normal, are given by viewdir
	// d is the parameter along the view direction. the first d is given by
	// inserting previously found vertex into the plane equation

	/* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
	ds = (ABS(viewnormal[0])*size[0] + ABS(viewnormal[1])*size[1] + ABS(viewnormal[2])*size[2]);
	dd = 0.05; // ds/512.0f;
	n = 0;
	good_index = i;

	// printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);

	points = MEM_callocN(sizeof(float)*12*3, "smoke_points_preview");

	while(1) {
		float p0[3];
		float tmp_point[3], tmp_point2[3];

		if(dd*(float)n > ds)
			break;

		copy_v3_v3(tmp_point, viewnormal);
		mul_v3_fl(tmp_point, -dd*((ds/dd)-(float)n));
		add_v3_v3v3(tmp_point2, cv[good_index], tmp_point);
		d = dot_v3v3(tmp_point2, viewnormal);

		// printf("my d: %f\n", d);

		// intersect_edges returns the intersection points of all cube edges with
		// the given plane that lie within the cube
		numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);

		// printf("points: %d\n", numpoints);

		if (numpoints > 2) {
			copy_v3_v3(p0, points);

			// sort points to get a convex polygon
			for(i = 1; i < numpoints - 1; i++)
			{
				for(j = i + 1; j < numpoints; j++)
				{
					if(!convex(p0, viewnormal, &points[j * 3], &points[i * 3]))
					{
						float tmp2[3];
						copy_v3_v3(tmp2, &points[j * 3]);
						copy_v3_v3(&points[j * 3], &points[i * 3]);
						copy_v3_v3(&points[i * 3], tmp2);
					}
				}
			}

			// printf("numpoints: %d\n", numpoints);
			glBegin(GL_POLYGON);
			glColor3f(1.0, 1.0, 1.0);
			for (i = 0; i < numpoints; i++) {
				glTexCoord3d((points[i * 3 + 0] - min[0] )*cor[0]/size[0], (points[i * 3 + 1] - min[1])*cor[1]/size[1], (points[i * 3 + 2] - min[2])*cor[2]/size[2]);
				glVertex3f(points[i * 3 + 0], points[i * 3 + 1], points[i * 3 + 2]);
			}
			glEnd();
		}
		n++;
	}

	tend();
	// printf ( "Draw Time: %f\n",( float ) tval() );

	if(tex_shadow)
		GPU_texture_unbind(tex_shadow);
	GPU_texture_unbind(tex);

	if(GLEW_ARB_fragment_program)
	{
		glDisable(GL_FRAGMENT_PROGRAM_ARB);
		glDeleteProgramsARB(1, &prog);
	}


	MEM_freeN(points);

	if(!gl_blend)
		glDisable(GL_BLEND);
	if(gl_depth)
	{
		glEnable(GL_DEPTH_TEST);
		glDepthMask(GL_TRUE);	
	}
}
Exemplo n.º 28
0
MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda)
{
    float co1[3], co2[3], co3[3], co4[3];
    float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l;
    int quad;

    quad= RE_rayface_isQuad(face);

    copy_v3_v3(co1, face->v1);
    copy_v3_v3(co2, face->v2);
    copy_v3_v3(co3, face->v3);

    copy_v3_v3(r, dir);

    /* intersect triangle */
    sub_v3_v3v3(t0, co3, co2);
    sub_v3_v3v3(t1, co3, co1);

    cross_v3_v3v3(x, r, t1);
    divdet= dot_v3v3(t0, x);

    sub_v3_v3v3(m, start, co3);
    det1= dot_v3v3(m, x);

    if(divdet != 0.0f) {
        divdet= 1.0f/divdet;
        v= det1*divdet;

        if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
            float cros[3];

            cross_v3_v3v3(cros, m, t0);
            u= divdet*dot_v3v3(cros, r);

            if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) {
                l= divdet*dot_v3v3(cros, t1);

                /* check if intersection is within ray length */
                if(l > -RE_RAYTRACE_EPSILON && l < *lambda) {
                    uv[0]= u;
                    uv[1]= v;
                    *lambda= l;
                    return 1;
                }
            }
        }
    }

    /* intersect second triangle in quad */
    if(quad) {
        copy_v3_v3(co4, face->v4);
        sub_v3_v3v3(t0, co3, co4);
        divdet= dot_v3v3(t0, x);

        if(divdet != 0.0f) {
            divdet= 1.0f/divdet;
            v = det1*divdet;

            if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
                float cros[3];

                cross_v3_v3v3(cros, m, t0);
                u= divdet*dot_v3v3(cros, r);

                if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) {
                    l= divdet*dot_v3v3(cros, t1);

                    if(l >- RE_RAYTRACE_EPSILON && l < *lambda) {
                        uv[0]= u;
                        uv[1]= -(1.0f + v + u);
                        *lambda= l;
                        return 2;
                    }
                }
            }
        }
    }

    return 0;
}
MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
{
	return dot_v3v3(co, plane) + plane[3];
}
Exemplo n.º 30
0
static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args)
{
	VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
	float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
	float det, inv_det, u, v, t;
	int clip = 1;

	if (!PyArg_ParseTuple(args,
	                      "O!O!O!O!O!|i:intersect_ray_tri",
	                      &vector_Type, &vec1,
	                      &vector_Type, &vec2,
	                      &vector_Type, &vec3,
	                      &vector_Type, &ray,
	                      &vector_Type, &ray_off, &clip))
	{
		return NULL;
	}
	if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
		PyErr_SetString(PyExc_ValueError,
		                "only 3D vectors for all parameters");
		return NULL;
	}

	if (BaseMath_ReadCallback(vec1) == -1 ||
	    BaseMath_ReadCallback(vec2) == -1 ||
	    BaseMath_ReadCallback(vec3) == -1 ||
	    BaseMath_ReadCallback(ray)  == -1 ||
	    BaseMath_ReadCallback(ray_off) == -1)
	{
		return NULL;
	}

	copy_v3_v3(v1, vec1->vec);
	copy_v3_v3(v2, vec2->vec);
	copy_v3_v3(v3, vec3->vec);

	copy_v3_v3(dir, ray->vec);
	normalize_v3(dir);

	copy_v3_v3(orig, ray_off->vec);

	/* find vectors for two edges sharing v1 */
	sub_v3_v3v3(e1, v2, v1);
	sub_v3_v3v3(e2, v3, v1);

	/* begin calculating determinant - also used to calculated U parameter */
	cross_v3_v3v3(pvec, dir, e2);

	/* if determinant is near zero, ray lies in plane of triangle */
	det = dot_v3v3(e1, pvec);

	if (det > -0.000001f && det < 0.000001f) {
		Py_RETURN_NONE;
	}

	inv_det = 1.0f / det;

	/* calculate distance from v1 to ray origin */
	sub_v3_v3v3(tvec, orig, v1);

	/* calculate U parameter and test bounds */
	u = dot_v3v3(tvec, pvec) * inv_det;
	if (clip && (u < 0.0f || u > 1.0f)) {
		Py_RETURN_NONE;
	}

	/* prepare to test the V parameter */
	cross_v3_v3v3(qvec, tvec, e1);

	/* calculate V parameter and test bounds */
	v = dot_v3v3(dir, qvec) * inv_det;

	if (clip && (v < 0.0f || u + v > 1.0f)) {
		Py_RETURN_NONE;
	}

	/* calculate t, ray intersects triangle */
	t = dot_v3v3(e2, qvec) * inv_det;

	mul_v3_fl(dir, t);
	add_v3_v3v3(pvec, orig, dir);

	return Vector_CreatePyObject(pvec, 3, Py_NEW, NULL);
}