Exemple #1
0
static void generate_vert_coordinates(
        DerivedMesh *dm, Object *ob, Object *ob_center, const float offset[3],
        const int num_verts, float (*r_cos)[3], float r_size[3])
{
	float min_co[3], max_co[3];
	float diff[3];
	bool do_diff = false;

	INIT_MINMAX(min_co, max_co);

	dm->getVertCos(dm, r_cos);

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

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

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

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

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

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

	if (do_diff) {
		int i = num_verts;
		while (i--) {
			add_v3_v3(r_cos[i], diff);
		}
	}
}
MINLINE float dot_v3v3v3(const float p[3], const float a[3], const float b[3])
{
	float vec1[3], vec2[3];

	sub_v3_v3v3(vec1, a, p);
	sub_v3_v3v3(vec2, b, p);
	if (is_zero_v3(vec1) || is_zero_v3(vec2)) {
		return 0.0f;
	}
	return dot_v3v3(vec1, vec2);
}
Exemple #3
0
/* adjust bone roll to align Z axis with vector
 * vec is in local space and is normalized
 */
float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
{
	float mat[3][3], nor[3];

	sub_v3_v3v3(nor, bone->tail, bone->head);
	vec_roll_to_mat3(nor, 0.0f, mat);
	
	/* check the bone isn't aligned with the axis */
	if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
		float vec[3], align_axis_proj[3], roll;
		
		/* project the new_up_axis along the normal */
		project_v3_v3v3(vec, align_axis, nor);
		sub_v3_v3v3(align_axis_proj, align_axis, vec);
		
		if (axis_only) {
			if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) {
				negate_v3(align_axis_proj);
			}
		}
		
		roll = angle_v3v3(align_axis_proj, mat[2]);
		
		cross_v3_v3v3(vec, mat[2], align_axis_proj);
		
		if (dot_v3v3(vec, nor) < 0) {
			roll = -roll;
		}
		
		return roll;
	}

	return 0.0f;
}
Exemple #4
0
/* axis vector suffers from precision errors, use this function to ensure */
static void quat__axis_angle_sanitize(float axis[3], float *angle)
{
	if (axis) {
		if (is_zero_v3(axis) ||
		    !finite(axis[0]) ||
		    !finite(axis[1]) ||
		    !finite(axis[2]))
		{
			axis[0] = 1.0f;
			axis[1] = 0.0f;
			axis[2] = 0.0f;
		}
		else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) &&
		         EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
		         EXPP_FloatsAreEqual(axis[2], 0.0f, 10))
		{
			axis[0] = 1.0f;
		}
	}

	if (angle) {
		if (!finite(*angle)) {
			*angle = 0.0f;
		}
	}
}
Exemple #5
0
static bool stroke_elem_project_fallback(
        const struct CurveDrawData *cdd,
        const int mval_i[2], const float mval_fl[2],
        const float surface_offset, const float radius,
        const float location_fallback_depth[3],
        float r_location_world[3], float r_location_local[3],
        float r_normal_world[3], float r_normal_local[3])
{
	bool is_depth_found = stroke_elem_project(
	        cdd, mval_i, mval_fl,
	        surface_offset, radius,
	        r_location_world, r_normal_world);
	if (is_depth_found == false) {
		ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world);
		zero_v3(r_normal_local);
	}
	mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world);

	if (!is_zero_v3(r_normal_world)) {
		copy_v3_v3(r_normal_local, r_normal_world);
		mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local);
		normalize_v3(r_normal_local);
	}
	else {
		zero_v3(r_normal_local);
	}

	return is_depth_found;
}
static void applyObjectConstraintVec(TransInfo *t,
                                     TransDataContainer *tc,
                                     TransData *td,
                                     const float in[3],
                                     float out[3],
                                     float pvec[3])
{
  copy_v3_v3(out, in);
  if (t->con.mode & CON_APPLY) {
    if (!td) {
      mul_m3_v3(t->con.pmtx, out);

      const int dims = getConstraintSpaceDimension(t);
      if (dims == 2) {
        if (!is_zero_v3(out)) {
          if (!isPlaneProjectionViewAligned(t)) {
            planeProjection(t, in, out);
          }
        }
      }
      else if (dims == 1) {
        float c[3];

        if (t->con.mode & CON_AXIS0) {
          copy_v3_v3(c, t->con.mtx[0]);
        }
        else if (t->con.mode & CON_AXIS1) {
          copy_v3_v3(c, t->con.mtx[1]);
        }
        else if (t->con.mode & CON_AXIS2) {
          copy_v3_v3(c, t->con.mtx[2]);
        }
        axisProjection(t, c, in, out);
      }
      postConstraintChecks(t, out, pvec);
      copy_v3_v3(out, pvec);
    }
    else {
      int i = 0;

      out[0] = out[1] = out[2] = 0.0f;
      if (t->con.mode & CON_AXIS0) {
        out[0] = in[i++];
      }
      if (t->con.mode & CON_AXIS1) {
        out[1] = in[i++];
      }
      if (t->con.mode & CON_AXIS2) {
        out[2] = in[i++];
      }

      mul_m3_v3(td->axismtx, out);
      if (t->flag & T_EDIT) {
        mul_m3_v3(tc->mat3_unit, out);
      }
    }
  }
}
Exemple #7
0
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persistent_id[MAX_DUPLI_RECUR],
                            int level, short flag)
{
	DupliObject *dob;
	Group *group;
	GroupObject *go;
	float mat[4][4], tmat[4][4], id;
	
	if (ob->dup_group == NULL) return;
	group = ob->dup_group;
	
	/* simple preventing of too deep nested groups */
	if (level > MAX_DUPLI_RECUR) return;
	
	/* handles animated groups, and */

	/* we need to check update for objects that are not in scene... */
	if (flag & DUPLILIST_DO_UPDATE) {
		/* note: update is optional because we don't always need object
		 * transformations to be correct. Also fixes bug [#29616]. */
		group_handle_recalc_and_update(scene, ob, group);
	}

	if (group_is_animated(ob, group))
		flag |= DUPLILIST_ANIMATED;
	
	for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
		/* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
		if (go->ob != ob) {
			
			/* group dupli offset, should apply after everything else */
			if (!is_zero_v3(group->dupli_ofs)) {
				copy_m4_m4(tmat, go->ob->obmat);
				sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs);
				mult_m4_m4m4(mat, ob->obmat, tmat);
			}
			else {
				mult_m4_m4m4(mat, ob->obmat, go->ob->obmat);
			}
			
			dob = new_dupli_object(lb, go->ob, mat, ob->lay, persistent_id, level, id, OB_DUPLIGROUP, flag);

			/* check the group instance and object layers match, also that the object visible flags are ok. */
			if ((dob->origlay & group->layer) == 0 ||
			    ((G.is_rendering == FALSE) && dob->ob->restrictflag & OB_RESTRICT_VIEW) ||
			    ((G.is_rendering == TRUE)  && dob->ob->restrictflag & OB_RESTRICT_RENDER))
			{
				dob->no_draw = TRUE;
			}

			if (go->ob->transflag & OB_DUPLI) {
				copy_m4_m4(dob->ob->obmat, dob->mat);
				object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, persistent_id, level + 1, id, flag);
				copy_m4_m4(dob->ob->obmat, dob->omat);
			}
		}
	}
}
Exemple #8
0
bool validSnappingNormal(TransInfo *t)
{
	if (validSnap(t)) {
		if (!is_zero_v3(t->tsnap.snapNormal)) {
			return true;
		}
	}
	
	return false;
}
void setBoneRollFromNormal(EditBone *bone, const float no[3], float UNUSED(invmat[4][4]), float tmat[3][3])
{
	if (no != NULL && !is_zero_v3(no)) {
		float normal[3];

		copy_v3_v3(normal, no);
		mul_m3_v3(tmat, normal);
		
		bone->roll = ED_rollBoneToVector(bone, normal, false);
	}
}
Exemple #10
0
static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated)
{
	DupliObject *dob;
	Group *group;
	GroupObject *go;
	float mat[4][4], tmat[4][4];
	
	if (ob->dup_group==NULL) return;
	group= ob->dup_group;
	
	/* simple preventing of too deep nested groups */
	if (level>MAX_DUPLI_RECUR) return;
	
	/* handles animated groups, and */
	/* we need to check update for objects that are not in scene... */
	group_handle_recalc_and_update(scene, ob, group);
	animated= animated || group_is_animated(ob, group);
	
	for (go= group->gobject.first; go; go= go->next) {
		/* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
		if (go->ob!=ob) {
			
			/* group dupli offset, should apply after everything else */
			if (!is_zero_v3(group->dupli_ofs)) {
				copy_m4_m4(tmat, go->ob->obmat);
				sub_v3_v3v3(tmat[3], tmat[3], group->dupli_ofs);
				mult_m4_m4m4(mat, ob->obmat, tmat);
			}
			else {
				mult_m4_m4m4(mat, ob->obmat, go->ob->obmat);
			}
			
			dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP, animated);

			/* check the group instance and object layers match, also that the object visible flags are ok. */
			if (	(dob->origlay & group->layer)==0 ||
				(G.rendering==0 && dob->ob->restrictflag & OB_RESTRICT_VIEW) ||
				(G.rendering && dob->ob->restrictflag & OB_RESTRICT_RENDER)
			) {
				dob->no_draw= 1;
			}
			else {
				dob->no_draw= 0;
			}

			if (go->ob->transflag & OB_DUPLI) {
				copy_m4_m4(dob->ob->obmat, dob->mat);
				object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, level+1, animated);
				copy_m4_m4(dob->ob->obmat, dob->omat);
			}
		}
	}
}
Exemple #11
0
void init_tex_mapping(TexMapping *texmap)
{
	float smat[3][3], rmat[3][3], mat[3][3], proj[3][3];

	if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z &&
	    is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size))
	{
		unit_m4(texmap->mat);

		texmap->flag |= TEXMAP_UNIT_MATRIX;
	}
	else {
		/* axis projection */
		zero_m3(proj);

		if (texmap->projx != PROJ_N)
			proj[texmap->projx - 1][0] = 1.0f;
		if (texmap->projy != PROJ_N)
			proj[texmap->projy - 1][1] = 1.0f;
		if (texmap->projz != PROJ_N)
			proj[texmap->projz - 1][2] = 1.0f;

		/* scale */
		size_to_mat3(smat, texmap->size);
		
		/* rotation */
		/* TexMapping rotation are now in radians. */
		eul_to_mat3(rmat, texmap->rot);
		
		/* compose it all */
		mul_m3_m3m3(mat, rmat, smat);
		mul_m3_m3m3(mat, proj, mat);
		
		/* translation */
		copy_m4_m3(texmap->mat, mat);
		copy_v3_v3(texmap->mat[3], texmap->loc);

		texmap->flag &= ~TEXMAP_UNIT_MATRIX;
	}
}
Exemple #12
0
static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, struct StrokeElem *selem, float pressure)
{
	if ((cdd->project.surface_offset != 0.0f) &&
	    !cdd->project.use_surface_offset_absolute &&
	    !is_zero_v3(selem->normal_local))
	{
		const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) -
		                     stroke_elem_radius_from_pressure(cdd, selem->pressure);
		madd_v3_v3fl(selem->location_local, selem->normal_local, adjust);
		mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local);
	}
	selem->pressure = pressure;
}
Exemple #13
0
static void vpaint_proj_dm_map_cosnos_init__map_cb(
    void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
{
  struct VertProjHandle *vp_handle = userData;
  CoNo *co_no = &vp_handle->vcosnos[index];

  /* check if we've been here before (normal should not be 0) */
  if (!is_zero_v3(co_no->no)) {
    /* remember that multiple dm verts share the same source vert */
    vp_handle->use_update = true;
    return;
  }

  copy_v3_v3(co_no->co, co);
  if (no_f) {
    copy_v3_v3(co_no->no, no_f);
  }
  else {
    normal_short_to_float_v3(co_no->no, no_s);
  }
}
static void applyAxisConstraintVec(TransInfo *t,
                                   TransDataContainer *UNUSED(tc),
                                   TransData *td,
                                   const float in[3],
                                   float out[3],
                                   float pvec[3])
{
  copy_v3_v3(out, in);
  if (!td && t->con.mode & CON_APPLY) {
    mul_m3_v3(t->con.pmtx, out);

    // With snap, a projection is alright, no need to correct for view alignment
    if (!validSnap(t)) {
      const int dims = getConstraintSpaceDimension(t);
      if (dims == 2) {
        if (!is_zero_v3(out)) {
          if (!isPlaneProjectionViewAligned(t)) {
            planeProjection(t, in, out);
          }
        }
      }
      else if (dims == 1) {
        float c[3];

        if (t->con.mode & CON_AXIS0) {
          copy_v3_v3(c, t->con.mtx[0]);
        }
        else if (t->con.mode & CON_AXIS1) {
          copy_v3_v3(c, t->con.mtx[1]);
        }
        else if (t->con.mode & CON_AXIS2) {
          copy_v3_v3(c, t->con.mtx[2]);
        }
        axisProjection(t, c, in, out);
      }
    }
    postConstraintChecks(t, out, pvec);
  }
}
Exemple #15
0
static void cloth_continuum_step(ClothModifierData *clmd, float dt)
{
	ClothSimSettings *parms = clmd->sim_parms;
	Cloth *cloth = clmd->clothObject;
	Implicit_Data *data = cloth->implicit;
	int mvert_num = cloth->mvert_num;
	ClothVertex *vert;
	
	const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
	float smoothfac = parms->velocity_smooth;
	/* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead,
	 * like number of hairs per cell and time decay instead of "strength"
	 */
	float density_target = parms->density_target;
	float density_strength = parms->density_strength;
	float gmin[3], gmax[3];
	int i;
	
	/* clear grid info */
	zero_v3_int(clmd->hair_grid_res);
	zero_v3(clmd->hair_grid_min);
	zero_v3(clmd->hair_grid_max);
	clmd->hair_grid_cellsize = 0.0f;
	
	hair_get_boundbox(clmd, gmin, gmax);
	
	/* gather velocities & density */
	if (smoothfac > 0.0f || density_strength > 0.0f) {
		HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
		
		cloth_continuum_fill_grid(grid, cloth);
		
		/* main hair continuum solver */
		BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength);
		
		for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
			float x[3], v[3], nv[3];
			
			/* calculate volumetric velocity influence */
			BPH_mass_spring_get_position(data, i, x);
			BPH_mass_spring_get_new_velocity(data, i, v);
			
			BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv);
			
			interp_v3_v3v3(nv, v, nv, smoothfac);
			
			/* apply on hair data */
			BPH_mass_spring_set_new_velocity(data, i, nv);
		}
		
		/* store basic grid info in the modifier data */
		BPH_hair_volume_grid_geometry(grid, &clmd->hair_grid_cellsize, clmd->hair_grid_res, clmd->hair_grid_min, clmd->hair_grid_max);
		
