Ejemplo n.º 1
0
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
	ParticleThreadContext *ctx= thread->ctx;
	DerivedMesh *dm= ctx->dm;
	float *v1, *v2, *v3, *v4, nor[3], co[3];
	float cur_d, min_d, randu, randv;
	int distr= ctx->distr;
	int i, intersect, tot;
	int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
	
	MFace *mface;
	MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
	
	pa->num = i = ctx->index[p];
	mface = dm->getTessFaceData(dm,i,CD_MFACE);
	
	switch (distr) {
		case PART_DISTR_JIT:
			if (ctx->jitlevel == 1) {
				if (mface->v4)
					psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
				else
					psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
			}
			else {
				float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
				if (!isnan(offset)) {
					psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv);
				}
			}
			break;
		case PART_DISTR_RAND:
			randu= BLI_rng_get_float(thread->rng);
			randv= BLI_rng_get_float(thread->rng);
			rng_skip_tot -= 2;
			
			psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
			break;
	}
	pa->foffset= 0.0f;
	
	/* experimental */
	tot=dm->getNumTessFaces(dm);
	
	psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
	
	normalize_v3(nor);
	negate_v3(nor);
	
	min_d=FLT_MAX;
	intersect=0;
	
	for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
		if (i==pa->num) continue;
		
		v1=mvert[mface->v1].co;
		v2=mvert[mface->v2].co;
		v3=mvert[mface->v3].co;
		
		if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, NULL)) {
			if (cur_d<min_d) {
				min_d=cur_d;
				pa->foffset=cur_d*0.5f; /* to the middle of volume */
				intersect=1;
			}
		}
		if (mface->v4) {
			v4=mvert[mface->v4].co;
			
			if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, NULL)) {
				if (cur_d<min_d) {
					min_d=cur_d;
					pa->foffset=cur_d*0.5f; /* to the middle of volume */
					intersect=1;
				}
			}
		}
	}
	if (intersect==0)
		pa->foffset=0.0;
	else {
		switch (distr) {
			case PART_DISTR_JIT:
				pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
				break;
			case PART_DISTR_RAND:
				pa->foffset *= BLI_frand();
				break;
		}
	}
	
	if (rng_skip_tot > 0) /* should never be below zero */
		BLI_rng_skip(thread->rng, rng_skip_tot);
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
static void handleRadialSymmetry(BGraph *graph, BNode *root_node, int depth, float axis[3], float limit)
{
	RadialArc *ring = NULL;
	RadialArc *unit;
	int total = 0;
	int group;
	int first;
	int i;

	/* mark topological symmetry */
	root_node->symmetry_flag |= SYM_TOPOLOGICAL;

	/* total the number of arcs in the symmetry ring */
	for (i = 0; i < root_node->degree; i++) {
		BArc *connectedArc = root_node->arcs[i];
		
		/* depth is store as a negative in flag. symmetry level is positive */
		if (connectedArc->symmetry_level == -depth) {
			total++;
		}
	}

	ring = MEM_callocN(sizeof(RadialArc) * total, "radial symmetry ring");
	unit = ring;

	/* fill in the ring */
	for (i = 0; i < root_node->degree; i++) {
		BArc *connectedArc = root_node->arcs[i];
		
		/* depth is store as a negative in flag. symmetry level is positive */
		if (connectedArc->symmetry_level == -depth) {
			BNode *otherNode = BLI_otherNode(connectedArc, root_node);
			float vec[3];

			unit->arc = connectedArc;

			/* project the node to node vector on the symmetry plane */
			sub_v3_v3v3(unit->n, otherNode->p, root_node->p);
			project_v3_v3v3(vec, unit->n, axis);
			sub_v3_v3v3(unit->n, unit->n, vec);

			normalize_v3(unit->n);

			unit++;
		}
	}

	/* sort ring by arc length
	 * using a rather bogus insertion sort
	 * but rings will never get too big to matter
	 * */
	for (i = 0; i < total; i++) {
		int j;

		for (j = i - 1; j >= 0; j--) {
			BArc *arc1, *arc2;
			
			arc1 = ring[j].arc;
			arc2 = ring[j + 1].arc;
			
			if (arc1->length > arc2->length) {
				/* swap with smaller */
				RadialArc tmp;
				
				tmp = ring[j + 1];
				ring[j + 1] = ring[j];
				ring[j] = tmp;
			}
			else {
				break;
			}
		}
	}

	/* Dispatch to specific symmetry tests */
	first = 0;
	group = 0;
	
	for (i = 1; i < total; i++) {
		int dispatch = 0;
		int last = i - 1;
		
		if (fabsf(ring[first].arc->length - ring[i].arc->length) > limit) {
			dispatch = 1;
		}

		/* if not dispatching already and on last arc
		 * Dispatch using current arc as last
		 */
		if (dispatch == 0 && i == total - 1) {
			last = i;
			dispatch = 1;
		}
		
		if (dispatch) {
			int sub_total = last - first + 1; 

			group += 1;

			if (sub_total == 1) {
				group -= 1; /* not really a group so decrement */
				/* NOTHING TO DO */
			}
			else if (sub_total == 2) {
				BArc *arc1, *arc2;
				BNode *node1, *node2;
				
				arc1 = ring[first].arc;
				arc2 = ring[last].arc;
				
				node1 = BLI_otherNode(arc1, root_node);
				node2 = BLI_otherNode(arc2, root_node);
				
				testAxialSymmetry(graph, root_node, node1, node2, arc1, arc2, axis, limit, group);
			}
			else if (sub_total != total) /* allocate a new sub ring if needed */ {
				RadialArc *sub_ring = MEM_callocN(sizeof(RadialArc) * sub_total, "radial symmetry ring");
				int sub_i;
				
				/* fill in the sub ring */
				for (sub_i = 0; sub_i < sub_total; sub_i++) {
					sub_ring[sub_i] = ring[first + sub_i];
				}
				
				testRadialSymmetry(graph, root_node, sub_ring, sub_total, axis, limit, group);
			
				MEM_freeN(sub_ring);
			}
			else if (sub_total == total) {
				testRadialSymmetry(graph, root_node, ring, total, axis, limit, group);
			}
			
			first = i;
		}
	}


	MEM_freeN(ring);
}
Ejemplo n.º 4
0
static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3])
{
	float visifac, lv[3], lampdist;
	float tr[3] = {1.0, 1.0, 1.0};
	float hitco[3], *atten_co;
	float p, ref_col[3];
	
	if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay) == 0) return;
	if ((lar->lay & shi->lay) == 0) return;
	if (lar->energy == 0.0f) return;
	
	if ((visifac = lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
	
	copy_v3_v3(lacol, &lar->r);
	
	if (lar->mode & LA_TEXTURE) {
		shi->osatex = 0;
		do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
	}

	mul_v3_fl(lacol, visifac);

	if (ELEM(lar->type, LA_SUN, LA_HEMI))
		copy_v3_v3(lv, lar->vec);
	negate_v3(lv);
	
	if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
		mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
	}
	else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
		Isect is;
		
		if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
			mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
			if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
		}
		
		/* find minimum of volume bounds, or lamp coord */
		if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
			float dist = len_v3v3(co, hitco);
			VlakRen *vlr = (VlakRen *)is.hit.face;
			
			/* simple internal shadowing */
			if (vlr->mat->material_type == MA_TYPE_SURFACE) {
				lacol[0] = lacol[1] = lacol[2] = 0.0f;
				return;
			}

			if (ELEM(lar->type, LA_SUN, LA_HEMI))
				/* infinite lights, can never be inside volume */
				atten_co = hitco;
			else if (lampdist < dist) {
				atten_co = lar->co;
			}
			else
				atten_co = hitco;
			
			vol_get_transmittance(shi, tr, co, atten_co);
			
			mul_v3_v3v3(lacol, lacol, tr);
		}
		else {
			/* Point is on the outside edge of the volume,
			 * therefore no attenuation, full transmission.
			 * Radiance from lamp remains unchanged */
		}
	}
	
	if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return;
	
	normalize_v3(lv);
	p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv);
	
	/* physically based scattering with non-physically based RGB gain */
	vol_get_reflection_color(shi, ref_col, co);
	
	lacol[0] *= p * ref_col[0];
	lacol[1] *= p * ref_col[1];
	lacol[2] *= p * ref_col[2];
}
Ejemplo n.º 5
0
static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad)
{
	ShadeInput *shi = ssamp->shi;
	ShadeResult *shr = ssamp->shr;
	float l, u, v, *v1, *v2, *v3;
	
	/* init */
	if (vlr->v4) {
		shi->u = u = 0.5f;
		shi->v = v = 0.5f;
	}
	else {
		shi->u = u = 1.0f / 3.0f;
		shi->v = v = 1.0f / 3.0f;
	}

	/* setup render coordinates */
	v1 = vlr->v1->co;
	v2 = vlr->v2->co;
	v3 = vlr->v3->co;
	
	/* renderco */
	l = 1.0f - u - v;
	
	shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
	shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
	shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];

	shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);

	/* set up view vector */
	copy_v3_v3(shi->view, shi->co);
	normalize_v3(shi->view);
	
	/* cache for shadow */
	shi->samplenr++;

	shi->xs = 0; /* TODO */
	shi->ys = 0;
	
	shade_input_set_normals(shi);

	/* no normal flip */
	if (shi->flippednor)
		shade_input_flip_normals(shi);

	madd_v3_v3fl(shi->co, shi->facenor, -0.0001f); /* ugly.. */

	/* not a pretty solution, but fixes common cases */
	if (shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
		negate_v3(shi->vn);
		negate_v3(shi->vno);
		negate_v3(shi->nmapnorm);
	}

	/* init material vars */
	shade_input_init_material(shi);

	/* render */
	shade_input_set_shade_texco(shi);

	if (shi->mat->nodetree && shi->mat->use_nodes) {
		ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
		shi->mat = vlr->mat;  /* shi->mat is being set in nodetree */
	}
	else {
		shade_material_loop(shi, shr);
	}

	copy_v3_v3(rad, shr->combined);
}
Ejemplo n.º 6
0
struct chartrans *BKE_text_to_curve(Main *bmain, Scene *scene, Object *ob, int mode)
{
	VFont *vfont, *oldvfont;
	VFontData *vfd= NULL;
	Curve *cu;
	CharInfo *info = NULL, *custrinfo;
	TextBox *tb;
	VChar *che;
	struct chartrans *chartransdata=NULL, *ct;
	float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4;
	float twidth, maxlen= 0;
	int i, slen, j;
	int curbox;
	int selstart, selend;
	int utf8len;
	short cnr=0, lnr=0, wsnr= 0;
	wchar_t *mem, *tmp, ascii;

	/* renark: do calculations including the trailing '\0' of a string
	 * because the cursor can be at that location */

	if (ob->type!=OB_FONT) return NULL;

	// Set font data
	cu= (Curve *) ob->data;
	vfont= cu->vfont;
	
	if (cu->str == NULL) return NULL;
	if (vfont == NULL) return NULL;

	// Create unicode string
	utf8len = BLI_strlen_utf8(cu->str);
	mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem");
	
	BLI_strncpy_wchar_from_utf8(mem, cu->str, utf8len + 1);

	// Count the wchar_t string length
	slen = wcslen(mem);

	if (cu->ulheight == 0.0f)
		cu->ulheight = 0.05f;
	
	if (cu->strinfo==NULL)	/* old file */
		cu->strinfo = MEM_callocN((slen+4) * sizeof(CharInfo), "strinfo compat");
	
	custrinfo= cu->strinfo;
	if (cu->editfont)
		custrinfo= cu->editfont->textbufinfo;
	
	if (cu->tb==NULL)
		cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBox compat");

	vfd= vfont_get_data(bmain, vfont);