#if 0 /* DEBUG hair velocity vector field */
		{
			const int size = 64;
			int i, j;
			float offset[3], a[3], b[3];
			const int axis = 0;
			const float shift = 0.0f;
			
			copy_v3_v3(offset, clmd->hair_grid_min);
			zero_v3(a);
			zero_v3(b);
			
			offset[axis] = shift * clmd->hair_grid_cellsize;
			a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3];
			b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3];
			
			BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
			for (j = 0; j < size; ++j) {
				for (i = 0; i < size; ++i) {
					float x[3], v[3], gvel[3], gvel_smooth[3], gdensity;
					
					madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1));
					madd_v3_v3fl(x, b, (float)j / (float)(size-1));
					zero_v3(v);
					
					BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL);
					
//					BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity, 0.7, 0.3, 1, "grid density", i, j, 3111);
					if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) {
						float dvel[3];
						sub_v3_v3v3(dvel, gvel_smooth, gvel);
//						BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel, 0.4, 0, 1, "grid velocity", i, j, 3112);
//						BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, "grid velocity", i, j, 3113);
						BKE_sim_debug_data_add_vector(clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114);
#if 0
						if (gdensity > 0.0f) {
							float col0[3] = {0.0, 0.0, 0.0};
							float col1[3] = {0.0, 1.0, 0.0};
							float col[3];
							
							interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0));