	/* The VFont Data can not be found */
	if (!vfd) {
		if (mem)
			MEM_freeN(mem);	
		return NULL;
	}

	/* calc offset and rotation of each char */
	ct = chartransdata =
		(struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext");

	/* We assume the worst case: 1 character per line (is freed at end anyway) */

	linedata= MEM_mallocN(sizeof(float)*(slen*2 + 1),"buildtext2");
	linedata2= MEM_mallocN(sizeof(float)*(slen*2 + 1),"buildtext3");
	linedata3= MEM_callocN(sizeof(float)*(slen*2 + 1),"buildtext4");	
	linedata4= MEM_callocN(sizeof(float)*(slen*2 + 1),"buildtext5");		
	
	linedist= cu->linedist;
	
	xof= cu->xof + (cu->tb[0].x/cu->fsize);
	yof= cu->yof + (cu->tb[0].y/cu->fsize);

	xtrax= 0.5f*cu->spacing-0.5f;

	oldvfont = NULL;

	for (i=0; i<slen; i++) custrinfo[i].flag &= ~(CU_CHINFO_WRAP|CU_CHINFO_SMALLCAPS_CHECK);

	if (cu->selboxes) MEM_freeN(cu->selboxes);
	cu->selboxes = NULL;
	if (BKE_font_getselection(ob, &selstart, &selend))
		cu->selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes");

	tb = &(cu->tb[0]);
	curbox= 0;
	for (i = 0 ; i<=slen ; i++) {
	makebreak:
		// Characters in the list
		info = &(custrinfo[i]);
		ascii = mem[i];
		if (info->flag & CU_CHINFO_SMALLCAPS) {
			ascii = towupper(ascii);
			if (mem[i] != ascii) {
				mem[i]= ascii;
				info->flag |= CU_CHINFO_SMALLCAPS_CHECK;
			}
		}

		vfont = which_vfont(cu, info);
		
		if (vfont==NULL) break;

		che= find_vfont_char(vfd, ascii);

		/*
		 * The character wasn't in the current curve base so load it
		 * But if the font is FO_BUILTIN_NAME then do not try loading since
		 * whole font is in the memory already
		 */
		if (che == NULL && strcmp(vfont->name, FO_BUILTIN_NAME))	{
			BLI_vfontchar_from_freetypefont(vfont, ascii);
		}

		/* Try getting the character again from the list */
		che= find_vfont_char(vfd, ascii);

		/* No VFont found */
		if (vfont==NULL) {
			if (mem)
				MEM_freeN(mem);
			MEM_freeN(chartransdata);
			return NULL;
		}

		if (vfont != oldvfont) {
			vfd= vfont_get_data(bmain, vfont);
			oldvfont = vfont;
		}

		/* VFont Data for VFont couldn't be found */
		if (!vfd) {
			if (mem)
				MEM_freeN(mem);
			MEM_freeN(chartransdata);
			return NULL;
		}

		twidth = char_width(cu, che, info);

		// Calculate positions
		if ((tb->w != 0.0f) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w + cu->xof*cu->fsize) {
	//		fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
			for (j=i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak==0); j--) {
				if (mem[j]==' ' || mem[j]=='-') {
					ct -= (i-(j-1));
					cnr -= (i-(j-1));
					if (mem[j] == ' ') wsnr--;
					if (mem[j] == '-') wsnr++;
					i = j-1;
					xof = ct->xof;
					ct[1].dobreak = 1;
					custrinfo[i+1].flag |= CU_CHINFO_WRAP;
					goto makebreak;
				}
				if (chartransdata[j].dobreak) {
	//				fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]);
					ct->dobreak= 1;
					custrinfo[i+1].flag |= CU_CHINFO_WRAP;
					ct -= 1;
					cnr -= 1;
					i--;
					xof = ct->xof;
					goto makebreak;
				}
			}
		}
		if (ascii== '\n' || ascii== '\r' || ascii==0 || ct->dobreak) {
			ct->xof= xof;
			ct->yof= yof;
			ct->linenr= lnr;
			ct->charnr= cnr;
			
			yof-= linedist;
			
			maxlen= MAX2(maxlen, (xof-tb->x/cu->fsize));
			linedata[lnr]= xof-tb->x/cu->fsize;
			linedata2[lnr]= cnr;
			linedata3[lnr]= tb->w/cu->fsize;
			linedata4[lnr]= wsnr;
			
			if ( (tb->h != 0.0f) &&
				 ((-(yof-(tb->y/cu->fsize))) > ((tb->h/cu->fsize)-(linedist*cu->fsize)) - cu->yof) &&
				 (cu->totbox > (curbox+1)) ) {
				maxlen= 0;
				tb++;
				curbox++;
				yof= cu->yof + tb->y/cu->fsize;
			}

			/* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
#if 0
			if (ascii == '\n' || ascii == '\r')
				xof = cu->xof;
			else
				xof= cu->xof + (tb->x/cu->fsize);
#else
			xof= cu->xof + (tb->x/cu->fsize);
#endif
			lnr++;
			cnr= 0;
			wsnr= 0;
		}
		else if (ascii==9) {	/* TAB */
			float tabfac;
			
			ct->xof= xof;
			ct->yof= yof;
			ct->linenr= lnr;
			ct->charnr= cnr++;

			tabfac= (xof-cu->xof+0.01f);
			tabfac= 2.0f*ceilf(tabfac/2.0f);
			xof= cu->xof+tabfac;
		}
		else {
			SelBox *sb= NULL;
			float wsfac;

			ct->xof= xof;
			ct->yof= yof;
			ct->linenr= lnr;
			ct->charnr= cnr++;

			if (cu->selboxes && (i>=selstart) && (i<=selend)) {
				sb = &(cu->selboxes[i-selstart]);
				sb->y = yof*cu->fsize-linedist*cu->fsize*0.1f;
				sb->h = linedist*cu->fsize;
				sb->w = xof*cu->fsize;
			}
	
			if (ascii==32) {
				wsfac = cu->wordspace; 
				wsnr++;
			} 
			else wsfac = 1.0f;
			
			// Set the width of the character
			twidth = char_width(cu, che, info);

			xof += (twidth*wsfac*(1.0f+(info->kern/40.0f)) ) + xtrax;
			
			if (sb) 
				sb->w = (xof*cu->fsize) - sb->w;
		}
		ct++;
	}
	
	cu->lines= 1;
	ct= chartransdata;
	tmp = mem;
	for (i= 0; i<=slen; i++, tmp++, ct++) {
		ascii = *tmp;
		if (ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++;
	}	

	// linedata is now: width of line
	// linedata2 is now: number of characters
	// linedata3 is now: maxlen of that line
	// linedata4 is now: number of whitespaces of line

	if (cu->spacemode!=CU_LEFT) {
		ct= chartransdata;

		if (cu->spacemode==CU_RIGHT) {
			for (i=0;i<lnr;i++) linedata[i]= linedata3[i]-linedata[i];
			for (i=0; i<=slen; i++) {
				ct->xof+= linedata[ct->linenr];
				ct++;
			}
		}
		else if (cu->spacemode==CU_MIDDLE) {
			for (i=0;i<lnr;i++) linedata[i]= (linedata3[i]-linedata[i])/2;
			for (i=0; i<=slen; i++) {
				ct->xof+= linedata[ct->linenr];
				ct++;
			}
		}
		else if ((cu->spacemode==CU_FLUSH) &&
				  (cu->tb[0].w != 0.0f)) {
			for (i=0;i<lnr;i++)
				if (linedata2[i]>1)
					linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1);
			for (i=0; i<=slen; i++) {
				for (j=i; (!ELEM3(mem[j], '\0', '\n', '\r')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) {
					/* do nothing */
				}

//				if ((mem[j]!='\r') && (mem[j]!='\n') && (mem[j])) {
					ct->xof+= ct->charnr*linedata[ct->linenr];
//				}
				ct++;
			}
		} 
		else if ((cu->spacemode==CU_JUSTIFY) && (cu->tb[0].w != 0.0f)) {
			float curofs= 0.0f;
			for (i=0; i<=slen; i++) {
				for (j=i; (mem[j]) && (mem[j]!='\n') && 
						  (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
				if ((mem[j]!='\r') && (mem[j]!='\n') &&
					((chartransdata[j].dobreak!=0))) {
					if (mem[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr];
					ct->xof+= curofs;
				}
				if (mem[i]=='\n' || mem[i]=='\r' || chartransdata[i].dobreak) curofs= 0;
				ct++;
			}			
		}
	}
	
	/* TEXT ON CURVE */
	/* Note: Only OB_CURVE objects could have a path  */
	if (cu->textoncurve && cu->textoncurve->type==OB_CURVE) {
		Curve *cucu= cu->textoncurve->data;
		int oldflag= cucu->flag;
		
		cucu->flag |= (CU_PATH+CU_FOLLOW);
		
		if (cucu->path==NULL) makeDispListCurveTypes(scene, cu->textoncurve, 0);
		if (cucu->path) {
			float distfac, imat[4][4], imat3[3][3], cmat[3][3];
			float minx, maxx, miny, maxy;
			float timeofs, sizefac;
			
			invert_m4_m4(imat, ob->obmat);
			copy_m3_m4(imat3, imat);

			copy_m3_m4(cmat, cu->textoncurve->obmat);
			mul_m3_m3m3(cmat, cmat, imat3);
			sizefac= normalize_v3(cmat[0])/cu->fsize;
			
			minx=miny= 1.0e20f;
			maxx=maxy= -1.0e20f;
			ct= chartransdata;
			for (i=0; i<=slen; i++, ct++) {
				if (minx>ct->xof) minx= ct->xof;
				if (maxx<ct->xof) maxx= ct->xof;
				if (miny>ct->yof) miny= ct->yof;
				if (maxy<ct->yof) maxy= ct->yof;
			}
			
			/* we put the x-coordinaat exact at the curve, the y is rotated */
			
			/* length correction */
			distfac= sizefac*cucu->path->totdist/(maxx-minx);
			timeofs= 0.0f;
			
			if (distfac > 1.0f) {
				/* path longer than text: spacemode involves */
				distfac= 1.0f/distfac;
				
				if (cu->spacemode==CU_RIGHT) {
					timeofs= 1.0f-distfac;
				}
				else if (cu->spacemode==CU_MIDDLE) {
					timeofs= (1.0f-distfac)/2.0f;
				}
				else if (cu->spacemode==CU_FLUSH) distfac= 1.0f;
				
			}
			else distfac= 1.0;
			
			distfac/= (maxx-minx);
			
			timeofs+= distfac*cu->xof;	/* not cyclic */
			
			ct= chartransdata;
			for (i=0; i<=slen; i++, ct++) {
				float ctime, dtime, vec[4], tvec[4], rotvec[3];
				float si, co;
				
				/* rotate around center character */
				ascii = mem[i];

				che= find_vfont_char(vfd, ascii);
	
				twidth = char_width(cu, che, info);

				dtime= distfac*0.5f*twidth;

				ctime= timeofs + distfac*( ct->xof - minx);
				CLAMP(ctime, 0.0f, 1.0f);

				/* calc the right loc AND the right rot separately */
				/* vec, tvec need 4 items */
				where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL);
				where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec, NULL, NULL, NULL);
				
				mul_v3_fl(vec, sizefac);
				
				ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0]));

				si= (float)sin(ct->rot);
				co= (float)cos(ct->rot);

				yof= ct->yof;
				
				ct->xof= vec[0] + si*yof;
				ct->yof= vec[1] + co*yof;
				
			}
			cucu->flag= oldflag;
		}
	}

	if (cu->selboxes) {
		ct= chartransdata;
		for (i=0; i<=selend; i++, ct++) {
			if (i>=selstart) {
				cu->selboxes[i-selstart].x = ct->xof*cu->fsize;
				cu->selboxes[i-selstart].y = ct->yof*cu->fsize;				
			}
		}
	}

	if (mode==FO_CURSUP || mode==FO_CURSDOWN || mode==FO_PAGEUP || mode==FO_PAGEDOWN) {
		/* 2: curs up
		 * 3: curs down */
		ct= chartransdata+cu->pos;
		
		if ((mode==FO_CURSUP || mode==FO_PAGEUP) && ct->linenr==0);
		else if ((mode==FO_CURSDOWN || mode==FO_PAGEDOWN) && ct->linenr==lnr);
		else {
			switch(mode) {
				case FO_CURSUP:		lnr= ct->linenr-1; break;
				case FO_CURSDOWN:	lnr= ct->linenr+1; break;
				case FO_PAGEUP:		lnr= ct->linenr-10; break;
				case FO_PAGEDOWN:	lnr= ct->linenr+10; break;
			}
			cnr= ct->charnr;
			/* seek for char with lnr en cnr */
			cu->pos= 0;
			ct= chartransdata;
			for (i= 0; i<slen; i++) {
				if (ct->linenr==lnr) {
					if (ct->charnr==cnr) break;
					if ( (ct+1)->charnr==0) break;
				}
				else if (ct->linenr>lnr) break;
				cu->pos++;
				ct++;
			}
		}
	}
	
	/* cursor first */
	if (cu->editfont) {
		float si, co;
		
		ct= chartransdata+cu->pos;
		si= (float)sin(ct->rot);
		co= (float)cos(ct->rot);
				
		f= cu->editfont->textcurs[0];
		
		f[0]= cu->fsize*(-0.1f*co + ct->xof);
		f[1]= cu->fsize*(0.1f*si + ct->yof);
		
		f[2]= cu->fsize*(0.1f*co + ct->xof);
		f[3]= cu->fsize*(-0.1f*si + ct->yof);
		
		f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof);
		f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof);
		
		f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof);
		f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof);
		
	}

	MEM_freeN(linedata);
	MEM_freeN(linedata2);		
	MEM_freeN(linedata3);
	MEM_freeN(linedata4);

	if (mode == FO_SELCHANGE) {
		MEM_freeN(chartransdata);
		MEM_freeN(mem);
		return NULL;
	}

	if (mode == FO_EDIT) {
		/* make nurbdata */
		freeNurblist(&cu->nurb);
		
		ct= chartransdata;
		if (cu->sepchar==0) {
			for (i= 0; i<slen; i++) {
				unsigned long cha = (uintptr_t) mem[i];
				info = &(custrinfo[i]);
				if (info->mat_nr > (ob->totcol)) {
					/* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */
					info->mat_nr = 0;
				}
				// We do not want to see any character for \n or \r
				if (cha != '\n' && cha != '\r')
					buildchar(bmain, cu, cha, info, ct->xof, ct->yof, ct->rot, i);
				
				if ((info->flag & CU_CHINFO_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) {
					float ulwidth, uloverlap= 0.0f;
					
					if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') &&
						 ((mem[i+1] != ' ') || (custrinfo[i+1].flag & CU_CHINFO_UNDERLINE)) && ((custrinfo[i+1].flag & CU_CHINFO_WRAP)==0)
						 ) {
						uloverlap = xtrax + 0.1f;
					}
					// Find the character, the characters has to be in the memory already 
					// since character checking has been done earlier already.
					che= find_vfont_char(vfd, cha);

					twidth = char_width(cu, che, info);
					ulwidth = cu->fsize * ((twidth* (1.0f+(info->kern/40.0f)))+uloverlap);
					build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05f)*cu->fsize,
									ct->xof*cu->fsize + ulwidth, 
									ct->yof*cu->fsize + (cu->ulpos-0.05f)*cu->fsize - cu->ulheight*cu->fsize,
									i, info->mat_nr);
				}
				ct++;
			}
		}
		else {
			int outta = 0;
			for (i= 0; (i<slen) && (outta==0); i++) {
				ascii = mem[i];
				info = &(custrinfo[i]);
				if (cu->sepchar == (i+1)) {
					float vecyo[3];

					vecyo[0]= ct->xof;
					vecyo[1]= ct->yof;
					vecyo[2]= 0.0f;

					mem[0] = ascii;
					mem[1] = 0;
					custrinfo[0]= *info;
					cu->pos = 1;
					cu->len = 1;
					mul_v3_m4v3(ob->loc, ob->obmat, vecyo);
					outta = 1;
					cu->sepchar = 0;
				}
				ct++;
			}
		}
	}

	if (mode==FO_DUPLI) {
		MEM_freeN(mem);
		return chartransdata;
	}

	if (mem)
		MEM_freeN(mem);

	MEM_freeN(chartransdata);
	return NULL;
}
Ejemplo n.º 7
0
static void setNearestAxis3d(TransInfo *t)
{
	float zfac;
	float mvec[3], axis[3], proj[3];
	float len[3];
	int i, icoord[2];

	/* calculate mouse movement */
	mvec[0] = (float)(t->mval[0] - t->con.imval[0]);
	mvec[1] = (float)(t->mval[1] - t->con.imval[1]);
	mvec[2] = 0.0f;

	/* we need to correct axis length for the current zoomlevel of view,
	   this to prevent projected values to be clipped behind the camera
	   and to overflow the short integers.
	   The formula used is a bit stupid, just a simplification of the substraction
	   of two 2D points 30 pixels apart (that's the last factor in the formula) after
	   projecting them with window_to_3d_delta and then get the length of that vector.
	*/
	zfac= t->persmat[0][3]*t->center[0]+ t->persmat[1][3]*t->center[1]+ t->persmat[2][3]*t->center[2]+ t->persmat[3][3];
	zfac = len_v3(t->persinv[0]) * 2.0f/t->ar->winx * zfac * 30.0f;

	for (i = 0; i<3; i++) {
		copy_v3_v3(axis, t->con.mtx[i]);

		mul_v3_fl(axis, zfac);
		/* now we can project to get window coordinate */
		add_v3_v3(axis, t->con.center);
		projectIntView(t, axis, icoord);

		axis[0] = (float)(icoord[0] - t->center2d[0]);
		axis[1] = (float)(icoord[1] - t->center2d[1]);
		axis[2] = 0.0f;

		if (normalize_v3(axis) != 0.0f) {
			project_v3_v3v3(proj, mvec, axis);
			sub_v3_v3v3(axis, mvec, proj);
			len[i] = normalize_v3(axis);
		}
		else {
			len[i] = 10000000000.0f;
		}
	}

	if (len[0] <= len[1] && len[0] <= len[2]) {
		if (t->modifiers & MOD_CONSTRAINT_PLANE) {
			t->con.mode |= (CON_AXIS1|CON_AXIS2);
			sprintf(t->con.text, " locking %s X axis", t->spacename);
		}
		else {
			t->con.mode |= CON_AXIS0;
			sprintf(t->con.text, " along %s X axis", t->spacename);
		}
	}
	else if (len[1] <= len[0] && len[1] <= len[2]) {
		if (t->modifiers & MOD_CONSTRAINT_PLANE) {
			t->con.mode |= (CON_AXIS0|CON_AXIS2);
			sprintf(t->con.text, " locking %s Y axis", t->spacename);
		}
		else {
			t->con.mode |= CON_AXIS1;
			sprintf(t->con.text, " along %s Y axis", t->spacename);
		}
	}
	else if (len[2] <= len[1] && len[2] <= len[0]) {
		if (t->modifiers & MOD_CONSTRAINT_PLANE) {
			t->con.mode |= (CON_AXIS0|CON_AXIS1);
			sprintf(t->con.text, " locking %s Z axis", t->spacename);
		}
		else {
			t->con.mode |= CON_AXIS2;
			sprintf(t->con.text, " along %s Z axis", t->spacename);
		}
	}
}
Ejemplo n.º 8
0
static void do_physical_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force)
{
	PartDeflect *pd = eff->pd;
	RNG *rng = pd->rng;
	float force[3] = {0, 0, 0};
	float temp[3];
	float fac;
	float strength = pd->f_strength;
	float damp = pd->f_damp;
	float noise_factor = pd->f_noise;

	if (noise_factor > 0.0f) {
		strength += wind_func(rng, noise_factor);

		if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG))
			damp += wind_func(rng, noise_factor);
	}

	copy_v3_v3(force, efd->vec_to_point);

	switch (pd->forcefield) {
		case PFIELD_WIND:
			copy_v3_v3(force, efd->nor);
			mul_v3_fl(force, strength * efd->falloff);
			break;
		case PFIELD_FORCE:
			normalize_v3(force);
			mul_v3_fl(force, strength * efd->falloff);
			break;
		case PFIELD_VORTEX:
			/* old vortex force */
			if (pd->shape == PFIELD_SHAPE_POINT) {
				cross_v3_v3v3(force, efd->nor, efd->vec_to_point);
				normalize_v3(force);
				mul_v3_fl(force, strength * efd->distance * efd->falloff);
			}
			else {
				/* new vortex force */
				cross_v3_v3v3(temp, efd->nor2, efd->vec_to_point2);
				mul_v3_fl(temp, strength * efd->falloff);
				
				cross_v3_v3v3(force, efd->nor2, temp);
				mul_v3_fl(force, strength * efd->falloff);
				
				madd_v3_v3fl(temp, point->vel, -point->vel_to_sec);
				add_v3_v3(force, temp);
			}
			break;
		case PFIELD_MAGNET:
			if (eff->pd->shape == PFIELD_SHAPE_POINT)
				/* magnetic field of a moving charge */
				cross_v3_v3v3(temp, efd->nor, efd->vec_to_point);
			else
				copy_v3_v3(temp, efd->nor);

			normalize_v3(temp);
			mul_v3_fl(temp, strength * efd->falloff);
			cross_v3_v3v3(force, point->vel, temp);
			mul_v3_fl(force, point->vel_to_sec);
			break;
		case PFIELD_HARMONIC:
			mul_v3_fl(force, -strength * efd->falloff);
			copy_v3_v3(temp, point->vel);
			mul_v3_fl(temp, -damp * 2.0f * (float)sqrt(fabs(strength)) * point->vel_to_sec);
			add_v3_v3(force, temp);
			break;
		case PFIELD_CHARGE:
			mul_v3_fl(force, point->charge * strength * efd->falloff);
			break;
		case PFIELD_LENNARDJ:
			fac = pow((efd->size + point->size) / efd->distance, 6.0);
			
			fac = - fac * (1.0f - fac) / efd->distance;

			/* limit the repulsive term drastically to avoid huge forces */
			fac = ((fac>2.0f) ? 2.0f : fac);

			mul_v3_fl(force, strength * fac);
			break;
		case PFIELD_BOID:
			/* Boid field is handled completely in boids code. */
			return;
		case PFIELD_TURBULENCE:
			if (pd->flag & PFIELD_GLOBAL_CO) {
				copy_v3_v3(temp, point->loc);
			}
			else {
				add_v3_v3v3(temp, efd->vec_to_point2, efd->nor2);
			}
			force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2, 0, 2);
			force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2, 0, 2);
			force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2, 0, 2);
			mul_v3_fl(force, strength * efd->falloff);
			break;
		case PFIELD_DRAG:
			copy_v3_v3(force, point->vel);
			fac = normalize_v3(force) * point->vel_to_sec;

			strength = MIN2(strength, 2.0f);
			damp = MIN2(damp, 2.0f);

			mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
			break;
		case PFIELD_SMOKEFLOW:
			zero_v3(force);
			if (pd->f_source) {
				float density;
				if ((density = smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
					float influence = strength * efd->falloff;
					if (pd->flag & PFIELD_SMOKE_DENSITY)
						influence *= density;
					mul_v3_fl(force, influence);
					/* apply flow */
					madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence);
				}
			}
			break;

	}

	if (pd->flag & PFIELD_DO_LOCATION) {
		madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec);

		if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) {
			madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
		}
	}

	if (point->ave)
		zero_v3(point->ave);
	if (pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) {
		float xvec[3] = {1.0f, 0.0f, 0.0f};
		float dave[3];
		mul_qt_v3(point->rot, xvec);
		cross_v3_v3v3(dave, xvec, force);
		if (pd->f_flow != 0.0f) {
			madd_v3_v3fl(dave, point->ave, -pd->f_flow * efd->falloff);
		}
		add_v3_v3(point->ave, dave);
	}
}
Ejemplo n.º 9
0
PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
{
	bPoseChannel* pchan = static_cast<bPoseChannel*>(self_v);
	// decompose the pose matrix in euler rotation
	float rest_mat[3][3];
	float pose_mat[3][3];
	float joint_mat[3][3];
	float joints[3];
	float norm;
	double sa, ca;
	// get rotation in armature space
	copy_m3_m4(pose_mat, pchan->pose_mat);
	normalize_m3(pose_mat);
	if (pchan->parent) {
		// bone has a parent, compute the rest pose of the bone taking actual pose of parent
		mul_m3_m3m4(rest_mat, pchan->bone->bone_mat, pchan->parent->pose_mat);
		normalize_m3(rest_mat);
	} else {
		// otherwise, the bone matrix in armature space is the rest pose
		copy_m3_m4(rest_mat, pchan->bone->arm_mat);
	}
	// remove the rest pose to get the joint movement
	transpose_m3(rest_mat);
	mul_m3_m3m3(joint_mat, rest_mat, pose_mat);		
	joints[0] = joints[1] = joints[2] = 0.f;
	// returns a 3 element list that gives corresponding joint
	int flag = 0;
	if (!(pchan->ikflag & BONE_IK_NO_XDOF))
		flag |= 1;
	if (!(pchan->ikflag & BONE_IK_NO_YDOF))
		flag |= 2;
	if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
		flag |= 4;
	switch (flag) {
	case 0:	// fixed joint
		break;
	case 1:	// X only
		mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
		joints[1] = joints[2] = 0.f;
		break;
	case 2:	// Y only
		mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
		joints[0] = joints[2] = 0.f;
		break;
	case 3:	// X+Y
		mat3_to_eulO( joints, EULER_ORDER_ZYX,joint_mat);
		joints[2] = 0.f;
		break;
	case 4:	// Z only
		mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
		joints[0] = joints[1] = 0.f;
		break;
	case 5:	// X+Z
		// decompose this as an equivalent rotation vector in X/Z plane
		joints[0] = joint_mat[1][2];
		joints[2] = -joint_mat[1][0];
		norm = normalize_v3(joints);
		if (norm < FLT_EPSILON) {
			norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f;
		} else {
			norm = acos(joint_mat[1][1]);
		}
		mul_v3_fl(joints, norm);
		break;
	case 6:	// Y+Z
		mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
		joints[0] = 0.f;
		break;
	case 7: // X+Y+Z
		// equivalent axis
		joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f;
		joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f;
		joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f;
		sa = len_v3(joints);
		ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f;
		if (sa > FLT_EPSILON) {
			norm = atan2(sa,ca)/sa;
		} else {
		   if (ca < 0.0) {
			   norm = M_PI;
			   mul_v3_fl(joints,0.f);
			   if (joint_mat[0][0] > 0.f) {
				   joints[0] = 1.0f;
			   } else if (joint_mat[1][1] > 0.f) {
				   joints[1] = 1.0f;
			   } else {
				   joints[2] = 1.0f;
			   }
		   } else {
			   norm = 0.0;
		   }
		}
		mul_v3_fl(joints,norm);
		break;
	}
	return newVectorObject(joints, 3, Py_NEW, NULL);
}
Ejemplo n.º 10
0
static DerivedMesh *arrayModifier_doArray(
        ArrayModifierData *amd,
        Scene *scene, Object *ob, DerivedMesh *dm,
        ModifierApplyFlag flag)
{
	const float eps = 1e-6f;
	const MVert *src_mvert;
	MVert *mv, *mv_prev, *result_dm_verts;

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

	const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0;
	const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge;
	const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob);
	/* allow pole vertices to be used by many faces */
	const bool with_follow = use_offset_ob;

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

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

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

	count = amd->count;

	if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) {
		start_cap_dm = get_dm_for_modifier(amd->start_cap, flag);
		if (start_cap_dm) {
			start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm);
			start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm);
			start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm);
			start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm);
		}
	}
	if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) {
		end_cap_dm = get_dm_for_modifier(amd->end_cap, flag);
		if (end_cap_dm) {
			end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm);
			end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm);
			end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm);
			end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm);
		}
	}

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

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

	if (amd->offset_type & MOD_ARR_OFF_CONST)
		add_v3_v3v3(offset[3], offset[3], amd->offset);

	if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
		for (j = 0; j < 3; j++)
			offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j);
	}

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

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

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

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

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

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

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

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

	if (count < 1)
		count = 1;

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

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

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

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

	/* subsurf for eg wont have mesh data in the
	 * now add mvert/medge/mface layers */

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

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

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

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

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

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

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

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

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

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

		/* Handle merge between chunk n and n-1 */
		if (use_merge && (c >= 1)) {
			if (!offset_has_scale && (c >= 2)) {
				/* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1
				 * ... that is except if scaling makes the distance grow */
				int k;
				int this_chunk_index = c * chunk_nverts;
				int prev_chunk_index = (c - 1) * chunk_nverts;
				for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) {
					int target = full_doubles_map[prev_chunk_index];
					if (target != -1) {
						target += chunk_nverts; /* translate mapping */
						if (full_doubles_map[target] != -1) {
							if (with_follow) {
								target = full_doubles_map[target];
							}
							else {
								/* The rule here is to not follow mapping to chunk N-2, which could be too far
								 * so if target vertex was itself mapped, then this vertex is not mapped */
								target = -1;
							}
						}
					}
					full_doubles_map[this_chunk_index] = target;
				}
			}
			else {
				dm_mvert_map_doubles(
				        full_doubles_map,
				        result_dm_verts,
				        (c - 1) * chunk_nverts,
				        chunk_nverts,
				        c * chunk_nverts,
				        chunk_nverts,
				        amd->merge_dist,
				        with_follow);
			}
		}
	}

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

	copy_m4_m4(final_offset, current_offset);

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

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

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

	/* Handle merging */
	tot_doubles = 0;
	if (use_merge) {
		for (i = 0; i < result_nverts; i++) {
			if (full_doubles_map[i] != -1) {
				if (i == full_doubles_map[i]) {
					full_doubles_map[i] = -1;
				}
				else {
					tot_doubles++;
				}
			}
		}
		if (tot_doubles > 0) {
			result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL);
		}
		MEM_freeN(full_doubles_map);
	}

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

	return result;
}
Ejemplo n.º 11
0
int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity)
{
	float cfra = eff->scene->r.cfra;
	int ret = 0;

	if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) {
		/* closest point in the object surface is an effector */
		float vec[3];

		/* using velocity corrected location allows for easier sliding over effector surface */
		copy_v3_v3(vec, point->vel);
		mul_v3_fl(vec, point->vel_to_frame);
		add_v3_v3(vec, point->loc);

		ret = closest_point_on_surface(eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : NULL);

		efd->size = 0.0f;
	}
	else if (eff->pd && eff->pd->shape==PFIELD_SHAPE_POINTS) {

		if (eff->ob->derivedFinal) {
			DerivedMesh *dm = eff->ob->derivedFinal;

			dm->getVertCo(dm, *efd->index, efd->loc);
			dm->getVertNo(dm, *efd->index, efd->nor);

			mul_m4_v3(eff->ob->obmat, efd->loc);
			mul_mat3_m4_v3(eff->ob->obmat, efd->nor);

			normalize_v3(efd->nor);

			efd->size = 0.0f;

			/**/
			ret = 1;
		}
	}
	else if (eff->psys) {
		ParticleData *pa = eff->psys->particles + *efd->index;
		ParticleKey state;

		/* exclude the particle itself for self effecting particles */
		if (eff->psys == point->psys && *efd->index == point->index) {
			/* pass */
		}
		else {
			ParticleSimulationData sim= {NULL};
			sim.scene= eff->scene;
			sim.ob= eff->ob;
			sim.psys= eff->psys;

			/* TODO: time from actual previous calculated frame (step might not be 1) */
			state.time = cfra - 1.0f;
			ret = psys_get_particle_state(&sim, *efd->index, &state, 0);

			/* TODO */
			//if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) {
			//	if (pa->dietime < eff->psys->cfra)
			//		eff->flag |= PE_VELOCITY_TO_IMPULSE;
			//}

			copy_v3_v3(efd->loc, state.co);

			/* rather than use the velocity use rotated x-axis (defaults to velocity) */
			efd->nor[0] = 1.f;
			efd->nor[1] = efd->nor[2] = 0.f;
			mul_qt_v3(state.rot, efd->nor);
		
			if (real_velocity)
				copy_v3_v3(efd->vel, state.vel);

			efd->size = pa->size;
		}
	}
	else {
		/* use center of object for distance calculus */
		Object *ob = eff->ob;
		Object obcopy = *ob;

		/* use z-axis as normal*/
		normalize_v3_v3(efd->nor, ob->obmat[2]);

		if (eff->pd && eff->pd->shape == PFIELD_SHAPE_PLANE) {
			float temp[3], translate[3];
			sub_v3_v3v3(temp, point->loc, ob->obmat[3]);
			project_v3_v3v3(translate, temp, efd->nor);

			/* for vortex the shape chooses between old / new force */
			if (eff->pd->forcefield == PFIELD_VORTEX)
				add_v3_v3v3(efd->loc, ob->obmat[3], translate);
			else /* normally efd->loc is closest point on effector xy-plane */
				sub_v3_v3v3(efd->loc, point->loc, translate);
		}
		else {
			copy_v3_v3(efd->loc, ob->obmat[3]);
		}

		if (real_velocity)
			copy_v3_v3(efd->vel, eff->velocity);

		*eff->ob = obcopy;

		efd->size = 0.0f;

		ret = 1;
	}

	if (ret) {
		sub_v3_v3v3(efd->vec_to_point, point->loc, efd->loc);
		efd->distance = len_v3(efd->vec_to_point);

		/* rest length for harmonic effector, will have to see later if this could be extended to other effectors */
		if (eff->pd && eff->pd->forcefield == PFIELD_HARMONIC && eff->pd->f_size)
			mul_v3_fl(efd->vec_to_point, (efd->distance-eff->pd->f_size)/efd->distance);

		if (eff->flag & PE_USE_NORMAL_DATA) {
			copy_v3_v3(efd->vec_to_point2, efd->vec_to_point);
			copy_v3_v3(efd->nor2, efd->nor);
		}
		else {
			/* for some effectors we need the object center every time */
			sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]);
			normalize_v3_v3(efd->nor2, eff->ob->obmat[2]);
		}
	}

	return ret;
}
Ejemplo n.º 12
0
static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr, float *rad)
{
	ShadeInput *shi= ssamp->shi;
	ShadeResult *shr= ssamp->shr;
	float l, u, v, *v1, *v2, *v3;
	
	/* init */
	if(vlr->v4) {
		shi->u= u= 0.5f;
		shi->v= v= 0.5f;
	}
	else {
		shi->u= u= 1.0f/3.0f;
		shi->v= v= 1.0f/3.0f;
	}

	/* setup render coordinates */
	v1= vlr->v1->co;
	v2= vlr->v2->co;
	v3= vlr->v3->co;
	
	/* renderco */
	l= 1.0f-u-v;
	
	shi->co[0]= l*v3[0]+u*v1[0]+v*v2[0];
	shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1];
	shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2];

	shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);

	/* set up view vector */
	copy_v3_v3(shi->view, shi->co);
	normalize_v3(shi->view);
	
	/* cache for shadow */
	shi->samplenr++;
	
	shi->xs= 0; // TODO
	shi->ys= 0;
	
	shade_input_set_normals(shi);

	/* no normal flip */
	if(shi->flippednor)
		shade_input_flip_normals(shi);

	madd_v3_v3fl(shi->co, shi->vn, 0.0001f); /* ugly.. */

	/* not a pretty solution, but fixes common cases */
	if(shi->obr->ob && shi->obr->ob->transflag & OB_NEG_SCALE) {
		negate_v3(shi->vn);
		negate_v3(shi->vno);
		negate_v3(shi->nmapnorm);
	}

	/* init material vars */
	// note, keep this synced with render_types.h
	memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
	shi->har= shi->mat->har;
	
	/* render */
	shade_input_set_shade_texco(shi);
	shade_material_loop(shi, shr); /* todo: nodes */
	
	copy_v3_v3(rad, shr->combined);
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
0
static int  RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
{
	InstanceRayObject *obj = (InstanceRayObject*)o;
	float start[3], dir[3], idot_axis[3], dist;
	int changed = 0, i, res;
	
	// TODO - this is disabling self intersection on instances
	if(isec->orig.ob == obj->ob && obj->ob)
	{
		changed = 1;
		isec->orig.ob = obj->target_ob;
	}
	
	// backup old values
	copy_v3_v3(start, isec->start);
	copy_v3_v3(dir, isec->dir);
	copy_v3_v3(idot_axis, isec->idot_axis);
	dist = isec->dist;

	// transform to target coordinates system
	mul_m4_v3(obj->global2target, isec->start);
	mul_mat3_m4_v3(obj->global2target, isec->dir);
	isec->dist *= normalize_v3(isec->dir);
	
	// update idot_axis and bv_index
	for(i=0; i<3; i++)
	{
		isec->idot_axis[i]		= 1.0f / isec->dir[i];
		
		isec->bv_index[2*i]		= isec->idot_axis[i] < 0.0 ? 1 : 0;
		isec->bv_index[2*i+1]	= 1 - isec->bv_index[2*i];
		
		isec->bv_index[2*i]		= i+3*isec->bv_index[2*i];
		isec->bv_index[2*i+1]	= i+3*isec->bv_index[2*i+1];
	}

	// raycast
	res = RE_rayobject_intersect(obj->target, isec);

	// map dist into original coordinate space
	if(res == 0)
	{
		isec->dist = dist;
	}
	else
	{
		// note we don't just multiply dist, because of possible
		// non-uniform scaling in the transform matrix
		float vec[3];

		mul_v3_v3fl(vec, isec->dir, isec->dist);
		mul_mat3_m4_v3(obj->target2global, vec);

		isec->dist = len_v3(vec);
		isec->hit.ob = obj->ob;

#ifdef RT_USE_LAST_HIT	
		// TODO support for last hit optimization in instances that can jump
		// directly to the last hit face.
		// For now it jumps directly to the last-hit instance root node.
		isec->last_hit = RE_rayobject_unalignRayAPI((RayObject*) obj);
#endif
	}

	// restore values
	copy_v3_v3(isec->start, start);
	copy_v3_v3(isec->dir, dir);
	copy_v3_v3(isec->idot_axis, idot_axis);
	
	if(changed)
		isec->orig.ob = obj->ob;

	// restore bv_index
	for(i=0; i<3; i++)
	{
		isec->bv_index[2*i]		= isec->idot_axis[i] < 0.0 ? 1 : 0;
		isec->bv_index[2*i+1]	= 1 - isec->bv_index[2*i];
		
		isec->bv_index[2*i]		= i+3*isec->bv_index[2*i];
		isec->bv_index[2*i+1]	= i+3*isec->bv_index[2*i+1];
	}
		
	return res;
}
Ejemplo n.º 15
0
static int walkApply(bContext *C, WalkInfo *walk)
{
#define WALK_ROTATE_FAC 2.2f /* more is faster */
#define WALK_TOP_LIMIT DEG2RADF(85.0f)
#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
#define WALK_MOVE_SPEED base_speed
#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)

	/* walk mode - Ctrl+Shift+F
	 * a walk loop where the user can move move the view as if they are in a walk game
	 */
	RegionView3D *rv3d = walk->rv3d;
	ARegion *ar = walk->ar;

	float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */
	float dvec[3] = {0.0f, 0.0f, 0.0f}; /* this is the direction that's added to the view offset per redraw */

	/* Camera Uprighting variables */
	float upvec[3] = {0.0f, 0.0f, 0.0f}; /* stores the view's up vector */

	int moffset[2]; /* mouse offset from the views center */
	float tmp_quat[4]; /* used for rotating the view */

#ifdef NDOF_WALK_DEBUG
	{
		static unsigned int iteration = 1;
		printf("walk timer %d\n", iteration++);
	}
#endif

	{
		/* mouse offset from the center */
		copy_v2_v2_int(moffset, walk->moffset);

		/* apply moffset so we can re-accumulate */
		walk->moffset[0] = 0;
		walk->moffset[1] = 0;

		/* revert mouse */
		if (walk->is_reversed) {
			moffset[1] = -moffset[1];
		}

		/* Should we redraw? */
		if ((walk->active_directions) ||
		    moffset[0] || moffset[1] ||
		    walk->teleport.state == WALK_TELEPORT_STATE_ON ||
		    walk->gravity_state != WALK_GRAVITY_STATE_OFF)
		{
			float dvec_tmp[3];

			/* time how fast it takes for us to redraw,
			 * this is so simple scenes don't walk too fast */
			double time_current;
			float time_redraw;
#ifdef NDOF_WALK_DRAW_TOOMUCH
			walk->redraw = 1;
#endif
			time_current = PIL_check_seconds_timer();
			time_redraw = (float)(time_current - walk->time_lastdraw);

			walk->time_lastdraw = time_current;

			/* base speed in m/s */
			walk->speed = WALK_MOVE_SPEED;

			if (walk->is_fast) {
				walk->speed *= WALK_BOOST_FACTOR;
			}
			else if (walk->is_slow) {
				walk->speed *= 1.0f / WALK_BOOST_FACTOR;
			}

			copy_m3_m4(mat, rv3d->viewinv);

			{
				/* rotate about the X axis- look up/down */
				if (moffset[1]) {
					float angle;
					float y;

					/* relative offset */
					y = (float) moffset[1] / ar->winy;

					/* speed factor */
					y *= WALK_ROTATE_FAC;

					/* user adjustement factor */
					y *= walk->mouse_speed;

					/* clamp the angle limits */
					/* it ranges from 90.0f to -90.0f */
					angle = -asinf(rv3d->viewmat[2][2]);

					if (angle > WALK_TOP_LIMIT && y > 0.0f)
						y = 0.0f;

					else if (angle < WALK_BOTTOM_LIMIT && y < 0.0f)
						y = 0.0f;

					copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
					mul_m3_v3(mat, upvec);
					/* Rotate about the relative up vec */
					axis_angle_to_quat(tmp_quat, upvec, -y);
					mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
				}

				/* rotate about the Y axis- look left/right */
				if (moffset[0]) {
					float x;

					/* if we're upside down invert the moffset */
					copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f);
					mul_m3_v3(mat, upvec);

					if (upvec[2] < 0.0f)
						moffset[0] = -moffset[0];

					/* relative offset */
					x = (float) moffset[0] / ar->winx;

					/* speed factor */
					x *= WALK_ROTATE_FAC;

					/* user adjustement factor */
					x *= walk->mouse_speed;

					copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);

					/* Rotate about the relative up vec */
					axis_angle_normalized_to_quat(tmp_quat, upvec, x);
					mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
				}
			}

			/* WASD - 'move' translation code */
			if ((walk->active_directions) &&
			    (walk->gravity_state == WALK_GRAVITY_STATE_OFF))
			{

				short direction;
				zero_v3(dvec);

				if ((walk->active_directions & WALK_BIT_FORWARD) ||
				    (walk->active_directions & WALK_BIT_BACKWARD))
				{

					direction = 0;

					if ((walk->active_directions & WALK_BIT_FORWARD))
						direction += 1;

					if ((walk->active_directions & WALK_BIT_BACKWARD))
						direction -= 1;

					copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction);
					mul_m3_v3(mat, dvec_tmp);

					if (walk->navigation_mode == WALK_MODE_GRAVITY) {
						dvec_tmp[2] = 0.0f;
					}

					normalize_v3(dvec_tmp);
					add_v3_v3(dvec, dvec_tmp);

				}

				if ((walk->active_directions & WALK_BIT_LEFT) ||
				    (walk->active_directions & WALK_BIT_RIGHT))
				{

					direction = 0;

					if ((walk->active_directions & WALK_BIT_LEFT))
						direction += 1;

					if ((walk->active_directions & WALK_BIT_RIGHT))
						direction -= 1;

					dvec_tmp[0] = direction * rv3d->viewinv[0][0];
					dvec_tmp[1] = direction * rv3d->viewinv[0][1];
					dvec_tmp[2] = 0.0f;

					normalize_v3(dvec_tmp);
					add_v3_v3(dvec, dvec_tmp);

				}

				if ((walk->active_directions & WALK_BIT_UP) ||
				    (walk->active_directions & WALK_BIT_DOWN))
				{

					if (walk->navigation_mode == WALK_MODE_FREE) {

						direction = 0;

						if ((walk->active_directions & WALK_BIT_UP))
							direction -= 1;

						if ((walk->active_directions & WALK_BIT_DOWN))
							direction = 1;

						copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction);
						add_v3_v3(dvec, dvec_tmp);
					}
				}

				/* apply movement */
				mul_v3_fl(dvec, walk->speed * time_redraw);
			}

			/* stick to the floor */
			if (walk->navigation_mode == WALK_MODE_GRAVITY &&
			    ELEM(walk->gravity_state,
			         WALK_GRAVITY_STATE_OFF,
			         WALK_GRAVITY_STATE_START))
			{

				bool ret;
				float ray_distance;
				float difference = -100.0f;
				float fall_distance;

				ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance);

				if (ret) {
					difference = walk->view_height - ray_distance;
				}

				/* the distance we would fall naturally smoothly enough that we
				 * can manually drop the object without activating gravity */
				fall_distance = time_redraw * walk->speed * WALK_BOOST_FACTOR;

				if (fabsf(difference) < fall_distance) {
					/* slope/stairs */
					dvec[2] -= difference;

					/* in case we switched from FREE to GRAVITY too close to the ground */
					if (walk->gravity_state == WALK_GRAVITY_STATE_START)
						walk->gravity_state = WALK_GRAVITY_STATE_OFF;
				}
				else {
					/* hijack the teleport variables */
					walk->teleport.initial_time = PIL_check_seconds_timer();
					walk->gravity_state = WALK_GRAVITY_STATE_ON;
					walk->teleport.duration = 0.0f;

					copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]);
					copy_v2_v2(walk->teleport.direction, dvec);

				}
			}

			/* Falling or jumping) */
			if (ELEM(walk->gravity_state, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) {
				float t;
				float z_cur, z_new;
				bool ret;
				float ray_distance, difference = -100.0f;

				/* delta time */
				t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time);

				/* keep moving if we were moving */
				copy_v2_v2(dvec, walk->teleport.direction);

				z_cur = walk->rv3d->viewinv[3][2];
				z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid;

				/* jump */
				z_new += t * walk->speed_jump * walk->grid;

				/* duration is the jump duration */
				if (t > walk->teleport.duration) {

					/* check to see if we are landing */
					ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance);

					if (ret) {
						difference = walk->view_height - ray_distance;
					}

					if (difference > 0.0f) {
						/* quit falling, lands at "view_height" from the floor */
						dvec[2] -= difference;
						walk->gravity_state = WALK_GRAVITY_STATE_OFF;
						walk->speed_jump = 0.0f;
					}
					else {
						/* keep falling */
						dvec[2] = z_cur - z_new;
					}
				}
				else {
					/* keep going up (jump) */
					dvec[2] = z_cur - z_new;
				}
			}

			/* Teleport */
			else if (walk->teleport.state == WALK_TELEPORT_STATE_ON) {
				float t; /* factor */
				float new_loc[3];
				float cur_loc[3];

				/* linear interpolation */
				t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time);
				t /= walk->teleport.duration;

				/* clamp so we don't go past our limit */
				if (t >= 1.0f) {
					t = 1.0f;
					walk->teleport.state = WALK_TELEPORT_STATE_OFF;
					walk_navigation_mode_set(C, walk, walk->teleport.navigation_mode);
				}

				mul_v3_v3fl(new_loc, walk->teleport.direction, t);
				add_v3_v3(new_loc, walk->teleport.origin);

				copy_v3_v3(cur_loc, walk->rv3d->viewinv[3]);
				sub_v3_v3v3(dvec, cur_loc, new_loc);
			}

			if (rv3d->persp == RV3D_CAMOB) {
				Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control);
				if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0f;
				if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0f;
				if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0f;
			}

			/* scale the movement to the scene size */
			mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
			add_v3_v3(rv3d->ofs, dvec_tmp);

			if (rv3d->persp == RV3D_CAMOB) {
				const bool do_rotate = (moffset[0] || moffset[1]);
				const bool do_translate = (walk->speed != 0.0f);
				walkMoveCamera(C, walk, do_rotate, do_translate);
			}
		}
		else {
			/* we're not redrawing but we need to update the time else the view will jump */
			walk->time_lastdraw = PIL_check_seconds_timer();
		}
		/* end drawing */
		copy_v3_v3(walk->dvec_prev, dvec);
	}

	return OPERATOR_FINISHED;