//							BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, "grid velocity", i, j, 3115);
//							BKE_sim_debug_data_add_dot(clmd->debug_data, x, col[0], col[1], col[2], "grid velocity", i, j, 3115);
							BKE_sim_debug_data_add_circle(clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115);
						}
#endif
					}
				}
			}
		}
#endif
		
		BPH_hair_volume_free_vertex_grid(grid);
	}
}
Exemple #16
0
/* OB_DUPLIPARTS */
static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem *psys)
{
	Scene *scene = ctx->scene;
	Object *par = ctx->object;
	bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
	bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);

	GroupObject *go;
	Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
	DupliObject *dob;
	ParticleDupliWeight *dw;
	ParticleSettings *part;
	ParticleData *pa;
	ChildParticle *cpa = NULL;
	ParticleKey state;
	ParticleCacheKey *cache;
	float ctime, pa_time, scale = 1.0f;
	float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0;
	float (*obmat)[4];
	int a, b, hair = 0;
	int totpart, totchild, totgroup = 0 /*, pa_num */;
	const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene);

	int no_draw_flag = PARS_UNEXIST;

	if (psys == NULL) return;

	part = psys->part;

	if (part == NULL)
		return;

	if (!psys_check_enabled(par, psys))
		return;

	if (!for_render)
		no_draw_flag |= PARS_NO_DISP;

	ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */

	totpart = psys->totpart;
	totchild = psys->totchild;

	BLI_srandom((unsigned int)(31415926 + psys->seed));

	if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
		ParticleSimulationData sim = {NULL};
		sim.scene = scene;
		sim.ob = par;
		sim.psys = psys;
		sim.psmd = psys_get_modifier(par, psys);
		/* make sure emitter imat is in global coordinates instead of render view coordinates */
		invert_m4_m4(par->imat, par->obmat);

		/* first check for loops (particle system object used as dupli object) */
		if (part->ren_as == PART_DRAW_OB) {
			if (ELEM(part->dup_ob, NULL, par))
				return;
		}
		else { /*PART_DRAW_GR */
			if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject))
				return;

			if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
				return;
			}
		}

		/* if we have a hair particle system, use the path cache */
		if (part->type == PART_HAIR) {
			if (psys->flag & PSYS_HAIR_DONE)
				hair = (totchild == 0 || psys->childcache) && psys->pathcache;
			if (!hair)
				return;

			/* we use cache, update totchild according to cached data */
			totchild = psys->totchildcache;
			totpart = psys->totcached;
		}

		psys_check_group_weights(part);

		psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);

		/* gather list of objects or single object */
		if (part->ren_as == PART_DRAW_GR) {
			if (ctx->do_update) {
				BKE_group_handle_recalc_and_update(ctx->eval_ctx, scene, par, part->dup_group);
			}

			if (part->draw & PART_DRAW_COUNT_GR) {
				for (dw = part->dupliweights.first; dw; dw = dw->next)
					totgroup += dw->count;
			}
			else {
				for (go = part->dup_group->gobject.first; go; go = go->next)
					totgroup++;
			}

			/* we also copy the actual objects to restore afterwards, since
			 * BKE_object_where_is_calc_time will change the object which breaks transform */
			oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list");
			obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list");

			if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
				dw = part->dupliweights.first;

				for (a = 0; a < totgroup; dw = dw->next) {
					for (b = 0; b < dw->count; b++, a++) {
						oblist[a] = dw->ob;
						obcopylist[a] = *dw->ob;
					}
				}
			}
			else {
				go = part->dup_group->gobject.first;
				for (a = 0; a < totgroup; a++, go = go->next) {
					oblist[a] = go->ob;
					obcopylist[a] = *go->ob;
				}
			}
		}
		else {
			ob = part->dup_ob;
			obcopy = *ob;
		}

		if (totchild == 0 || part->draw & PART_DRAW_PARENT)
			a = 0;
		else
			a = totpart;

		for (pa = psys->particles; a < totpart + totchild; a++, pa++) {
			if (a < totpart) {
				/* handle parent particle */
				if (pa->flag & no_draw_flag)
					continue;

				/* pa_num = pa->num; */ /* UNUSED */
				pa_time = pa->time;
				size = pa->size;
			}
			else {
				/* handle child particle */
				cpa = &psys->child[a - totpart];

				/* pa_num = a; */ /* UNUSED */
				pa_time = psys->particles[cpa->parent].time;
				size = psys_get_child_size(psys, cpa, ctime, NULL);
			}

			/* some hair paths might be non-existent so they can't be used for duplication */
			if (hair && psys->pathcache &&
			    ((a < totpart && psys->pathcache[a]->segments < 0) ||
			     (a >= totpart && psys->childcache[a - totpart]->segments < 0)))
			{
				continue;
			}

			if (part->ren_as == PART_DRAW_GR) {
				/* prevent divide by zero below [#28336] */
				if (totgroup == 0)
					continue;

				/* for groups, pick the object based on settings */
				if (part->draw & PART_DRAW_RAND_GR)
					b = BLI_rand() % totgroup;
				else
					b = a % totgroup;

				ob = oblist[b];
				obmat = oblist[b]->obmat;
			}
			else {
				obmat = ob->obmat;
			}

			if (hair) {
				/* hair we handle separate and compute transform based on hair keys */
				if (a < totpart) {
					cache = psys->pathcache[a];
					psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale);
				}
				else {
					cache = psys->childcache[a - totpart];
					psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale);
				}

				copy_v3_v3(pamat[3], cache->co);
				pamat[3][3] = 1.0f;

			}
			else {
				/* first key */
				state.time = ctime;
				if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
					continue;
				}
				else {
					float tquat[4];
					normalize_qt_qt(tquat, state.rot);
					quat_to_mat4(pamat, tquat);
					copy_v3_v3(pamat[3], state.co);
					pamat[3][3] = 1.0f;
				}
			}

			if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
				for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) {

					copy_m4_m4(tmat, oblist[b]->obmat);
					/* apply particle scale */
					mul_mat3_m4_fl(tmat, size * scale);
					mul_v3_fl(tmat[3], size * scale);
					/* group dupli offset, should apply after everything else */
					if (!is_zero_v3(part->dup_group->dupli_ofs))
						sub_v3_v3(tmat[3], part->dup_group->dupli_ofs);
					/* individual particle transform */
					mul_m4_m4m4(mat, pamat, tmat);

					dob = make_dupli(ctx, go->ob, mat, a, false, false);
					dob->particle_system = psys;
					if (use_texcoords)
						psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				}
			}
			else {
				/* to give ipos in object correct offset */
				BKE_object_where_is_calc_time(scene, ob, ctime - pa_time);

				copy_v3_v3(vec, obmat[3]);
				obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;

				/* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */
				if ((part->draw & PART_DRAW_ROTATE_OB) == 0) {
					float xvec[3], q[4], size_mat[4][4], original_size[3];

					mat4_to_size(original_size, obmat);
					size_to_mat4(size_mat, original_size);

					xvec[0] = -1.f;
					xvec[1] = xvec[2] = 0;
					vec_to_quat(q, xvec, ob->trackflag, ob->upflag);
					quat_to_mat4(obmat, q);
					obmat[3][3] = 1.0f;

					/* add scaling if requested */
					if ((part->draw & PART_DRAW_NO_SCALE_OB) == 0)
						mul_m4_m4m4(obmat, obmat, size_mat);
				}
				else if (part->draw & PART_DRAW_NO_SCALE_OB) {
					/* remove scaling */
					float size_mat[4][4], original_size[3];

					mat4_to_size(original_size, obmat);
					size_to_mat4(size_mat, original_size);
					invert_m4(size_mat);

					mul_m4_m4m4(obmat, obmat, size_mat);
				}

				mul_m4_m4m4(tmat, pamat, obmat);
				mul_mat3_m4_fl(tmat, size * scale);

				copy_m4_m4(mat, tmat);

				if (part->draw & PART_DRAW_GLOBAL_OB)
					add_v3_v3v3(mat[3], mat[3], vec);

				dob = make_dupli(ctx, ob, mat, a, false, false);
				dob->particle_system = psys;
				if (use_texcoords)
					psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				/* XXX blender internal needs this to be set to dupligroup to render
				 * groups correctly, but we don't want this hack for cycles */
				if (dupli_type_hack && ctx->group)
					dob->type = OB_DUPLIGROUP;
			}
		}

		/* restore objects since they were changed in BKE_object_where_is_calc_time */
		if (part->ren_as == PART_DRAW_GR) {
			for (a = 0; a < totgroup; a++)
				*(oblist[a]) = obcopylist[a];
		}
		else
			*ob = obcopy;
	}

	/* clean up */
	if (oblist)
		MEM_freeN(oblist);
	if (obcopylist)
		MEM_freeN(obcopylist);

	if (psys->lattice_deform_data) {
		end_latt_deform(psys->lattice_deform_data);
		psys->lattice_deform_data = NULL;
	}
}
Exemple #17
0
static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
{
	float loc[3];
	float rot[4];
	float scale[3];

	/* only update if rigid body exists */
	if (rbo->physics_object == NULL)
		return;

	if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
		DerivedMesh *dm = ob->derivedDeform;
		if (dm) {
			MVert *mvert = dm->getVertArray(dm);
			int totvert = dm->getNumVerts(dm);
			BoundBox *bb = BKE_object_boundbox_get(ob);

			RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
		}
	}

	mat4_decompose(loc, rot, scale, ob->obmat);

	/* update scale for all objects */
	RB_body_set_scale(rbo->physics_object, scale);
	/* compensate for embedded convex hull collision margin */
	if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH)
		RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2]));

	/* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */
	if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) {
		RB_body_set_kinematic_state(rbo->physics_object, TRUE);
		RB_body_set_mass(rbo->physics_object, 0.0f);
	}

	/* update rigid body location and rotation for kinematic bodies */
	if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
		RB_body_activate(rbo->physics_object);
		RB_body_set_loc_rot(rbo->physics_object, loc, rot);
	}
	/* update influence of effectors - but don't do it on an effector */
	/* only dynamic bodies need effector update */
	else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
		EffectorWeights *effector_weights = rbw->effector_weights;
		EffectedPoint epoint;
		ListBase *effectors;

		/* get effectors present in the group specified by effector_weights */
		effectors = pdInitEffectors(scene, ob, NULL, effector_weights);
		if (effectors) {
			float eff_force[3] = {0.0f, 0.0f, 0.0f};
			float eff_loc[3], eff_vel[3];

			/* create dummy 'point' which represents last known position of object as result of sim */
			// XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals?
			RB_body_get_position(rbo->physics_object, eff_loc);
			RB_body_get_linear_velocity(rbo->physics_object, eff_vel);

			pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);

			/* calculate net force of effectors, and apply to sim object
			 *	- we use 'central force' since apply force requires a "relative position" which we don't have...
			 */
			pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
			if (G.f & G_DEBUG)
				printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
			/* activate object in case it is deactivated */
			if (!is_zero_v3(eff_force))
				RB_body_activate(rbo->physics_object);
			RB_body_apply_central_force(rbo->physics_object, eff_force);
		}
		else if (G.f & G_DEBUG)
			printf("\tno forces to apply to '%s'\n", ob->id.name + 2);

		/* cleanup */
		pdEndEffectors(&effectors);
	}
	/* NOTE: passive objects don't need to be updated since they don't move */

	/* NOTE: no other settings need to be explicitly updated here,
	 * since RNA setters take care of the rest :)
	 */
}
static void axisProjection(TransInfo *t, const float axis[3], const float in[3], float out[3])
{
	float norm[3], vec[3], factor, angle;
	float t_con_center[3];

	if (is_zero_v3(in)) {
		return;
	}

	copy_v3_v3(t_con_center, t->center_global);

	/* 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) {
		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;
		}
	}
}
static int walkApply_ndof(bContext *C, WalkInfo *walk)
{
	/* shorthand for oft-used variables */
	wmNDOFMotionData *ndof = walk->ndof;
	const float dt = ndof->dt;
	RegionView3D *rv3d = walk->rv3d;
	const int flag = U.ndof_flag;

#if 0
	bool do_rotate = (flag & NDOF_SHOULD_ROTATE) && (walk->pan_view == false);
	bool do_translate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM)) != 0;