#undef WALK_ROTATE_FAC
#undef WALK_ZUP_CORRECT_FAC
#undef WALK_ZUP_CORRECT_ACCEL
#undef WALK_SMOOTH_FAC
#undef WALK_TOP_LIMIT
#undef WALK_BOTTOM_LIMIT
#undef WALK_MOVE_SPEED
#undef WALK_BOOST_FACTOR
}
Ejemplo n.º 16
0
static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
{
	if (data && node->id) {
		ShadeResult shrnode;
		ShadeInput *shi;
		ShaderCallData *shcd= data;
		float col[4];
		bNodeSocket *sock;
		char hasinput[NUM_MAT_IN] = {'\0'};
		int i, mode;
		
		/* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
		 * the constant input stack values (e.g. in case material node is inside a group).
		 * we just want to know if a node input uses external data or the material setting.
		 * this is an ugly hack, but so is this node as a whole.
		 */
		for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i)
			hasinput[i] = (sock->link != NULL);
		
		shi= shcd->shi;
		shi->mat= (Material *)node->id;
		
		/* copy all relevant material vars, note, keep this synced with render_types.h */
		memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
		shi->har= shi->mat->har;
		
		/* write values */
		if (hasinput[MAT_IN_COLOR])
			nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
		
		if (hasinput[MAT_IN_SPEC])
			nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
		
		if (hasinput[MAT_IN_REFL])
			nodestack_get_vec(&shi->refl, SOCK_FLOAT, in[MAT_IN_REFL]);
		
		/* retrieve normal */
		if (hasinput[MAT_IN_NORMAL]) {
			nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
			normalize_v3(shi->vn);
		}
		else
			copy_v3_v3(shi->vn, shi->vno);
		
		/* custom option to flip normal */
		if (node->custom1 & SH_NODE_MAT_NEG) {
			negate_v3(shi->vn);
		}
		
		if (node->type == SH_NODE_MATERIAL_EXT) {
			if (hasinput[MAT_IN_MIR])
				nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
			if (hasinput[MAT_IN_AMB])
				nodestack_get_vec(&shi->amb, SOCK_FLOAT, in[MAT_IN_AMB]);
			if (hasinput[MAT_IN_EMIT])
				nodestack_get_vec(&shi->emit, SOCK_FLOAT, in[MAT_IN_EMIT]);
			if (hasinput[MAT_IN_SPECTRA])
				nodestack_get_vec(&shi->spectra, SOCK_FLOAT, in[MAT_IN_SPECTRA]);
			if (hasinput[MAT_IN_RAY_MIRROR])
				nodestack_get_vec(&shi->ray_mirror, SOCK_FLOAT, in[MAT_IN_RAY_MIRROR]);
			if (hasinput[MAT_IN_ALPHA])
				nodestack_get_vec(&shi->alpha, SOCK_FLOAT, in[MAT_IN_ALPHA]);
			if (hasinput[MAT_IN_TRANSLUCENCY])
				nodestack_get_vec(&shi->translucency, SOCK_FLOAT, in[MAT_IN_TRANSLUCENCY]);
		}
		
		/* make alpha output give results even if transparency is only enabled on
		 * the material linked in this not and not on the parent material */
		mode = shi->mode;
		if (shi->mat->mode & MA_TRANSP)
			shi->mode |= MA_TRANSP;

		shi->nodes= 1; /* temp hack to prevent trashadow recursion */
		node_shader_lamp_loop(shi, &shrnode);	/* clears shrnode */
		shi->nodes= 0;
		
		shi->mode = mode;

		/* write to outputs */
		if (node->custom1 & SH_NODE_MAT_DIFF) {
			copy_v3_v3(col, shrnode.combined);
			if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
				sub_v3_v3(col, shrnode.spec);
			}
		}
		else if (node->custom1 & SH_NODE_MAT_SPEC) {
			copy_v3_v3(col, shrnode.spec);
		}
		else
			col[0] = col[1] = col[2] = 0.0f;
		
		col[3] = shrnode.alpha;
		
		if (shi->do_preview)
			nodeAddToPreview(node, col, shi->xs, shi->ys, shi->do_manage);
		
		copy_v3_v3(out[MAT_OUT_COLOR]->vec, col);
		out[MAT_OUT_ALPHA]->vec[0] = shrnode.alpha;
		
		if (node->custom1 & SH_NODE_MAT_NEG) {
			shi->vn[0] = -shi->vn[0];
			shi->vn[1] = -shi->vn[1];
			shi->vn[2] = -shi->vn[2];
		}
		
		copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn);
		
		/* Extended material options */
		if (node->type == SH_NODE_MATERIAL_EXT) {
			/* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
			 * a node tree :( */
			copy_v3_v3(out[MAT_OUT_DIFFUSE]->vec, shrnode.diff);
			copy_v3_v3(out[MAT_OUT_SPEC]->vec, shrnode.spec);
			copy_v3_v3(out[MAT_OUT_AO]->vec, shrnode.ao);
		}
		
		/* copy passes, now just active node */
		if (node->flag & NODE_ACTIVE_ID) {
			float combined[4], alpha;

			copy_v4_v4(combined, shcd->shr->combined);
			alpha= shcd->shr->alpha;

			*(shcd->shr)= shrnode;

			copy_v4_v4(shcd->shr->combined, combined);
			shcd->shr->alpha= alpha;
		}
	}
}
Ejemplo n.º 17
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;
}
Ejemplo n.º 18
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DerivedMesh *dm = derivedData, *result;
	ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
	ParticleSimulationData sim;
	ParticleSystem *psys = NULL;
	ParticleData *pa = NULL;
	MPoly *mpoly, *orig_mpoly;
	MLoop *mloop, *orig_mloop;
	MVert *mvert, *orig_mvert;
	int totvert, totpoly, totloop /* , totedge */;
	int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0;
	int k, p, p_skip;
	short track = ob->trackflag % 3, trackneg, axis = pimd->axis;
	float max_co = 0.0, min_co = 0.0, temp_co[3];
	float *size = NULL;

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

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

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

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

	if (totpart == 0)
		return derivedData;

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

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

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

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

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

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

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

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

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

	psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);

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

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

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

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

	for (p = 0, p_skip = 0; p < totpart; p++) {
		float prev_dir[3];
		float frame[4]; /* frame orientation quaternion */
		
		/* skip particle? */
		if (particle_skip(pimd, psys, p))
			continue;

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

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

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

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

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

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

					mv->co[axis] = 0.0;
				}

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

				normalize_v3(state.vel);

				/* Incrementally Rotating Frame (Bishop Frame) */
				if (k == 0) {
					float hairmat[4][4];
					float mat[3][3];
					
					if (first_particle + p < psys->totpart)
						pa = psys->particles + first_particle + p;
					else {
						ChildParticle *cpa = psys->child + (p - psys->totpart);
						pa = psys->particles + cpa->parent;
					}
					psys_mat_hair_to_global(sim.ob, sim.psmd->dm, sim.psys->part->from, pa, hairmat);
					copy_m3_m4(mat, hairmat);
					/* to quaternion */
					mat3_to_quat(frame, mat);
					
					/* note: direction is same as normal vector currently,
					 * but best to keep this separate so the frame can be
					 * rotated later if necessary
					 */
					copy_v3_v3(prev_dir, state.vel);
				}
				else {
					float rot[4];
					
					/* incrementally rotate along bend direction */
					rotation_between_vecs_to_quat(rot, prev_dir, state.vel);
					mul_qt_qtqt(frame, rot, frame);
					
					copy_v3_v3(prev_dir, state.vel);
				}
				
				copy_qt_qt(state.rot, frame);
#if 0
				/* Absolute Frame (Frenet Frame) */
				if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
					unit_qt(state.rot);
				}
				else {
					float cross[3];
					float temp[3] = {0.0f, 0.0f, 0.0f};
					temp[axis] = 1.0f;
					
					cross_v3_v3v3(cross, temp, state.vel);
					
					/* state.vel[axis] is the only component surviving from a dot product with the axis */
					axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis]));
				}
#endif
			}
			else {
				state.time = -1.0;
				psys_get_particle_state(&sim, first_particle + p, &state, 1);
			}

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

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

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

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

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

		p_skip++;
	}

	CDDM_calc_edges(result);

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

	if (size)
		MEM_freeN(size);

	result->dirty |= DM_DIRTY_NORMALS;

	return result;
}
Ejemplo n.º 19
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;

		copy_v3_v3(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) {
			copy_v3_v3(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;
		}
	}
}
Ejemplo n.º 20
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;
}
Ejemplo n.º 21
0
/* axis is using another define!!! */
static int calc_curve_deform(Scene *scene, Object *par, float co[3],
                             const short axis, CurveDeform *cd, float quat_r[4])
{
	Curve *cu = par->data;
	float fac, loc[4], dir[3], new_quat[4], radius;
	short index;
	const int is_neg_axis = (axis > 2);

	/* to be sure, mostly after file load */
	if (cu->path == NULL) {
		BKE_displist_make_curveTypes(scene, par, 0);
		if (cu->path == NULL) return 0;  // happens on append...
	}
	
	/* options */
	if (is_neg_axis) {
		index = axis - 3;
		if (cu->flag & CU_STRETCH)
			fac = (-co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
		else
			fac = -(co[index] - cd->dmax[index]) / (cu->path->totdist);
	}
	else {
		index = axis;
		if (cu->flag & CU_STRETCH)
			fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
		else
			fac = +(co[index] - cd->dmin[index]) / (cu->path->totdist);
	}
	
	if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) {  /* returns OK */
		float quat[4], cent[3];

		if (cd->no_rot_axis) {  /* set by caller */

			/* this is not exactly the same as 2.4x, since the axis is having rotation removed rather than
			 * changing the axis before calculating the tilt but serves much the same purpose */
			float dir_flat[3] = {0, 0, 0}, q[4];
			copy_v3_v3(dir_flat, dir);
			dir_flat[cd->no_rot_axis - 1] = 0.0f;

			normalize_v3(dir);
			normalize_v3(dir_flat);

			rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */

			mul_qt_qtqt(new_quat, q, new_quat);
		}


		/* Logic for 'cent' orientation *
		 *
		 * The way 'co' is copied to 'cent' may seem to have no meaning, but it does.
		 *
		 * Use a curve modifier to stretch a cube out, color each side RGB, positive side light, negative dark.
		 * view with X up (default), from the angle that you can see 3 faces RGB colors (light), anti-clockwise
		 * Notice X,Y,Z Up all have light colors and each ordered CCW.
		 *
		 * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell
		 *
		 * note: moved functions into quat_apply_track/vec_apply_track
		 * */
		copy_qt_qt(quat, new_quat);
		copy_v3_v3(cent, co);

		/* zero the axis which is not used,
		 * the big block of text above now applies to these 3 lines */
		quat_apply_track(quat, axis, (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */
		vec_apply_track(cent, axis);
		cent[index] = 0.0f;


		/* scale if enabled */
		if (cu->flag & CU_PATH_RADIUS)
			mul_v3_fl(cent, radius);
		
		/* local rotation */
		normalize_qt(quat);
		mul_qt_v3(quat, cent);

		/* translation */
		add_v3_v3v3(co, cent, loc);

		if (quat_r)
			copy_qt_qt(quat_r, quat);

		return 1;
	}
	return 0;
}
Ejemplo n.º 22
0
/**
 * This function converts an object space normal map to a tangent space normal map for a given low poly mesh
 */
void RE_bake_normal_world_to_tangent(
        const BakePixel pixel_array[], const size_t num_pixels, const int depth,
        float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3],
        float mat[4][4])
{
	size_t i;

	TriTessFace *triangles;

	DerivedMesh *dm = CDDM_from_mesh(me);

	triangles = mesh_calc_tri_tessface(me, true, dm);

	BLI_assert(num_pixels >= 3);

	for (i = 0; i < num_pixels; i++) {
		TriTessFace *triangle;
		float tangents[3][3];
		float normals[3][3];
		float signs[3];
		int j;

		float tangent[3];
		float normal[3];
		float binormal[3];
		float sign;
		float u, v, w;

		float tsm[3][3]; /* tangent space matrix */
		float itsm[3][3];

		size_t offset;
		float nor[3]; /* texture normal */

		bool is_smooth;

		int primitive_id = pixel_array[i].primitive_id;

		offset = i * depth;

		if (primitive_id == -1) {
			copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f);
			continue;
		}

		triangle = &triangles[primitive_id];
		is_smooth = triangle->is_smooth;

		for (j = 0; j < 3; j++) {
			const TSpace *ts;

			if (is_smooth)
				normal_short_to_float_v3(normals[j], triangle->mverts[j]->no);
			else
				normal[j] = triangle->normal[j];

			ts = triangle->tspace[j];
			copy_v3_v3(tangents[j], ts->tangent);
			signs[j] = ts->sign;
		}

		u = pixel_array[i].uv[0];
		v = pixel_array[i].uv[1];
		w = 1.0f - u - v;

		/* normal */
		if (is_smooth)
			interp_barycentric_tri_v3(normals, u, v, normal);

		/* tangent */
		interp_barycentric_tri_v3(tangents, u, v, tangent);

		/* sign */
		/* The sign is the same at all face vertices for any non degenerate face.
		 * Just in case we clamp the interpolated value though. */
		sign = (signs[0]  * u + signs[1]  * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f;

		/* binormal */
		/* B = sign * cross(N, T)  */
		cross_v3_v3v3(binormal, normal, tangent);
		mul_v3_fl(binormal, sign);

		/* populate tangent space matrix */
		copy_v3_v3(tsm[0], tangent);
		copy_v3_v3(tsm[1], binormal);
		copy_v3_v3(tsm[2], normal);

		/* texture values */
		normal_uncompress(nor, &result[offset]);

		/* converts from world space to local space */
		mul_transposed_mat3_m4_v3(mat, nor);

		invert_m3_m3(itsm, tsm);
		mul_m3_v3(itsm, nor);
		normalize_v3(nor);

		/* save back the values */
		normal_compress(&result[offset], nor, normal_swizzle);
	}

	/* garbage collection */
	MEM_freeN(triangles);

	if (dm)
		dm->release(dm);
}
Ejemplo n.º 23
0
/* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't 
 * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light 
 * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct,
 * it also makes it harder to control the overall look of the volume since coloring the outscattered light results
 * in the inverse color being transmitted through the rest of the volume.
 */
static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co[3], const float endco[3])
{
	float radiance[3] = {0.f, 0.f, 0.f};
	float tr[3] = {1.f, 1.f, 1.f};
	float p[3] = {co[0], co[1], co[2]};
	float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
	const float stepsize = shi->mat->vol.stepsize;
	
	float t0 = 0.f;
	float pt0 = t0;
	float t1 = normalize_v3(step_vec);  /* returns vector length */
	
	t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
	p[0] += t0 * step_vec[0];
	p[1] += t0 * step_vec[1];
	p[2] += t0 * step_vec[2];
	mul_v3_fl(step_vec, stepsize);
	
	for (; t0 < t1; pt0 = t0, t0 += stepsize) {
		const float density = vol_get_density(shi, p);
		
		if (density > 0.00001f) {
			float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3];
			const float stepd = (t0 - pt0) * density;
			
			/* transmittance component (alpha) */
			vol_get_transmittance_seg(shi, tr, stepsize, co, density);
			
			if (t0 > t1 * 0.25f) {
				/* only use depth cutoff after we've traced a little way into the volume */
				if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break;
			}
			
			vol_get_emission(shi, emit_col, p);
			
			if (shi->obi->volume_precache) {
				float p2[3];
				
				p2[0] = p[0] + (step_vec[0] * 0.5f);
				p2[1] = p[1] + (step_vec[1] * 0.5f);
				p2[2] = p[2] + (step_vec[2] * 0.5f);
				
				vol_get_precached_scattering(&R, shi, scatter_col, p2);
			}
			else
				vol_get_scattering(shi, scatter_col, p, shi->view);
			
			radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]);
			radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]);
			radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]);
		}
		add_v3_v3(p, step_vec);
	}
	
	/* multiply original color (from behind volume) with transmittance over entire distance */
	mul_v3_v3v3(col, tr, col);
	add_v3_v3(col, radiance);
	
	/* alpha <-- transmission luminance */
	col[3] = 1.0f - IMB_colormanagement_get_luminance(tr);
}
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]);
		}
	}
}
Ejemplo n.º 25
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);
}
Ejemplo n.º 26
0
static void sphere_do(
        CastModifierData *cmd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	MDeformVert *dvert = NULL;

	Object *ctrl_ob = NULL;

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

	flag = cmd->flag;
	type = cmd->type; /* projection type: sphere or cylinder */

	if (type == MOD_CAST_TYPE_CYLINDER) 
		flag &= ~MOD_CAST_Z;

	ctrl_ob = cmd->object;

	/* spherify's center is {0, 0, 0} (the ob's own center in its local
	 * space), by default, but if the user defined a control object,
	 * we use its location, transformed to ob's local space */
	if (ctrl_ob) {
		if (flag & MOD_CAST_USE_OB_TRANSFORM) {
			invert_m4_m4(imat, ctrl_ob->obmat);
			mul_m4_m4m4(mat, imat, ob->obmat);
			invert_m4_m4(imat, mat);
		}

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

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

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

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

	if (flag & MOD_CAST_SIZE_FROM_RADIUS) {
		len = cmd->radius;
	}
	else {
		len = cmd->size;
	}

	if (len <= 0) {
		for (i = 0; i < numVerts; i++) {
			len += len_v3v3(center, vertexCos[i]);
		}
		len /= numVerts;

		if (len == 0.0f) len = 10.0f;
	}

	for (i = 0; i < numVerts; i++) {
		float tmp_co[3];

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

		copy_v3_v3(vec, tmp_co);

		if (type == MOD_CAST_TYPE_CYLINDER)
			vec[2] = 0.0f;

		if (has_radius) {
			if (len_v3(vec) > cmd->radius) continue;
		}

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

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

		normalize_v3(vec);

		if (flag & MOD_CAST_X)
			tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0];
		if (flag & MOD_CAST_Y)
			tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1];
		if (flag & MOD_CAST_Z)
			tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2];

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

		copy_v3_v3(vertexCos[i], tmp_co);
	}
}
Ejemplo n.º 27
0
/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
{
	BoidRule *rule;
	BoidSettings *boids = bbd->part->boids;
	BoidValues val;
	BoidState *state = get_boid_state(boids, pa);
	BoidParticle *bpa = pa->boid;
	ParticleSystem *psys = bbd->sim->psys;
	int rand;
	//BoidCondition *cond;

	if (bpa->data.health <= 0.0f) {
		pa->alive = PARS_DYING;
		pa->dietime = bbd->cfra;
		return;
	}

	//planned for near future
	//cond = state->conditions.first;
	//for (; cond; cond=cond->next) {
	//	if (boid_condition_is_true(cond)) {
	//		pa->boid->state_id = cond->state_id;
	//		state = get_boid_state(boids, pa);
	//		break; /* only first true condition is used */
	//	}
	//}

	zero_v3(bbd->wanted_co);
	bbd->wanted_speed = 0.0f;

	/* create random seed for every particle & frame */
	rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
	rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);

	set_boid_values(&val, bbd->part->boids, pa);

	/* go through rules */
	switch (state->ruleset_type) {
		case eBoidRulesetType_Fuzzy:
		{
			for (rule = state->rules.first; rule; rule = rule->next) {
				if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
					break; /* only first nonzero rule that comes through fuzzy rule is applied */
			}
			break;
		}
		case eBoidRulesetType_Random:
		{
			/* use random rule for each particle (always same for same particle though) */
			rule = BLI_findlink(&state->rules, rand % BLI_listbase_count(&state->rules));

			apply_boid_rule(bbd, rule, &val, pa, -1.0);
			break;
		}
		case eBoidRulesetType_Average:
		{
			float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
			int n = 0;
			for (rule = state->rules.first; rule; rule=rule->next) {
				if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
					add_v3_v3(wanted_co, bbd->wanted_co);
					wanted_speed += bbd->wanted_speed;
					n++;
					zero_v3(bbd->wanted_co);
					bbd->wanted_speed = 0.0f;
				}
			}

			if (n > 1) {
				mul_v3_fl(wanted_co, 1.0f/(float)n);
				wanted_speed /= (float)n;
			}

			copy_v3_v3(bbd->wanted_co, wanted_co);
			bbd->wanted_speed = wanted_speed;
			break;
		}

	}

	/* decide on jumping & liftoff */
	if (bpa->data.mode == eBoidMode_OnLand) {
		/* fuzziness makes boids capable of misjudgement */
		float mul = 1.0f + state->rule_fuzziness;
		
		if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
			float cvel[3], dir[3];

			copy_v3_v3(dir, pa->prev_state.ave);
			normalize_v2(dir);

			copy_v3_v3(cvel, bbd->wanted_co);
			normalize_v2(cvel);

			if (dot_v2v2(cvel, dir) > 0.95f / mul)
				bpa->data.mode = eBoidMode_Liftoff;
		}
		else if (val.jump_speed > 0.0f) {
			float jump_v[3];
			int jump = 0;

			/* jump to get to a location */
			if (bbd->wanted_co[2] > 0.0f) {
				float cvel[3], dir[3];
				float z_v, ground_v, cur_v;
				float len;

				copy_v3_v3(dir, pa->prev_state.ave);
				normalize_v2(dir);

				copy_v3_v3(cvel, bbd->wanted_co);
				normalize_v2(cvel);

				len = len_v2(pa->prev_state.vel);

				/* first of all, are we going in a suitable direction? */
				/* or at a suitably slow speed */
				if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
					/* try to reach goal at highest point of the parabolic path */
					cur_v = len_v2(pa->prev_state.vel);
					z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
					ground_v = len_v2(bbd->wanted_co)*sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / bbd->wanted_co[2]);

					len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v);

					if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
						jump = 1;

						len = MIN2(len, val.jump_speed);

						copy_v3_v3(jump_v, dir);
						jump_v[2] = z_v;
						mul_v3_fl(jump_v, ground_v);

						normalize_v3(jump_v);
						mul_v3_fl(jump_v, len);
						add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
					}
				}
			}

			/* jump to go faster */
			if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
				
			}

			if (jump) {
				copy_v3_v3(pa->prev_state.vel, jump_v);
				bpa->data.mode = eBoidMode_Falling;
			}
		}
	}
}
Ejemplo n.º 28
0
static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const wmEvent *event)
{
	if (event->type == TIMER && event->customdata == walk->timer) {
		walk->redraw = true;
	}
	else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {

		walk->moffset[0] += event->mval[0] - walk->prev_mval[0];
		walk->moffset[1] += event->mval[1] - walk->prev_mval[1];

		copy_v2_v2_int(walk->prev_mval, event->mval);

		if ((walk->center_mval[0] != event->mval[0]) ||
		    (walk->center_mval[1] != event->mval[1]))
		{
			walk->redraw = true;

			if (wm_event_is_last_mousemove(event)) {
				wmWindow *win = CTX_wm_window(C);

#ifdef __APPLE__
				if ((abs(walk->prev_mval[0] - walk->center_mval[0]) > walk->center_mval[0] / 2) ||
				    (abs(walk->prev_mval[1] - walk->center_mval[1]) > walk->center_mval[1] / 2))
#endif
				{
					WM_cursor_warp(win,
					               walk->ar->winrct.xmin + walk->center_mval[0],
					               walk->ar->winrct.ymin + walk->center_mval[1]);
					copy_v2_v2_int(walk->prev_mval, walk->center_mval);
				}
			}
		}
	}
	else if (event->type == NDOF_MOTION) {
		/* do these automagically get delivered? yes. */
		// puts("ndof motion detected in walk mode!");
		// static const char *tag_name = "3D mouse position";

		const wmNDOFMotionData *incoming_ndof = event->customdata;
		switch (incoming_ndof->progress) {
			case P_STARTING:
				/* start keeping track of 3D mouse position */
#ifdef NDOF_WALK_DEBUG
				puts("start keeping track of 3D mouse position");
#endif
				/* fall-through */
			case P_IN_PROGRESS:
				/* update 3D mouse position */
#ifdef NDOF_WALK_DEBUG
				putchar('.'); fflush(stdout);
#endif
				if (walk->ndof == NULL) {
					// walk->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
					walk->ndof = MEM_dupallocN(incoming_ndof);
					// walk->ndof = malloc(sizeof(wmNDOFMotionData));
				}
				else {
					memcpy(walk->ndof, incoming_ndof, sizeof(wmNDOFMotionData));
				}
				break;
			case P_FINISHING:
				/* stop keeping track of 3D mouse position */
#ifdef NDOF_WALK_DEBUG
				puts("stop keeping track of 3D mouse position");
#endif
				if (walk->ndof) {
					MEM_freeN(walk->ndof);
					// free(walk->ndof);
					walk->ndof = NULL;
				}

				/* update the time else the view will jump when 2D mouse/timer resume */
				walk->time_lastdraw = PIL_check_seconds_timer();

				break;
			default:
				break; /* should always be one of the above 3 */
		}
	}
	/* handle modal keymap first */
	else if (event->type == EVT_MODAL_MAP) {
		switch (event->val) {
			case WALK_MODAL_CANCEL:
				walk->state = WALK_CANCEL;
				break;
			case WALK_MODAL_CONFIRM:
				walk->state = WALK_CONFIRM;
				break;

			case WALK_MODAL_ACCELERATE:
				base_speed *= 1.0f + (walk->is_slow ? 0.01f : 0.1f);
				break;
			case WALK_MODAL_DECELERATE:
				base_speed /= 1.0f + (walk->is_slow ? 0.01f : 0.1f);
				break;

			/* implement WASD keys */
			case WALK_MODAL_DIR_FORWARD:
				walk->active_directions |= WALK_BIT_FORWARD;
				break;
			case WALK_MODAL_DIR_BACKWARD:
				walk->active_directions |= WALK_BIT_BACKWARD;
				break;
			case WALK_MODAL_DIR_LEFT:
				walk->active_directions |= WALK_BIT_LEFT;
				break;
			case WALK_MODAL_DIR_RIGHT:
				walk->active_directions |= WALK_BIT_RIGHT;
				break;
			case WALK_MODAL_DIR_UP:
				walk->active_directions |= WALK_BIT_UP;
				break;
			case WALK_MODAL_DIR_DOWN:
				walk->active_directions |= WALK_BIT_DOWN;
				break;

			case WALK_MODAL_DIR_FORWARD_STOP:
				walk->active_directions &= ~WALK_BIT_FORWARD;
				break;
			case WALK_MODAL_DIR_BACKWARD_STOP:
				walk->active_directions &= ~WALK_BIT_BACKWARD;
				break;
			case WALK_MODAL_DIR_LEFT_STOP:
				walk->active_directions &= ~WALK_BIT_LEFT;
				break;
			case WALK_MODAL_DIR_RIGHT_STOP:
				walk->active_directions &= ~WALK_BIT_RIGHT;
				break;
			case WALK_MODAL_DIR_UP_STOP:
				walk->active_directions &= ~WALK_BIT_UP;
				break;
			case WALK_MODAL_DIR_DOWN_STOP:
				walk->active_directions &= ~WALK_BIT_DOWN;
				break;

			case WALK_MODAL_FAST_ENABLE:
				walk->is_fast = true;
				break;
			case WALK_MODAL_FAST_DISABLE:
				walk->is_fast = false;
				break;
			case WALK_MODAL_SLOW_ENABLE:
				walk->is_slow = true;
				break;
			case WALK_MODAL_SLOW_DISABLE:
				walk->is_slow = false;
				break;

#define JUMP_SPEED_MIN 1.0f
#define JUMP_TIME_MAX 0.2f /* s */
#define JUMP_SPEED_MAX sqrtf(2.0f * walk->gravity * walk->jump_height)

			case WALK_MODAL_JUMP_STOP:
				if (walk->gravity_state == WALK_GRAVITY_STATE_JUMP) {
					float t;

					/* delta time */
					t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time);

					/* reduce the veolocity, if JUMP wasn't hold for long enough */
					t = min_ff(t, JUMP_TIME_MAX);
					walk->speed_jump = JUMP_SPEED_MIN + t * (JUMP_SPEED_MAX - JUMP_SPEED_MIN) / JUMP_TIME_MAX;

					/* when jumping, duration is how long it takes before we start going down */
					walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump);

					/* no more increase of jump speed */
					walk->gravity_state = WALK_GRAVITY_STATE_ON;
				}
				break;
			case WALK_MODAL_JUMP:
				if ((walk->navigation_mode == WALK_MODE_GRAVITY) &&
				    (walk->gravity_state == WALK_GRAVITY_STATE_OFF) &&
				    (walk->teleport.state == WALK_TELEPORT_STATE_OFF))
				{
					/* no need to check for ground,
					 * walk->gravity wouldn't be off
					 * if we were over a hole */
					walk->gravity_state = WALK_GRAVITY_STATE_JUMP;
					walk->speed_jump = JUMP_SPEED_MAX;

					walk->teleport.initial_time = PIL_check_seconds_timer();
					copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]);

					/* using previous vec because WASD keys are not called when SPACE is */
					copy_v2_v2(walk->teleport.direction, walk->dvec_prev);

					/* when jumping, duration is how long it takes before we start going down */
					walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump);
				}

				break;

			case WALK_MODAL_TELEPORT:
			{
				float loc[3], nor[3];
				float distance;
				bool ret = walk_ray_cast(C, walk->rv3d, walk, loc, nor, &distance);

				/* in case we are teleporting middle way from a jump */
				walk->speed_jump = 0.0f;

				if (ret) {
					WalkTeleport *teleport = &walk->teleport;
					teleport->state = WALK_TELEPORT_STATE_ON;
					teleport->initial_time = PIL_check_seconds_timer();
					teleport->duration = U.walk_navigation.teleport_time;

					teleport->navigation_mode = walk->navigation_mode;
					walk_navigation_mode_set(C, walk, WALK_MODE_FREE);

					copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]);

					/* stop the camera from a distance (camera height) */
					normalize_v3(nor);
					mul_v3_fl(nor, walk->view_height);
					add_v3_v3(loc, nor);

					sub_v3_v3v3(teleport->direction, loc, teleport->origin);
				}
				else {
					walk->teleport.state = WALK_TELEPORT_STATE_OFF;
				}
				break;
			}