#endif

	bool do_rotate = true;
	bool do_translate = true;

	float view_inv[4];
	invert_qt_qt(view_inv, rv3d->viewquat);

	rv3d->rot_angle = 0.0f; /* disable onscreen rotation doo-dad */

	if (do_translate) {
		const float forward_sensitivity  = 1.0f;
		const float vertical_sensitivity = 0.4f;
		const float lateral_sensitivity  = 0.6f;

		float speed = 10.0f; /* blender units per second */
		/* ^^ this is ok for default cube scene, but should scale with.. something */

		float trans[3] = {lateral_sensitivity  * ndof->tvec[0],
		                  vertical_sensitivity * ndof->tvec[1],
		                  forward_sensitivity  * ndof->tvec[2]};

		if (walk->is_slow)
			speed *= 0.2f;

		mul_v3_fl(trans, speed * dt);

		/* transform motion from view to world coordinates */
		mul_qt_v3(view_inv, trans);

		if (flag & NDOF_FLY_HELICOPTER) {
			/* replace world z component with device y (yes it makes sense) */
			trans[2] = speed * dt * vertical_sensitivity * ndof->tvec[1];
		}

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

		if (!is_zero_v3(trans)) {
			/* move center of view opposite of hand motion (this is camera mode, not object mode) */
			sub_v3_v3(rv3d->ofs, trans);
			do_translate = true;
		}
		else {
			do_translate = false;
		}
	}

	if (do_rotate) {
		const float turn_sensitivity = 1.0f;

		float rotation[4];
		float axis[3];
		float angle = turn_sensitivity * ndof_to_axis_angle(ndof, axis);

		if (fabsf(angle) > 0.0001f) {
			do_rotate = true;

			if (walk->is_slow)
				angle *= 0.2f;

			/* transform rotation axis from view to world coordinates */
			mul_qt_v3(view_inv, axis);

			/* apply rotation to view */
			axis_angle_to_quat(rotation, axis, angle);
			mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);

			if (flag & NDOF_LOCK_HORIZON) {
				/* force an upright viewpoint
				 * TODO: make this less... sudden */
				float view_horizon[3] = {1.0f, 0.0f, 0.0f}; /* view +x */
				float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */

				/* find new inverse since viewquat has changed */
				invert_qt_qt(view_inv, rv3d->viewquat);
				/* could apply reverse rotation to existing view_inv to save a few cycles */

				/* transform view vectors to world coordinates */
				mul_qt_v3(view_inv, view_horizon);
				mul_qt_v3(view_inv, view_direction);


				/* find difference between view & world horizons
				 * true horizon lives in world xy plane, so look only at difference in z */
				angle = -asinf(view_horizon[2]);

#ifdef NDOF_WALK_DEBUG
				printf("lock horizon: adjusting %.1f degrees\n\n", RAD2DEG(angle));
#endif

				/* rotate view so view horizon = world horizon */
				axis_angle_to_quat(rotation, view_direction, angle);
				mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
			}

			rv3d->view = RV3D_VIEW_USER;
		}
		else {
			do_rotate = false;
		}
	}

	if (do_translate || do_rotate) {
		walk->redraw = true;

		if (rv3d->persp == RV3D_CAMOB) {
			walkMoveCamera(C, walk, do_rotate, do_translate);
		}
	}

	return OPERATOR_FINISHED;
}
Exemple #20
0
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated)
{
	GroupObject *go;
	Object *ob=NULL, **oblist=NULL, obcopy, *obcopylist=NULL;
	DupliObject *dob;
	ParticleDupliWeight *dw;
	ParticleSettings *part;
	ParticleData *pa;
	ChildParticle *cpa=NULL;
	ParticleKey state;
	ParticleCacheKey *cache;
	float ctime, pa_time, scale = 1.0f;
	float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size=0.0;
	float (*obmat)[4], (*oldobmat)[4];
	int a, b, counter, hair = 0;
	int totpart, totchild, totgroup=0 /*, pa_num */;

	int no_draw_flag = PARS_UNEXIST;

	if (psys==NULL) return;
	
	/* simple preventing of too deep nested groups */
	if (level>MAX_DUPLI_RECUR) return;
	
	part=psys->part;

	if (part==NULL)
		return;

	if (!psys_check_enabled(par, psys))
		return;

	if (G.rendering == 0)
		no_draw_flag |= PARS_NO_DISP;
	
	ctime = BKE_curframe(scene); /* NOTE: in old animsys, used parent object's timeoffset... */

	totpart = psys->totpart;
	totchild = psys->totchild;

	BLI_srandom(31415926 + psys->seed);

	if ((psys->renderdata || part->draw_as==PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
		ParticleSimulationData sim= {NULL};
		sim.scene= scene;
		sim.ob= par;
		sim.psys= psys;
		sim.psmd= psys_get_modifier(par, psys);
		/* make sure emitter imat is in global coordinates instead of render view coordinates */
		invert_m4_m4(par->imat, par->obmat);

		/* first check for loops (particle system object used as dupli object) */
		if (part->ren_as == PART_DRAW_OB) {
			if (ELEM(part->dup_ob, NULL, par))
				return;
		}
		else { /*PART_DRAW_GR */
			if (part->dup_group == NULL || part->dup_group->gobject.first == NULL)
				return;

			for (go=part->dup_group->gobject.first; go; go=go->next)
				if (go->ob == par)
					return;
		}

		/* if we have a hair particle system, use the path cache */
		if (part->type == PART_HAIR) {
			if (psys->flag & PSYS_HAIR_DONE)
				hair= (totchild == 0 || psys->childcache) && psys->pathcache;
			if (!hair)
				return;
			
			/* we use cache, update totchild according to cached data */
			totchild = psys->totchildcache;
			totpart = psys->totcached;
		}

		psys_check_group_weights(part);

		psys->lattice = psys_get_lattice(&sim);

		/* gather list of objects or single object */
		if (part->ren_as==PART_DRAW_GR) {
			group_handle_recalc_and_update(scene, par, part->dup_group);

			if (part->draw & PART_DRAW_COUNT_GR) {
				for (dw=part->dupliweights.first; dw; dw=dw->next)
					totgroup += dw->count;
			}
			else {
				for (go=part->dup_group->gobject.first; go; go=go->next)
					totgroup++;
			}

			/* we also copy the actual objects to restore afterwards, since
			 * where_is_object_time will change the object which breaks transform */
			oblist = MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list");
			obcopylist = MEM_callocN(totgroup*sizeof(Object), "dupgroup copy list");

			
			if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
				dw = part->dupliweights.first;

				for (a=0; a<totgroup; dw=dw->next) {
					for (b=0; b<dw->count; b++, a++) {
						oblist[a] = dw->ob;
						obcopylist[a] = *dw->ob;
					}
				}
			}
			else {
				go = part->dup_group->gobject.first;
				for (a=0; a<totgroup; a++, go=go->next) {
					oblist[a] = go->ob;
					obcopylist[a] = *go->ob;
				}
			}
		}
		else {
			ob = part->dup_ob;
			obcopy = *ob;
		}

		if (totchild==0 || part->draw & PART_DRAW_PARENT)
			a = 0;
		else
			a = totpart;

		for (pa=psys->particles,counter=0; a<totpart+totchild; a++,pa++,counter++) {
			if (a<totpart) {
				/* handle parent particle */
				if (pa->flag & no_draw_flag)
					continue;

				/* pa_num = pa->num; */ /* UNUSED */
				pa_time = pa->time;
				size = pa->size;
			}
			else {
				/* handle child particle */
				cpa = &psys->child[a - totpart];

				/* pa_num = a; */ /* UNUSED */
				pa_time = psys->particles[cpa->parent].time;
				size = psys_get_child_size(psys, cpa, ctime, NULL);
			}

			/* some hair paths might be non-existent so they can't be used for duplication */
			if (hair &&
				((a < totpart && psys->pathcache[a]->steps < 0) ||
				(a >= totpart && psys->childcache[a-totpart]->steps < 0)))
				continue;

			if (part->ren_as==PART_DRAW_GR) {
				/* prevent divide by zero below [#28336] */
				if (totgroup == 0)
					continue;

				/* for groups, pick the object based on settings */
				if (part->draw&PART_DRAW_RAND_GR)
					b= BLI_rand() % totgroup;
				else
					b= a % totgroup;

				ob = oblist[b];
				obmat = oblist[b]->obmat;
				oldobmat = obcopylist[b].obmat;
			}
			else {
				obmat= ob->obmat;
				oldobmat= obcopy.obmat;
			}

			if (hair) {
				/* hair we handle separate and compute transform based on hair keys */
				if (a < totpart) {
					cache = psys->pathcache[a];
					psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale);
				}
				else {
					cache = psys->childcache[a-totpart];
					psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale);
				}

				copy_v3_v3(pamat[3], cache->co);
				pamat[3][3]= 1.0f;
				
			}
			else {
				/* first key */
				state.time = ctime;
				if (psys_get_particle_state(&sim, a, &state, 0) == 0) {
					continue;
				}
				else {
					float tquat[4];
					normalize_qt_qt(tquat, state.rot);
					quat_to_mat4(pamat, tquat);
					copy_v3_v3(pamat[3], state.co);
					pamat[3][3]= 1.0f;
				}
			}

			if (part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
				for (go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) {

					copy_m4_m4(tmat, oblist[b]->obmat);
					/* apply particle scale */
					mul_mat3_m4_fl(tmat, size*scale);
					mul_v3_fl(tmat[3], size*scale);
					/* group dupli offset, should apply after everything else */
					if (!is_zero_v3(part->dup_group->dupli_ofs))
						sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs);
					/* individual particle transform */
					mult_m4_m4m4(tmat, pamat, tmat);

					if (par_space_mat)
						mult_m4_m4m4(mat, par_space_mat, tmat);
					else
						copy_m4_m4(mat, tmat);

					dob= new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated);
					copy_m4_m4(dob->omat, obcopylist[b].obmat);
					if (G.rendering)
						psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
				}
			}
			else {
				/* to give ipos in object correct offset */
				where_is_object_time(scene, ob, ctime-pa_time);

				copy_v3_v3(vec, obmat[3]);
				obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;

				/* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */
				if ((part->draw & PART_DRAW_ROTATE_OB) == 0) {
					float xvec[3], q[4];
					xvec[0] = -1.f;
					xvec[1] = xvec[2] = 0;
					vec_to_quat(q, xvec, ob->trackflag, ob->upflag);
					quat_to_mat4(obmat, q);
					obmat[3][3]= 1.0f;
				}
				
				/* Normal particles and cached hair live in global space so we need to
				 * remove the real emitter's transformation before 2nd order duplication.
				 */
				if (par_space_mat && GS(id->name) != ID_GR)
					mult_m4_m4m4(mat, psys->imat, pamat);
				else
					copy_m4_m4(mat, pamat);

				mult_m4_m4m4(tmat, mat, obmat);
				mul_mat3_m4_fl(tmat, size*scale);

				if (par_space_mat)
					mult_m4_m4m4(mat, par_space_mat, tmat);
				else
					copy_m4_m4(mat, tmat);

				if (part->draw & PART_DRAW_GLOBAL_OB)
					add_v3_v3v3(mat[3], mat[3], vec);

				dob= new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated);
				copy_m4_m4(dob->omat, oldobmat);
				if (G.rendering)
					psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
			}
		}

		/* restore objects since they were changed in where_is_object_time */
		if (part->ren_as==PART_DRAW_GR) {
			for (a=0; a<totgroup; a++)
				*(oblist[a])= obcopylist[a];
		}
		else
			*ob= obcopy;
	}

	/* clean up */
	if (oblist)
		MEM_freeN(oblist);
	if (obcopylist)
		MEM_freeN(obcopylist);

	if (psys->lattice) {
		end_latt_deform(psys->lattice);
		psys->lattice = NULL;
	}
}
Exemple #21
0
void init_tex_mapping(TexMapping *texmap)
{
	float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3];

	if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z &&
	    is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size))
	{
		unit_m4(texmap->mat);

		texmap->flag |= TEXMAP_UNIT_MATRIX;
	}
	else {
		/* axis projection */
		zero_m4(proj);
		proj[3][3] = 1.0f;

		if (texmap->projx != PROJ_N)
			proj[texmap->projx - 1][0] = 1.0f;
		if (texmap->projy != PROJ_N)
			proj[texmap->projy - 1][1] = 1.0f;
		if (texmap->projz != PROJ_N)
			proj[texmap->projz - 1][2] = 1.0f;

		/* scale */
		copy_v3_v3(size, texmap->size);

		if (ELEM(texmap->type, TEXMAP_TYPE_TEXTURE, TEXMAP_TYPE_NORMAL)) {
			/* keep matrix invertible */
			if (fabsf(size[0]) < 1e-5f)
				size[0] = signf(size[0]) * 1e-5f;
			if (fabsf(size[1]) < 1e-5f)
				size[1] = signf(size[1]) * 1e-5f;
			if (fabsf(size[2]) < 1e-5f)
				size[2] = signf(size[2]) * 1e-5f;
		}
		
		size_to_mat4(smat, texmap->size);

		/* rotation */
		eul_to_mat4(rmat, texmap->rot);

		/* translation */
		unit_m4(tmat);
		copy_v3_v3(tmat[3], texmap->loc);

		if (texmap->type == TEXMAP_TYPE_TEXTURE) {
			/* to transform a texture, the inverse transform needs
			 * to be applied to the texture coordinate */
			mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0);
			invert_m4(texmap->mat);
		}
		else if (texmap->type == TEXMAP_TYPE_POINT) {
			/* forward transform */
			mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0);
		}
		else if (texmap->type == TEXMAP_TYPE_VECTOR) {
			/* no translation for vectors */
			mul_m4_m4m4(texmap->mat, rmat, smat);
		}
		else if (texmap->type == TEXMAP_TYPE_NORMAL) {
			/* no translation for normals, and inverse transpose */
			mul_m4_m4m4(texmap->mat, rmat, smat);
			invert_m4(texmap->mat);
			transpose_m4(texmap->mat);
		}

		/* projection last */
		mul_m4_m4m4(texmap->mat, texmap->mat, proj);

		texmap->flag &= ~TEXMAP_UNIT_MATRIX;
	}
}
static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
{
	if (t->spacetype == SPACE_VIEW3D) {
		float loc[3];
		float no[3];
		float mval[2];
		bool found = false;
		float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
		
		mval[0] = t->mval[0];
		mval[1] = t->mval[1];
		
		if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
			found = peelObjectsTransform(
			        t, mval,
			        (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
			        loc, no, NULL);
		}
		else {
			zero_v3(no);  /* objects won't set this */
			found = snapObjectsTransform(
			        t, mval, &dist_px,
			        loc, no);
		}
		
		if (found == true) {
			float tangent[3];
			
			sub_v2_v2v2(tangent, loc, t->tsnap.snapPoint);
			tangent[2] = 0.0f;
			
			if (!is_zero_v3(tangent)) {
				copy_v3_v3(t->tsnap.snapTangent, tangent);
			}
			
			copy_v3_v3(t->tsnap.snapPoint, loc);
			copy_v3_v3(t->tsnap.snapNormal, no);

			t->tsnap.status |=  POINT_INIT;
		}
		else {
			t->tsnap.status &= ~POINT_INIT;
		}
	}
	else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) {
		/* same as above but for UV's */
		Image *ima = ED_space_image(t->sa->spacedata.first);
		float co[2];
		
		UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);

		if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) {
			t->tsnap.snapPoint[0] *= t->aspect[0];
			t->tsnap.snapPoint[1] *= t->aspect[1];

			t->tsnap.status |=  POINT_INIT;
		}
		else {
			t->tsnap.status &= ~POINT_INIT;
		}
	}
	else if (t->spacetype == SPACE_NODE) {
		float loc[2];
		float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
		char node_border;
		
		if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) {
			copy_v2_v2(t->tsnap.snapPoint, loc);
			t->tsnap.snapNodeBorder = node_border;
			
			t->tsnap.status |=  POINT_INIT;
		}
		else {
			t->tsnap.status &= ~POINT_INIT;
		}
	}
}