#undef JUMP_SPEED_MAX
#undef JUMP_TIME_MAX
#undef JUMP_SPEED_MIN

			case WALK_MODAL_TOGGLE:
				if (walk->navigation_mode == WALK_MODE_GRAVITY) {
					walk_navigation_mode_set(C, walk, WALK_MODE_FREE);
				}
				else { /* WALK_MODE_FREE */
					walk_navigation_mode_set(C, walk, WALK_MODE_GRAVITY);
				}
				break;
		}
	}
}
Ejemplo n.º 29
0
void addnormalsDispList(ListBase *lb)
{
	DispList *dl = NULL;
	float *vdata, *ndata, nor[3];
	float *v1, *v2, *v3, *v4;
	float *n1, *n2, *n3, *n4;
	int a, b, p1, p2, p3, p4;


	dl= lb->first;
	
	while(dl) {
		if(dl->type==DL_INDEX3) {
			if(dl->nors==NULL) {
				dl->nors= MEM_callocN(sizeof(float)*3, "dlnors");
				if(dl->verts[2] < 0.0f) dl->nors[2]= -1.0f;
				else dl->nors[2]= 1.0f;
			}
		}
		else if(dl->type==DL_SURF) {
			if(dl->nors==NULL) {
				dl->nors= MEM_callocN(sizeof(float)*3*dl->nr*dl->parts, "dlnors");
				
				vdata= dl->verts;
				ndata= dl->nors;
				
				for(a=0; a<dl->parts; a++) {
					
					if (surfindex_displist(dl, a, &b, &p1, &p2, &p3, &p4)==0)
						break;
	
					v1= vdata+ 3*p1; 
					n1= ndata+ 3*p1;
					v2= vdata+ 3*p2; 
					n2= ndata+ 3*p2;
					v3= vdata+ 3*p3; 
					n3= ndata+ 3*p3;
					v4= vdata+ 3*p4; 
					n4= ndata+ 3*p4;
					
					for(; b<dl->nr; b++) {
	
						normal_quad_v3( nor,v1, v3, v4, v2);
	
						add_v3_v3(n1, nor);
						add_v3_v3(n2, nor);
						add_v3_v3(n3, nor);
						add_v3_v3(n4, nor);
	
						v2= v1; v1+= 3;
						v4= v3; v3+= 3;
						n2= n1; n1+= 3;
						n4= n3; n3+= 3;
					}
				}
				a= dl->parts*dl->nr;
				v1= ndata;
				while(a--) {
					normalize_v3(v1);
					v1+= 3;
				}
			}
		}
		dl= dl->next;
	}
}
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]);
		}
	}
}