Ejemplo n.º 1
0
static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
                           float (*vertexCos)[3], int numVerts)
{
	bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
	float vec[3], mat[4][4], dmat[4][4];
	int i, *index_pt;
	const float falloff_squared = hmd->falloff * hmd->falloff; /* for faster comparisons */
	
	MDeformVert *dvert;
	int defgrp_index, max_dvert;
	
	/* get world-space matrix of target, corrected for the space the verts are in */
	if (hmd->subtarget[0] && pchan) {
		/* bone target if there's a matching pose-channel */
		mul_m4_m4m4(dmat, hmd->object->obmat, pchan->pose_mat);
	}
	else {
		/* just object target */
		copy_m4_m4(dmat, hmd->object->obmat);
	}
	invert_m4_m4(ob->imat, ob->obmat);
	mul_serie_m4(mat, ob->imat, dmat, hmd->parentinv,
	             NULL, NULL, NULL, NULL, NULL);

	modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index);
	max_dvert = (dvert) ? numVerts : 0;

	/* Regarding index range checking below.
	 *
	 * This should always be true and I don't generally like 
	 * "paranoid" style code like this, but old files can have
	 * indices that are out of range because old blender did
	 * not correct them on exit editmode. - zr
	 */
	
	if (hmd->force == 0.0f) {
		/* do nothing, avoid annoying checks in the loop */
	}
	else if (hmd->indexar) { /* vertex indices? */
		const float fac_orig = hmd->force;
		float fac;
		const int *origindex_ar;
		
		/* if DerivedMesh is present and has original index data, use it */
		if (dm && (origindex_ar = dm->getVertDataArray(dm, CD_ORIGINDEX))) {
			for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
				if (*index_pt < numVerts) {
					int j;
					
					for (j = 0; j < numVerts; j++) {
						if (origindex_ar[j] == *index_pt) {
							float *co = vertexCos[j];
							if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
								if (dvert)
									fac *= defvert_find_weight(dvert + j, defgrp_index);
								
								if (fac) {
									mul_v3_m4v3(vec, mat, co);
									interp_v3_v3v3(co, co, vec, fac);
								}
							}
						}
					}
				}
			}
		}
		else { /* missing dm or ORIGINDEX */
			for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
				if (*index_pt < numVerts) {
					float *co = vertexCos[*index_pt];
					if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
						if (dvert)
							fac *= defvert_find_weight(dvert + (*index_pt), defgrp_index);
						
						if (fac) {
							mul_v3_m4v3(vec, mat, co);
							interp_v3_v3v3(co, co, vec, fac);
						}
					}
				}
			}
		}
	}
	else if (dvert) {  /* vertex group hook */
		const float fac_orig = hmd->force;
		
		for (i = 0; i < max_dvert; i++, dvert++) {
			float fac;
			float *co = vertexCos[i];
			
			if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
				fac *= defvert_find_weight(dvert, defgrp_index);
				if (fac) {
					mul_v3_m4v3(vec, mat, co);
					interp_v3_v3v3(co, co, vec, fac);
				}
			}
		}
	}
}
Ejemplo n.º 2
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.º 3
0
static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
                                         Object *ob, DerivedMesh *dm)
{
	float (*coords)[3], (*co)[3];
	MLoopUV *mloop_uv;
	MTexPoly *mtexpoly, *mt = NULL;
	int i, numVerts, numPolys, numLoops;
	Image *image = umd->image;
	MPoly *mpoly, *mp;
	MLoop *mloop;
	int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0);
	Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
	int num_projectors = 0;
	char uvname[MAX_CUSTOMDATA_LAYER_NAME];
	float aspx = umd->aspectx ? umd->aspectx : 1.0f;
	float aspy = umd->aspecty ? umd->aspecty : 1.0f;
	float scax = umd->scalex ? umd->scalex : 1.0f;
	float scay = umd->scaley ? umd->scaley : 1.0f;
	int free_uci = 0;

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

	if (num_projectors == 0) return dm;

	/* make sure there are UV Maps available */

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

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

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

		projectors[i].uci = NULL;

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

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

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

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

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

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

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

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

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

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

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

	numVerts = dm->getNumVerts(dm);

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

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

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

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

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

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

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

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

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

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

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

	return dm;
}
Ejemplo n.º 4
0
int join_mesh_exec(bContext *C, wmOperator *op)
{
    Main *bmain= CTX_data_main(C);
    Scene *scene= CTX_data_scene(C);
    Object *ob= CTX_data_active_object(C);
    Material **matar, *ma;
    Mesh *me;
    MVert *mvert, *mv;
    MEdge *medge = NULL;
    MFace *mface = NULL;
    Key *key, *nkey=NULL;
    KeyBlock *kb, *okb, *kbn;
    float imat[4][4], cmat[4][4], *fp1, *fp2, curpos;
    int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0;
    int vertofs, *matmap=NULL;
    int	i, j, index, haskey=0, edgeofs, faceofs;
    bDeformGroup *dg, *odg;
    MDeformVert *dvert;
    CustomData vdata, edata, fdata;

    if(scene->obedit) {
        BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode");
        return OPERATOR_CANCELLED;
    }

    /* ob is the object we are adding geometry to */
    if(!ob || ob->type!=OB_MESH) {
        BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
        return OPERATOR_CANCELLED;
    }

    /* count & check */
    CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
        if(base->object->type==OB_MESH) {
            me= base->object->data;

            totvert+= me->totvert;
            totedge+= me->totedge;
            totface+= me->totface;
            totmat+= base->object->totcol;

            if(base->object == ob)
                ok= 1;

            /* check for shapekeys */
            if(me->key)
                haskey++;
        }
    }
    CTX_DATA_END;

    /* that way the active object is always selected */
    if(ok==0) {
        BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
        return OPERATOR_CANCELLED;
    }

    /* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */
    me= (Mesh *)ob->data;
    key= me->key;

    if(totvert==0 || totvert==me->totvert) {
        BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
        return OPERATOR_CANCELLED;
    }

    if(totvert > MESH_MAX_VERTS) {
        BKE_reportf(op->reports, RPT_WARNING, "Joining results in %d vertices, limit is " STRINGIFY(MESH_MAX_VERTS), totvert);
        return OPERATOR_CANCELLED;
    }

    /* new material indices and material array */
    matar= MEM_callocN(sizeof(void*)*totmat, "join_mesh matar");
    if (totmat) matmap= MEM_callocN(sizeof(int)*totmat, "join_mesh matmap");
    totcol= ob->totcol;

    /* obact materials in new main array, is nicer start! */
    for(a=0; a<ob->totcol; a++) {
        matar[a]= give_current_material(ob, a+1);
        id_us_plus((ID *)matar[a]);
        /* increase id->us : will be lowered later */
    }

    /* - if destination mesh had shapekeys, move them somewhere safe, and set up placeholders
     * 	with arrays that are large enough to hold shapekey data for all meshes
     * -	if destination mesh didn't have shapekeys, but we encountered some in the meshes we're
     *	joining, set up a new keyblock and assign to the mesh
     */
    if(key) {
        /* make a duplicate copy that will only be used here... (must remember to free it!) */
        nkey= copy_key(key);

        /* for all keys in old block, clear data-arrays */
        for(kb= key->block.first; kb; kb= kb->next) {
            if(kb->data) MEM_freeN(kb->data);
            kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey");
            kb->totelem= totvert;
            kb->weights= NULL;
        }
    }
    else if(haskey) {
        /* add a new key-block and add to the mesh */
        key= me->key= add_key((ID *)me);
        key->type = KEY_RELATIVE;
    }

    /* first pass over objects - copying materials and vertexgroups across */
    CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
        /* only act if a mesh, and not the one we're joining to */
        if((ob!=base->object) && (base->object->type==OB_MESH)) {
            me= base->object->data;

            /* Join this object's vertex groups to the base one's */
            for(dg=base->object->defbase.first; dg; dg=dg->next) {
                /* See if this group exists in the object (if it doesn't, add it to the end) */
                if(!defgroup_find_name(ob, dg->name)) {
                    odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup");
                    memcpy(odg, dg, sizeof(bDeformGroup));
                    BLI_addtail(&ob->defbase, odg);
                }
            }
            if(ob->defbase.first && ob->actdef==0)
                ob->actdef=1;


            if(me->totvert) {
                /* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */
                if(totcol < MAXMAT-1) {
                    for(a=1; a<=base->object->totcol; a++) {
                        ma= give_current_material(base->object, a);

                        for(b=0; b<totcol; b++) {
                            if(ma == matar[b]) break;
                        }
                        if(b==totcol) {
                            matar[b]= ma;
                            if(ma) {
                                id_us_plus(&ma->id);
                            }
                            totcol++;
                        }
                        if(totcol>=MAXMAT-1)
                            break;
                    }
                }

                /* if this mesh has shapekeys, check if destination mesh already has matching entries too */
                if(me->key && key) {
                    for(kb= me->key->block.first; kb; kb= kb->next) {
                        /* if key doesn't exist in destination mesh, add it */
                        if(key_get_named_keyblock(key, kb->name) == NULL) {
                            /* copy this existing one over to the new shapekey block */
                            kbn= MEM_dupallocN(kb);
                            kbn->prev= kbn->next= NULL;

                            /* adjust adrcode and other settings to fit (allocate a new data-array) */
                            kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey");
                            kbn->totelem= totvert;
                            kbn->weights= NULL;

                            okb= key->block.last;
                            curpos= (okb) ? okb->pos : -0.1f;
                            if(key->type == KEY_RELATIVE)
                                kbn->pos= curpos + 0.1f;
                            else
                                kbn->pos= curpos;

                            BLI_addtail(&key->block, kbn);
                            kbn->adrcode= key->totkey;
                            key->totkey++;
                            if(key->totkey==1) key->refkey= kbn;

                            // XXX 2.5 Animato
#if 0
                            /* also, copy corresponding ipo-curve to ipo-block if applicable */
                            if(me->key->ipo && key->ipo) {
                                // FIXME... this is a luxury item!
                                puts("FIXME: ignoring IPO's when joining shapekeys on Meshes for now...");
                            }
#endif
                        }
                    }
                }
            }
        }
    }
    CTX_DATA_END;

    /* setup new data for destination mesh */
    memset(&vdata, 0, sizeof(vdata));
    memset(&edata, 0, sizeof(edata));
    memset(&fdata, 0, sizeof(fdata));

    mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
    medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
    mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);

    vertofs= 0;
    edgeofs= 0;
    faceofs= 0;

    /* inverse transform for all selected meshes in this object */
    invert_m4_m4(imat, ob->obmat);

    CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
        /* only join if this is a mesh */
        if(base->object->type==OB_MESH) {
            me= base->object->data;

            if(me->totvert) {
                /* standard data */
                CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
                CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);

                /* vertex groups */
                dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);

                /* NB: vertex groups here are new version */
                if(dvert) {
                    for(i=0; i<me->totvert; i++) {
                        for(j=0; j<dvert[i].totweight; j++) {
                            /*	Find the old vertex group */
                            odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
                            if(odg) {
                                /*	Search for a match in the new object, and set new index */
                                for(dg=ob->defbase.first, index=0; dg; dg=dg->next, index++) {
                                    if(!strcmp(dg->name, odg->name)) {
                                        dvert[i].dw[j].def_nr = index;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                /* if this is the object we're merging into, no need to do anything */
                if(base->object != ob) {
                    /* watch this: switch matmul order really goes wrong */
                    mul_m4_m4m4(cmat, base->object->obmat, imat);

                    /* transform vertex coordinates into new space */
                    for(a=0, mv=mvert; a < me->totvert; a++, mv++) {
                        mul_m4_v3(cmat, mv->co);
                    }

                    /* for each shapekey in destination mesh:
                     *	- if there's a matching one, copy it across (will need to transform vertices into new space...)
                     *	- otherwise, just copy own coordinates of mesh (no need to transform vertex coordinates into new space)
                     */
                    if(key) {
                        /* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
                        for(kb= key->block.first; kb; kb= kb->next) {
                            /* get pointer to where to write data for this mesh in shapekey's data array */
                            fp1= ((float *)kb->data) + (vertofs*3);

                            /* check if this mesh has such a shapekey */
                            okb= key_get_named_keyblock(me->key, kb->name);
                            if(okb) {
                                /* copy this mesh's shapekey to the destination shapekey (need to transform first) */
                                fp2= ((float *)(okb->data));
                                for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
                                    VECCOPY(fp1, fp2);
                                    mul_m4_v3(cmat, fp1);
                                }
                            }
                            else {
                                /* copy this mesh's vertex coordinates to the destination shapekey */
                                mv= mvert;
                                for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
                                    VECCOPY(fp1, mv->co);
                                }
                            }
                        }
                    }
                }
                else {
                    /* for each shapekey in destination mesh:
                     *	- if it was an 'original', copy the appropriate data from nkey
                     *	- otherwise, copy across plain coordinates (no need to transform coordinates)
                     */
                    if(key) {
                        for(kb= key->block.first; kb; kb= kb->next) {
                            /* get pointer to where to write data for this mesh in shapekey's data array */
                            fp1= ((float *)kb->data) + (vertofs*3);

                            /* check if this was one of the original shapekeys */
                            okb= key_get_named_keyblock(nkey, kb->name);
                            if(okb) {
                                /* copy this mesh's shapekey to the destination shapekey */
                                fp2= ((float *)(okb->data));
                                for(a=0; a < me->totvert; a++, fp1+=3, fp2+=3) {
                                    VECCOPY(fp1, fp2);
                                }
                            }
                            else {
                                /* copy base-coordinates to the destination shapekey */
                                mv= mvert;
                                for(a=0; a < me->totvert; a++, fp1+=3, mv++) {
                                    VECCOPY(fp1, mv->co);
                                }
                            }
                        }
                    }
                }

                /* advance mvert pointer to end of base mesh's data */
                mvert+= me->totvert;
            }

            if(me->totface) {
                /* make mapping for materials */
                for(a=1; a<=base->object->totcol; a++) {
                    ma= give_current_material(base->object, a);

                    for(b=0; b<totcol; b++) {
                        if(ma == matar[b]) {
                            matmap[a-1]= b;
                            break;
                        }
                    }
                }

                if(base->object!=ob)
                    multiresModifier_prepare_join(scene, base->object, ob);

                CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
                CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);

                for(a=0; a<me->totface; a++, mface++) {
                    mface->v1+= vertofs;
                    mface->v2+= vertofs;
                    mface->v3+= vertofs;
                    if(mface->v4) mface->v4+= vertofs;

                    if (matmap)
                        mface->mat_nr= matmap[(int)mface->mat_nr];
                    else
                        mface->mat_nr= 0;
                }

                faceofs += me->totface;
            }

            if(me->totedge) {
                CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
                CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);

                for(a=0; a<me->totedge; a++, medge++) {
                    medge->v1+= vertofs;
                    medge->v2+= vertofs;
                }

                edgeofs += me->totedge;
            }

            /* vertofs is used to help newly added verts be reattached to their edge/face
             * (cannot be set earlier, or else reattaching goes wrong)
             */
            vertofs += me->totvert;

            /* free base, now that data is merged */
            if(base->object != ob)
                ED_base_object_free_and_unlink(bmain, scene, base);
        }
    }
    CTX_DATA_END;

    /* return to mesh we're merging to */
    me= ob->data;

    CustomData_free(&me->vdata, me->totvert);
    CustomData_free(&me->edata, me->totedge);
    CustomData_free(&me->fdata, me->totface);

    me->totvert= totvert;
    me->totedge= totedge;
    me->totface= totface;

    me->vdata= vdata;
    me->edata= edata;
    me->fdata= fdata;

    mesh_update_customdata_pointers(me);

    /* old material array */
    for(a=1; a<=ob->totcol; a++) {
        ma= ob->mat[a-1];
        if(ma) ma->id.us--;
    }
    for(a=1; a<=me->totcol; a++) {
        ma= me->mat[a-1];
        if(ma) ma->id.us--;
    }
    if(ob->mat) MEM_freeN(ob->mat);
    if(ob->matbits) MEM_freeN(ob->matbits);
    if(me->mat) MEM_freeN(me->mat);
    ob->mat= me->mat= NULL;
    ob->matbits= NULL;

    if(totcol) {
        me->mat= matar;
        ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
        ob->matbits= MEM_callocN(sizeof(char)*totcol, "join obmatbits");
    }
    else
        MEM_freeN(matar);

    ob->totcol= me->totcol= totcol;
    ob->colbits= 0;

    if (matmap) MEM_freeN(matmap);

    /* other mesh users */
    test_object_materials((ID *)me);

    /* free temp copy of destination shapekeys (if applicable) */
    if(nkey) {
        // XXX 2.5 Animato
#if 0
        /* free it's ipo too - both are not actually freed from memory yet as ID-blocks */
        if(nkey->ipo) {
            free_ipo(nkey->ipo);
            BLI_remlink(&bmain->ipo, nkey->ipo);
            MEM_freeN(nkey->ipo);
        }
#endif

        free_key(nkey);
        BLI_remlink(&bmain->key, nkey);
        MEM_freeN(nkey);
    }

    DAG_scene_sort(bmain, scene);	// removed objects, need to rebuild dag before editmode call

#if 0
    ED_object_enter_editmode(C, EM_WAITCURSOR);
    ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO);
#else
    /* toggle editmode using lower level functions so this can be called from python */
    make_editMesh(scene, ob);
    load_editMesh(scene, ob);
    free_editMesh(me->edit_mesh);
    MEM_freeN(me->edit_mesh);
    me->edit_mesh= NULL;
    DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
#endif
    WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);

    return OPERATOR_FINISHED;
}
Ejemplo n.º 5
0
/* from/to_world_space : whether from/to particles are in world or hair space
 * from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
 */
static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
                               Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
                               float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
{
	ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
	ParticleData *pa, *tpa;
	PTCacheEditPoint *edit_point;
	PTCacheEditKey *ekey;
	BVHTreeFromMesh bvhtree= {NULL};
	MFace *mface = NULL, *mf;
	MEdge *medge = NULL, *me;
	MVert *mvert;
	DerivedMesh *dm, *target_dm;
	int numverts;
	int i, k;
	float from_ob_imat[4][4], to_ob_imat[4][4];
	float from_imat[4][4], to_imat[4][4];

	if (!target_psmd->dm)
		return false;
	if (!psys->part || psys->part->type != PART_HAIR)
		return false;
	if (!target_psys->part || target_psys->part->type != PART_HAIR)
		return false;
	
	edit_point = target_edit ? target_edit->points : NULL;
	
	invert_m4_m4(from_ob_imat, ob->obmat);
	invert_m4_m4(to_ob_imat, target_ob->obmat);
	invert_m4_m4(from_imat, from_mat);
	invert_m4_m4(to_imat, to_mat);
	
	if (target_psmd->dm->deformedOnly) {
		/* we don't want to mess up target_psmd->dm when converting to global coordinates below */
		dm = target_psmd->dm;
	}
	else {
		/* warning: this rebuilds target_psmd->dm! */
		dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
	}
	target_dm = target_psmd->dm;
	/* don't modify the original vertices */
	dm = CDDM_copy(dm);

	/* BMESH_ONLY, deform dm may not have tessface */
	DM_ensure_tessface(dm);

	numverts = dm->getNumVerts(dm);
	mvert = dm->getVertArray(dm);

	/* convert to global coordinates */
	for (i=0; i<numverts; i++)
		mul_m4_v3(to_mat, mvert[i].co);

	if (dm->getNumTessFaces(dm) != 0) {
		mface = dm->getTessFaceArray(dm);
		bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
	}
	else if (dm->getNumEdges(dm) != 0) {
		medge = dm->getEdgeArray(dm);
		bvhtree_from_mesh_edges(&bvhtree, dm, 0.0, 2, 6);
	}
	else {
		dm->release(dm);
		return false;
	}

	for (i = 0, tpa = target_psys->particles, pa = psys->particles;
	     i < target_psys->totpart;
	     i++, tpa++, pa++) {

		float from_co[3];
		BVHTreeNearest nearest;

		if (from_global)
			mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
		else
			mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
		mul_m4_v3(from_mat, from_co);

		nearest.index = -1;
		nearest.dist_sq = FLT_MAX;

		BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);

		if (nearest.index == -1) {
			if (G.debug & G_DEBUG)
				printf("No nearest point found for hair root!");
			continue;
		}

		if (mface) {
			float v[4][3];
			
			mf = &mface[nearest.index];

			copy_v3_v3(v[0], mvert[mf->v1].co);
			copy_v3_v3(v[1], mvert[mf->v2].co);
			copy_v3_v3(v[2], mvert[mf->v3].co);
			if (mf->v4) {
				copy_v3_v3(v[3], mvert[mf->v4].co);
				interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
			}
			else
				interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL);
		}
		else {
			me = &medge[nearest.index];

			tpa->fuv[1] = line_point_factor_v3(nearest.co,
			                                   mvert[me->v1].co,
			                                   mvert[me->v2].co);
			tpa->fuv[0] = 1.0f - tpa->fuv[1];
			tpa->fuv[2] = tpa->fuv[3] = 0.0f;
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = -1;
		}

		/* translate hair keys */
		{
			HairKey *key, *tkey;
			float hairmat[4][4], imat[4][4];
			float offset[3];
			
			if (to_global)
				copy_m4_m4(imat, target_ob->obmat);
			else {
				/* note: using target_dm here, which is in target_ob object space and has full modifiers */
				psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat);
				invert_m4_m4(imat, hairmat);
			}
			mul_m4_m4m4(imat, imat, to_imat);
			
			/* offset in world space */
			sub_v3_v3v3(offset, nearest.co, from_co);
			
			if (edit_point) {
				for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) {
					float co_orig[3];
					
					if (from_global)
						mul_v3_m4v3(co_orig, from_ob_imat, key->co);
					else
						mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
					mul_m4_v3(from_mat, co_orig);
					
					add_v3_v3v3(tkey->co, co_orig, offset);
					
					mul_m4_v3(imat, tkey->co);
					
					ekey->flag |= PEK_USE_WCO;
				}
				
				edit_point++;
			}
			else {
				for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) {
					float co_orig[3];
					
					if (from_global)
						mul_v3_m4v3(co_orig, from_ob_imat, key->co);
					else
						mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
					mul_m4_v3(from_mat, co_orig);
					
					add_v3_v3v3(tkey->co, co_orig, offset);
					
					mul_m4_v3(imat, tkey->co);
				}
			}
		}
	}

	free_bvhtree_from_mesh(&bvhtree);
	dm->release(dm);

	psys_free_path_cache(target_psys, target_edit);

	PE_update_object(scene, target_ob, 0);

	return true;
}
Ejemplo n.º 6
0
static void normalEditModifier_do_directional(
        NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm,
        short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
        const short mix_mode, const float mix_factor, const float mix_limit,
        MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
        MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
        MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
{
	const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;

	float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__);
	float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__);

	float target_co[3];
	int i;

	dm->getVertCos(dm, cos);

	/* Get target's center coordinates in ob local coordinates. */
	{
		float mat[4][4];

		invert_m4_m4(mat, ob->obmat);
		mul_m4_m4m4(mat, mat, enmd->target->obmat);
		copy_v3_v3(target_co, mat[3]);
	}

	if (use_parallel_normals) {
		float no[3];

		sub_v3_v3v3(no, target_co, enmd->offset);
		normalize_v3(no);

		for (i = num_loops; i--; ) {
			copy_v3_v3(nos[i], no);
		}
	}
	else {
		BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
		MLoop *ml;
		float (*no)[3];

		/* We reuse cos to now store the 'to target' normal of the verts! */
		for (i = num_loops, no = nos, ml = mloop; i--; no++, ml++) {
			const int vidx = ml->v;
			float *co = cos[vidx];

			if (!BLI_BITMAP_TEST(done_verts, vidx)) {
				sub_v3_v3v3(co, target_co, co);
				normalize_v3(co);

				BLI_BITMAP_ENABLE(done_verts, vidx);
			}

			copy_v3_v3(*no, co);
		}

		MEM_freeN(done_verts);
	}

	if (loopnors) {
		mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
		            mix_limit, mix_mode, num_verts, mloop, loopnors, nos, num_loops);
	}

	if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
		dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
	}

	BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
	                                 mpoly, (const float(*)[3])polynors, num_polys, clnors);

	MEM_freeN(cos);
	MEM_freeN(nos);
}
Ejemplo n.º 7
0
/* render call to fill in strands */
int zbuffer_strands_abuf(Render *re, RenderPart *pa, APixstrand *apixbuf, ListBase *apsmbase, unsigned int lay, int UNUSED(negzmask), float winmat[4][4], int winx, int winy, int samples, float (*jit)[2], float clipcrop, int shadow, StrandShadeCache *cache)
{
	ObjectRen *obr;
	ObjectInstanceRen *obi;
	ZSpan zspan;
	StrandRen *strand=0;
	StrandVert *svert;
	StrandBound *sbound;
	StrandPart spart;
	StrandSegment sseg;
	StrandSortSegment *sortsegments = NULL, *sortseg, *firstseg;
	MemArena *memarena;
	float z[4], bounds[4], obwinmat[4][4];
	int a, b, c, i, totsegment, clip[4];

	if (re->test_break(re->tbh))
		return 0;
	if (re->totstrand == 0)
		return 0;

	/* setup StrandPart */
	memset(&spart, 0, sizeof(spart));

	spart.re= re;
	spart.rectx= pa->rectx;
	spart.recty= pa->recty;
	spart.apixbuf= apixbuf;
	spart.zspan= &zspan;
	spart.rectdaps= pa->rectdaps;
	spart.rectz= pa->rectz;
	spart.rectmask= pa->rectmask;
	spart.cache= cache;
	spart.shadow= shadow;
	spart.jit= jit;
	spart.samples= samples;

	zbuf_alloc_span(&zspan, pa->rectx, pa->recty, clipcrop);

	/* needed for transform from hoco to zbuffer co */
	zspan.zmulx= ((float)winx)/2.0f;
	zspan.zmuly= ((float)winy)/2.0f;
	
	zspan.zofsx= -pa->disprect.xmin;
	zspan.zofsy= -pa->disprect.ymin;

	/* to center the sample position */
	if (!shadow) {
		zspan.zofsx -= 0.5f;
		zspan.zofsy -= 0.5f;
	}

	zspan.apsmbase= apsmbase;

	/* clipping setup */
	bounds[0]= (2*pa->disprect.xmin - winx-1)/(float)winx;
	bounds[1]= (2*pa->disprect.xmax - winx+1)/(float)winx;
	bounds[2]= (2*pa->disprect.ymin - winy-1)/(float)winy;
	bounds[3]= (2*pa->disprect.ymax - winy+1)/(float)winy;

	memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "strand sort arena");
	firstseg= NULL;
	totsegment= 0;

	/* for all object instances */
	for (obi=re->instancetable.first, i=0; obi; obi=obi->next, i++) {
		Material *ma;
		float widthx, widthy;

		obr= obi->obr;

		if (!obr->strandbuf || !(obr->strandbuf->lay & lay))
			continue;

		/* compute matrix and try clipping whole object */
		if (obi->flag & R_TRANSFORMED)
			mul_m4_m4m4(obwinmat, winmat, obi->mat);
		else
			copy_m4_m4(obwinmat, winmat);

		/* test if we should skip it */
		ma = obr->strandbuf->ma;

		if (shadow && !(ma->mode & MA_SHADBUF))
			continue;
		else if (!shadow && (ma->mode & MA_ONLYCAST))
			continue;

		if (clip_render_object(obi->obr->boundbox, bounds, obwinmat))
			continue;
		
		widthx= obr->strandbuf->maxwidth*obwinmat[0][0];
		widthy= obr->strandbuf->maxwidth*obwinmat[1][1];

		/* for each bounding box containing a number of strands */
		sbound= obr->strandbuf->bound;
		for (c=0; c<obr->strandbuf->totbound; c++, sbound++) {
			if (clip_render_object(sbound->boundbox, bounds, obwinmat))
				continue;

			/* for each strand in this bounding box */
			for (a=sbound->start; a<sbound->end; a++) {
				strand= RE_findOrAddStrand(obr, a);
				svert= strand->vert;

				/* keep clipping and z depth for 4 control points */
				clip[1]= strand_test_clip(obwinmat, &zspan, bounds, svert->co, &z[1], widthx, widthy);
				clip[2]= strand_test_clip(obwinmat, &zspan, bounds, (svert+1)->co, &z[2], widthx, widthy);
				clip[0]= clip[1]; z[0]= z[1];

				for (b=0; b<strand->totvert-1; b++, svert++) {
					/* compute 4th point clipping and z depth */
					if (b < strand->totvert-2) {
						clip[3]= strand_test_clip(obwinmat, &zspan, bounds, (svert+2)->co, &z[3], widthx, widthy);
					}
					else {
						clip[3]= clip[2]; z[3]= z[2];
					}

					/* check clipping and add to sortsegments buffer */
					if (!(clip[0] & clip[1] & clip[2] & clip[3])) {
						sortseg= BLI_memarena_alloc(memarena, sizeof(StrandSortSegment));
						sortseg->obi= i;
						sortseg->strand= strand->index;
						sortseg->segment= b;

						sortseg->z= 0.5f*(z[1] + z[2]);

						sortseg->next= firstseg;
						firstseg= sortseg;
						totsegment++;
					}

					/* shift clipping and z depth */
					clip[0]= clip[1]; z[0]= z[1];
					clip[1]= clip[2]; z[1]= z[2];
					clip[2]= clip[3]; z[2]= z[3];
				}
			}
		}
	}

	if (!re->test_break(re->tbh)) {
		/* convert list to array and sort */
		sortsegments= MEM_mallocN(sizeof(StrandSortSegment)*totsegment, "StrandSortSegment");
		for (a=0, sortseg=firstseg; a<totsegment; a++, sortseg=sortseg->next)
			sortsegments[a]= *sortseg;
		qsort(sortsegments, totsegment, sizeof(StrandSortSegment), compare_strand_segment);
	}

	BLI_memarena_free(memarena);

	spart.totapixbuf= MEM_callocN(sizeof(int)*pa->rectx*pa->recty, "totapixbuf");

	if (!re->test_break(re->tbh)) {
		/* render segments in sorted order */
		sortseg= sortsegments;
		for (a=0; a<totsegment; a++, sortseg++) {
			if (re->test_break(re->tbh))
				break;

			obi= &re->objectinstance[sortseg->obi];
			obr= obi->obr;

			sseg.obi= obi;
			sseg.strand= RE_findOrAddStrand(obr, sortseg->strand);
			sseg.buffer= sseg.strand->buffer;
			sseg.sqadaptcos= sseg.buffer->adaptcos;
			sseg.sqadaptcos *= sseg.sqadaptcos;

			svert= sseg.strand->vert + sortseg->segment;
			sseg.v[0]= (sortseg->segment > 0)? (svert-1): svert;
			sseg.v[1]= svert;
			sseg.v[2]= svert+1;
			sseg.v[3]= (sortseg->segment < sseg.strand->totvert-2)? svert+2: svert+1;
			sseg.shaded= 0;

			spart.segment= &sseg;

			render_strand_segment(re, winmat, &spart, &zspan, 1, &sseg);
		}
	}

	if (sortsegments)
		MEM_freeN(sortsegments);
	MEM_freeN(spart.totapixbuf);
	
	zbuf_free_span(&zspan);

	return totsegment;
}
std::string AnimationExporter::create_4x4_source(std::vector<float> &frames, Object *ob, Bone *bone, const std::string &anim_id)
{
	COLLADASW::InputSemantic::Semantics semantic = COLLADASW::InputSemantic::OUTPUT;
	std::string source_id = anim_id + get_semantic_suffix(semantic);

	COLLADASW::Float4x4Source source(mSW);
	source.setId(source_id);
	source.setArrayId(source_id + ARRAY_ID_SUFFIX);
	source.setAccessorCount(frames.size());
	source.setAccessorStride(16);

	COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
	add_source_parameters(param, semantic, false, NULL, true);

	source.prepareToAppendValues();

	bPoseChannel *parchan = NULL;
	bPoseChannel *pchan = NULL;

	if (ob->type == OB_ARMATURE && bone) {
		bPose *pose = ob->pose;
		pchan = BKE_pose_channel_find_name(pose, bone->name);
		if (!pchan)
			return "";

		parchan = pchan->parent;

		enable_fcurves(ob->adt->action, bone->name);
	}
	
	std::vector<float>::iterator it;
	int j = 0;
	for (it = frames.begin(); it != frames.end(); it++) {
		float mat[4][4], ipar[4][4];

		float ctime = BKE_scene_frame_get_from_ctime(scene, *it);
		CFRA = BKE_scene_frame_get_from_ctime(scene, *it);
		//BKE_scene_update_for_newframe(G.main->eval_ctx, G.main,scene,scene->lay);
		BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
				
		if (bone) {
			if (pchan->flag & POSE_CHAIN) {
				enable_fcurves(ob->adt->action, NULL);
				BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL);
				BKE_pose_where_is(scene, ob);
			}
			else {
				BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
			}
			
			// compute bone local mat
			if (bone->parent) {
				invert_m4_m4(ipar, parchan->pose_mat);
				mul_m4_m4m4(mat, ipar, pchan->pose_mat);
			}
			else
				copy_m4_m4(mat, pchan->pose_mat);
			
		// OPEN_SIM_COMPATIBILITY
		// AFAIK animation to second life is via BVH, but no
		// reason to not have the collada-animation be correct
			if (export_settings->open_sim) {
				float temp[4][4];
				copy_m4_m4(temp, bone->arm_mat);
				temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;
				invert_m4(temp);

				mul_m4_m4m4(mat, mat, temp);

				if (bone->parent) {
					copy_m4_m4(temp, bone->parent->arm_mat);
					temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;

					mul_m4_m4m4(mat, temp, mat);
				}
			}

		}
		else {
			calc_ob_mat_at_time(ob, ctime, mat);
		}
		
		UnitConverter converter;

		double outmat[4][4];
		converter.mat4_to_dae_double(outmat, mat);

		source.appendValues(outmat);

		j++;

		BIK_release_tree(scene, ob, ctime);
	}

	if (ob->adt) {
		enable_fcurves(ob->adt->action, NULL);
	}

	source.finish();

	return source_id;
}
Ejemplo n.º 9
0
/* Warning: be sure to account for a negative return value
*   This is an error, "Too many objects in select buffer"
*   and no action should be taken (can crash blender) if this happens
*/
short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
{
	Scene *scene= vc->scene;
	View3D *v3d= vc->v3d;
	ARegion *ar= vc->ar;
	rctf rect;
	short code, hits;
	char dt, dtx;
	
	G.f |= G_PICKSEL;
	
	/* case not a border select */
	if(input->xmin==input->xmax) {
		rect.xmin= input->xmin-12;	// seems to be default value for bones only now
		rect.xmax= input->xmin+12;
		rect.ymin= input->ymin-12;
		rect.ymax= input->ymin+12;
	}
	else {
		rect.xmin= input->xmin;
		rect.xmax= input->xmax;
		rect.ymin= input->ymin;
		rect.ymax= input->ymax;
	}
	
	setwinmatrixview3d(ar, v3d, &rect);
	mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
	
	if(v3d->drawtype > OB_WIRE) {
		v3d->zbuf= TRUE;
		glEnable(GL_DEPTH_TEST);
	}
	
	if(vc->rv3d->rflag & RV3D_CLIPPING)
		view3d_set_clipping(vc->rv3d);
	
	glSelectBuffer( bufsize, (GLuint *)buffer);
	glRenderMode(GL_SELECT);
	glInitNames();	/* these two calls whatfor? It doesnt work otherwise */
	glPushName(-1);
	code= 1;
	
	if(vc->obedit && vc->obedit->type==OB_MBALL) {
		draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
	}
	else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
		/* if not drawing sketch, draw bones */
		if(!BDR_drawSketchNames(vc)) {
			draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
		}
	}
	else {
		Base *base;
		
		v3d->xray= TRUE;	// otherwise it postpones drawing
		for(base= scene->base.first; base; base= base->next) {
			if(base->lay & v3d->lay) {
				
				if (base->object->restrictflag & OB_RESTRICT_SELECT)
					base->selcol= 0;
				else {
					base->selcol= code;
					glLoadName(code);
					draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
					
					/* we draw group-duplicators for selection too */
					if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
						ListBase *lb;
						DupliObject *dob;
						Base tbase;
						
						tbase.flag= OB_FROMDUPLI;
						lb= object_duplilist(scene, base->object);
						
						for(dob= lb->first; dob; dob= dob->next) {
							tbase.object= dob->ob;
							copy_m4_m4(dob->ob->obmat, dob->mat);
							
							/* extra service: draw the duplicator in drawtype of parent */
							/* MIN2 for the drawtype to allow bounding box objects in groups for lods */
							dt= tbase.object->dt;	tbase.object->dt= MIN2(tbase.object->dt, base->object->dt);
							dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;

							draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
							
							tbase.object->dt= dt;
							tbase.object->dtx= dtx;

							copy_m4_m4(dob->ob->obmat, dob->omat);
						}
						free_object_duplilist(lb);
					}
					code++;
				}				
			}
		}
		v3d->xray= FALSE;	// restore
	}
	
	glPopName();	/* see above (pushname) */
	hits= glRenderMode(GL_RENDER);
	
	G.f &= ~G_PICKSEL;
	setwinmatrixview3d(ar, v3d, NULL);
	mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
	
	if(v3d->drawtype > OB_WIRE) {
		v3d->zbuf= 0;
		glDisable(GL_DEPTH_TEST);
	}
// XXX	persp(PERSP_WIN);
	
	if(vc->rv3d->rflag & RV3D_CLIPPING)
		view3d_clr_clipping();
	
	if(hits<0) printf("Too many objects in select buffer\n");	// XXX make error message
	
	return hits;
}
Ejemplo n.º 10
0
static int set_plane_exec(bContext *C, wmOperator *op)
{
  SpaceClip *sc = CTX_wm_space_clip(C);
  MovieClip *clip = ED_space_clip_get_clip(sc);
  Scene *scene = CTX_data_scene(C);
  MovieTracking *tracking = &clip->tracking;
  MovieTrackingObject *tracking_object;
  MovieTrackingTrack *track, *axis_track = NULL, *act_track;
  ListBase *tracksbase;
  Object *object;
  Object *camera = get_camera_with_movieclip(scene, clip);
  Depsgraph *depsgraph = CTX_data_depsgraph(C);
  int tot = 0;
  float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
  int plane = RNA_enum_get(op->ptr, "plane");
  float rot[4][4] = {
      {0.0f, 0.0f, -1.0f, 0.0f},
      {0.0f, 1.0f, 0.0f, 0.0f},
      {1.0f, 0.0f, 0.0f, 0.0f},
      {0.0f, 0.0f, 0.0f, 1.0f},
  }; /* 90 degrees Y-axis rotation matrix */

  if (count_selected_bundles(C) != 3) {
    BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");

    return OPERATOR_CANCELLED;
  }

  tracking_object = BKE_tracking_object_get_active(tracking);
  tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
  act_track = BKE_tracking_track_get_active(tracking);

  object = get_orientation_object(C);
  if (object == NULL) {
    BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
    return OPERATOR_CANCELLED;
  }

  BKE_tracking_get_camera_object_matrix(scene, camera, mat);

  /* Get 3 bundles to use as reference. */
  track = tracksbase->first;
  while (track && tot < 3) {
    if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
      mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
      if (tot == 0 || track == act_track) {
        copy_v3_v3(orig, vec[tot]);
      }
      else {
        axis_track = track;
      }
      tot++;
    }
    track = track->next;
  }

  sub_v3_v3(vec[1], vec[0]);
  sub_v3_v3(vec[2], vec[0]);

  /* Construct ortho-normal basis. */
  unit_m4(mat);
  if (plane == 0) { /* floor */
    cross_v3_v3v3(mat[0], vec[1], vec[2]);
    copy_v3_v3(mat[1], vec[1]);
    cross_v3_v3v3(mat[2], mat[0], mat[1]);
  }
  else if (plane == 1) { /* wall */
    cross_v3_v3v3(mat[2], vec[1], vec[2]);
    copy_v3_v3(mat[1], vec[1]);
    cross_v3_v3v3(mat[0], mat[1], mat[2]);
  }

  normalize_v3(mat[0]);
  normalize_v3(mat[1]);
  normalize_v3(mat[2]);

  /* Move to origin point. */
  mat[3][0] = orig[0];
  mat[3][1] = orig[1];
  mat[3][2] = orig[2];

  if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
    invert_m4(mat);

    BKE_object_to_mat4(object, obmat);
    mul_m4_m4m4(mat, mat, obmat);
    mul_m4_m4m4(newmat, rot, mat);
    BKE_object_apply_mat4(object, newmat, 0, 0);

    /* Make camera have positive z-coordinate. */
    if (object->loc[2] < 0) {
      invert_m4(rot);
      mul_m4_m4m4(newmat, rot, mat);
      BKE_object_apply_mat4(object, newmat, 0, 0);
    }
  }
  else {
    BKE_object_apply_mat4(object, mat, 0, 0);
  }

  BKE_object_where_is_calc(depsgraph, scene, object);
  set_axis(scene, object, clip, tracking_object, axis_track, 'X');

  DEG_id_tag_update(&clip->id, 0);
  DEG_id_tag_update(&object->id, ID_RECALC_TRANSFORM);

  WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
  WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);

  return OPERATOR_FINISHED;
}
Ejemplo n.º 11
0
static void meshdeformModifier_do(
        ModifierData *md, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
	struct Mesh *me = (mmd->object) ? mmd->object->data : NULL;
	BMEditMesh *em = me ? me->edit_btmesh : NULL;
	DerivedMesh *tmpdm, *cagedm;
	MDeformVert *dvert = NULL;
	MDefInfluence *influences;
	int *offsets;
	float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4];
	float weight, totweight, fac, co[3], (*dco)[3], (*bindcagecos)[3];
	int a, b, totvert, totcagevert, defgrp_index;
	float (*cagecos)[3];

	if (!mmd->object || (!mmd->bindcagecos && !mmd->bindfunc))
		return;
	
	/* get cage derivedmesh */
	if (em) {
		tmpdm = editbmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0);
		if (tmpdm)
			tmpdm->release(tmpdm);
	}
	else
		cagedm = mmd->object->derivedFinal;

	/* if we don't have one computed, use derivedmesh from data
	 * without any modifiers */
	if (!cagedm) {
		cagedm = get_dm(mmd->object, NULL, NULL, NULL, false, false);
		if (cagedm)
			cagedm->needsFree = 1;
	}
	
	if (!cagedm) {
		modifier_setError(md, "Cannot get mesh from cage object");
		return;
	}

	/* compute matrices to go in and out of cage object space */
	invert_m4_m4(imat, mmd->object->obmat);
	mul_m4_m4m4(cagemat, imat, ob->obmat);
	mul_m4_m4m4(cmat, mmd->bindmat, cagemat);
	invert_m4_m4(iobmat, cmat);
	copy_m3_m4(icagemat, iobmat);

	/* bind weights if needed */
	if (!mmd->bindcagecos) {
		static int recursive = 0;

		/* progress bar redraw can make this recursive .. */
		if (!recursive) {
			recursive = 1;
			mmd->bindfunc(md->scene, mmd, (float *)vertexCos, numVerts, cagemat);
			recursive = 0;
		}
	}

	/* verify we have compatible weights */
	totvert = numVerts;
	totcagevert = cagedm->getNumVerts(cagedm);

	if (mmd->totvert != totvert) {
		modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert);
		cagedm->release(cagedm);
		return;
	}
	else if (mmd->totcagevert != totcagevert) {
		modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert);
		cagedm->release(cagedm);
		return;
	}
	else if (mmd->bindcagecos == NULL) {
		modifier_setError(md, "Bind data missing");
		cagedm->release(cagedm);
		return;
	}

	cagecos = MEM_callocN(sizeof(*cagecos) * totcagevert, "meshdeformModifier vertCos");

	/* setup deformation data */
	cagedm->getVertCos(cagedm, cagecos);
	influences = mmd->bindinfluences;
	offsets = mmd->bindoffsets;
	bindcagecos = (float(*)[3])mmd->bindcagecos;

	dco = MEM_callocN(sizeof(*dco) * totcagevert, "MDefDco");
	for (a = 0; a < totcagevert; a++) {
		/* get cage vertex in world space with binding transform */
		copy_v3_v3(co, cagecos[a]);

		if (G.debug_value != 527) {
			mul_m4_v3(mmd->bindmat, co);
			/* compute difference with world space bind coord */
			sub_v3_v3v3(dco[a], co, bindcagecos[a]);
		}
		else
			copy_v3_v3(dco[a], co);
	}

	modifier_get_vgroup(ob, dm, mmd->defgrp_name, &dvert, &defgrp_index);

	/* do deformation */
	fac = 1.0f;

	for (b = 0; b < totvert; b++) {
		if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
			if (!mmd->dynverts[b])
				continue;

		if (dvert) {
			fac = defvert_find_weight(&dvert[b], defgrp_index);

			if (mmd->flag & MOD_MDEF_INVERT_VGROUP) {
				fac = 1.0f - fac;
			}

			if (fac <= 0.0f) {
				continue;
			}
		}

		if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
			/* transform coordinate into cage's local space */
			mul_v3_m4v3(co, cagemat, vertexCos[b]);
			totweight = meshdeform_dynamic_bind(mmd, dco, co);
		}
		else {
			totweight = 0.0f;
			zero_v3(co);

			for (a = offsets[b]; a < offsets[b + 1]; a++) {
				weight = influences[a].weight;
				madd_v3_v3fl(co, dco[influences[a].vertex], weight);
				totweight += weight;
			}
		}

		if (totweight > 0.0f) {
			mul_v3_fl(co, fac / totweight);
			mul_m3_v3(icagemat, co);
			if (G.debug_value != 527)
				add_v3_v3(vertexCos[b], co);
			else
				copy_v3_v3(vertexCos[b], co);
		}
	}

	/* release cage derivedmesh */
	MEM_freeN(dco);
	MEM_freeN(cagecos);
	cagedm->release(cagedm);
}
Ejemplo n.º 12
0
static void set_axis(Scene *scene,
                     Object *ob,
                     MovieClip *clip,
                     MovieTrackingObject *tracking_object,
                     MovieTrackingTrack *track,
                     char axis)
{
  Object *camera = get_camera_with_movieclip(scene, clip);
  const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
  bool flip = false;
  float mat[4][4], vec[3], obmat[4][4], dvec[3];

  BKE_object_to_mat4(ob, obmat);

  BKE_tracking_get_camera_object_matrix(scene, camera, mat);
  mul_v3_m4v3(vec, mat, track->bundle_pos);
  copy_v3_v3(dvec, vec);

  if (!is_camera) {
    float imat[4][4];

    object_solver_inverted_matrix(scene, ob, imat);
    mul_v3_m4v3(vec, imat, vec);

    invert_m4_m4(imat, obmat);
    mul_v3_m4v3(dvec, imat, vec);

    sub_v3_v3(vec, obmat[3]);
  }

  if (len_squared_v2(vec) < (1e-3f * 1e-3f)) {
    return;
  }

  unit_m4(mat);

  if (axis == 'X') {
    if (fabsf(dvec[1]) < 1e-3f) {
      flip = true;

      mat[0][0] = -1.0f;
      mat[0][1] = 0.0f;
      mat[0][2] = 0.0f;
      mat[1][0] = 0.0f;
      mat[1][1] = -1.0f;
      mat[1][2] = 0.0f;
      mat[2][0] = 0.0f;
      mat[2][1] = 0.0f;
      mat[2][2] = 1.0f;
    }
    else {
      copy_v3_v3(mat[0], vec);

      if (is_camera || fabsf(vec[2]) < 1e-3f) {
        mat[0][2] = 0.0f;
        mat[2][0] = 0.0f;
        mat[2][1] = 0.0f;
        mat[2][2] = 1.0f;
        cross_v3_v3v3(mat[1], mat[2], mat[0]);
      }
      else {
        vec[2] = 0.0f;

        cross_v3_v3v3(mat[1], mat[0], vec);
        cross_v3_v3v3(mat[2], mat[0], mat[1]);
      }
    }
  }
  else {
    if (fabsf(dvec[0]) < 1e-3f) {
      flip = true;

      mat[0][0] = -1.0f;
      mat[0][1] = 0.0f;
      mat[0][2] = 0.0f;
      mat[1][0] = 0.0f;
      mat[1][1] = -1.0f;
      mat[1][2] = 0.0f;
      mat[2][0] = 0.0f;
      mat[2][1] = 0.0f;
      mat[2][2] = 1.0f;
    }
    else {
      copy_v3_v3(mat[1], vec);

      if (is_camera || fabsf(vec[2]) < 1e-3f) {
        mat[1][2] = 0.0f;
        mat[2][0] = 0.0f;
        mat[2][1] = 0.0f;
        mat[2][2] = 1.0f;
        cross_v3_v3v3(mat[0], mat[1], mat[2]);
      }
      else {
        vec[2] = 0.0f;

        cross_v3_v3v3(mat[0], vec, mat[1]);
        cross_v3_v3v3(mat[2], mat[0], mat[1]);
      }
    }
  }

  normalize_v3(mat[0]);
  normalize_v3(mat[1]);
  normalize_v3(mat[2]);

  if (is_camera) {
    invert_m4(mat);

    mul_m4_m4m4(mat, mat, obmat);
  }
  else {
    if (!flip) {
      float lmat[4][4], ilmat[4][4], rmat[3][3];

      BKE_object_rot_to_mat3(ob, rmat, true);
      invert_m3(rmat);
      mul_m4_m4m3(mat, mat, rmat);

      unit_m4(lmat);
      copy_v3_v3(lmat[3], obmat[3]);
      invert_m4_m4(ilmat, lmat);

      mul_m4_series(mat, lmat, mat, ilmat, obmat);
    }
    else {
      mul_m4_m4m4(mat, obmat, mat);
    }
  }

  BKE_object_apply_mat4(ob, mat, 0, 0);
}
Ejemplo n.º 13
0
std::string ControllerExporter::add_inv_bind_mats_source(Object *ob_arm, ListBase *defbase, const std::string& controller_id)
{
	std::string source_id = controller_id + BIND_POSES_SOURCE_ID_SUFFIX;

	int totjoint = 0;
	for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) {
		if (is_bone_defgroup(ob_arm, def))
			totjoint++;
	}

	COLLADASW::FloatSourceF source(mSW);
	source.setId(source_id);
	source.setArrayId(source_id + ARRAY_ID_SUFFIX);
	source.setAccessorCount(totjoint); //BLI_countlist(defbase));
	source.setAccessorStride(16);
	
	source.setParameterTypeName(&COLLADASW::CSWC::CSW_VALUE_TYPE_FLOAT4x4);
	COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
	param.push_back("TRANSFORM");

	source.prepareToAppendValues();

	bPose *pose = ob_arm->pose;
	bArmature *arm = (bArmature *)ob_arm->data;

	int flag = arm->flag;

	// put armature in rest position
	if (!(arm->flag & ARM_RESTPOS)) {
		arm->flag |= ARM_RESTPOS;
		BKE_pose_where_is(scene, ob_arm);
	}

	for (bDeformGroup *def = (bDeformGroup *)defbase->first; def; def = def->next) {
		if (is_bone_defgroup(ob_arm, def)) {
			bPoseChannel *pchan = BKE_pose_channel_find_name(pose, def->name);

			float mat[4][4];
			float world[4][4];
			float inv_bind_mat[4][4];

			// OPEN_SIM_COMPATIBILITY
			if (export_settings->open_sim) {
				// Only translations, no rotation vs armature
				float temp[4][4];
				unit_m4(temp);
				copy_v3_v3(temp[3], pchan->bone->arm_mat[3]);
				mul_m4_m4m4(world, ob_arm->obmat, temp);
			}
			else {
				// make world-space matrix, arm_mat is armature-space
				mul_m4_m4m4(world, ob_arm->obmat, pchan->bone->arm_mat);
			}

			invert_m4_m4(mat, world);
			converter.mat4_to_dae(inv_bind_mat, mat);

			source.appendValues(inv_bind_mat);
		}
	}

	// back from rest positon
	if (!(flag & ARM_RESTPOS)) {
		arm->flag = flag;
		BKE_pose_where_is(scene, ob_arm);
	}

	source.finish();

	return source_id;
}
Ejemplo n.º 14
0
static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
{
	Camera *data = (Camera *)camera->data;
	float interocular_distance, convergence_distance;
	short convergence_mode, pivot;
	float sizemat[4][4];

	float fac = 1.0f;
	float fac_signed;

	interocular_distance = data->stereo.interocular_distance;
	convergence_distance = data->stereo.convergence_distance;
	convergence_mode = data->stereo.convergence_mode;
	pivot = data->stereo.pivot;

	if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
	    ((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
	{
		camera_model_matrix(camera, r_modelmat);
		return;
	}
	else {
		float size[3];
		mat4_to_size(size, camera->obmat);
		size_to_mat4(sizemat, size);
	}

	if (pivot == CAM_S3D_PIVOT_CENTER)
		fac = 0.5f;

	fac_signed = is_left ? fac : -fac;

	/* rotation */
	if (convergence_mode == CAM_S3D_TOE) {
		float angle;
		float angle_sin, angle_cos;
		float toeinmat[4][4];
		float rotmat[4][4];

		unit_m4(rotmat);

		if (pivot == CAM_S3D_PIVOT_CENTER) {
			fac = -fac;
			fac_signed = -fac_signed;
		}

		angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac;

		angle_cos = cosf(angle * fac_signed);
		angle_sin = sinf(angle * fac_signed);

		rotmat[0][0] =  angle_cos;
		rotmat[2][0] = -angle_sin;
		rotmat[0][2] =  angle_sin;
		rotmat[2][2] =  angle_cos;

		if (pivot == CAM_S3D_PIVOT_CENTER) {
			/* set the rotation */
			copy_m4_m4(toeinmat, rotmat);
			/* set the translation */
			toeinmat[3][0] = interocular_distance * fac_signed;

			/* transform */
			normalize_m4_m4(r_modelmat, camera->obmat);
			mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);

			/* scale back to the original size */
			mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
		}
		else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
			/* rotate perpendicular to the interocular line */
			normalize_m4_m4(r_modelmat, camera->obmat);
			mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);

			/* translate along the interocular line */
			unit_m4(toeinmat);
			toeinmat[3][0] = -interocular_distance * fac_signed;
			mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);

			/* rotate to toe-in angle */
			mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);

			/* scale back to the original size */
			mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
		}
	}
	else {
		normalize_m4_m4(r_modelmat, camera->obmat);

		/* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
		translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);

		/* scale back to the original size */
		mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
	}
}
Ejemplo n.º 15
0
/* Retrieve reconstructed tracks from libmv to blender.
 * Actually, this also copies reconstructed cameras
 * from libmv to movie clip datablock.
 */
static bool reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking)
{
	struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
	MovieTrackingReconstruction *reconstruction = NULL;
	MovieReconstructedCamera *reconstructed;
	MovieTrackingTrack *track;
	ListBase *tracksbase =  NULL;
	int tracknr = 0, a;
	bool ok = true;
	bool origin_set = false;
	int sfra = context->sfra, efra = context->efra;
	float imat[4][4];

	if (context->is_camera) {
		tracksbase = &tracking->tracks;
		reconstruction = &tracking->reconstruction;
	}
	else {
		MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, context->object_name);

		tracksbase = &object->tracks;
		reconstruction = &object->reconstruction;
	}

	unit_m4(imat);

	track = tracksbase->first;
	while (track) {
		double pos[3];

		if (libmv_reprojectionPointForTrack(libmv_reconstruction, tracknr, pos)) {
			track->bundle_pos[0] = pos[0];
			track->bundle_pos[1] = pos[1];
			track->bundle_pos[2] = pos[2];

			track->flag |= TRACK_HAS_BUNDLE;
			track->error = libmv_reprojectionErrorForTrack(libmv_reconstruction, tracknr);
		}
		else {
			track->flag &= ~TRACK_HAS_BUNDLE;
			ok = false;

			printf("Unable to reconstruct position for track #%d '%s'\n", tracknr, track->name);
		}

		track = track->next;
		tracknr++;
	}

	if (reconstruction->cameras)
		MEM_freeN(reconstruction->cameras);

	reconstruction->camnr = 0;
	reconstruction->cameras = NULL;
	reconstructed = MEM_callocN((efra - sfra + 1) * sizeof(MovieReconstructedCamera),
	                            "temp reconstructed camera");

	for (a = sfra; a <= efra; a++) {
		double matd[4][4];

		if (libmv_reprojectionCameraForImage(libmv_reconstruction, a, matd)) {
			int i, j;
			float mat[4][4];
			float error = libmv_reprojectionErrorForImage(libmv_reconstruction, a);

			for (i = 0; i < 4; i++) {
				for (j = 0; j < 4; j++)
					mat[i][j] = matd[i][j];
			}

			/* Ensure first camera has got zero rotation and transform.
			 * This is essential for object tracking to work -- this way
			 * we'll always know object and environment are properly
			 * oriented.
			 *
			 * There's one weak part tho, which is requirement object
			 * motion starts at the same frame as camera motion does,
			 * otherwise that;' be a russian roulette whether object is
			 * aligned correct or not.
			 */
			if (!origin_set) {
				invert_m4_m4(imat, mat);
				unit_m4(mat);
				origin_set = true;
			}
			else {
				mul_m4_m4m4(mat, imat, mat);
			}

			copy_m4_m4(reconstructed[reconstruction->camnr].mat, mat);
			reconstructed[reconstruction->camnr].framenr = a;
			reconstructed[reconstruction->camnr].error = error;
			reconstruction->camnr++;
		}
		else {
			ok = false;
			printf("No camera for frame %d\n", a);
		}
	}

	if (reconstruction->camnr) {
		int size = reconstruction->camnr * sizeof(MovieReconstructedCamera);
		reconstruction->cameras = MEM_callocN(size, "reconstructed camera");
		memcpy(reconstruction->cameras, reconstructed, size);
	}

	if (origin_set) {
		track = tracksbase->first;
		while (track) {
			if (track->flag & TRACK_HAS_BUNDLE)
				mul_v3_m4v3(track->bundle_pos, imat, track->bundle_pos);

			track = track->next;
		}
	}

	MEM_freeN(reconstructed);

	return ok;
}
Ejemplo n.º 16
0
static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys)
{
	DerivedMesh* dm;
	ParticleKey state;
	ParticleSimulationData sim= {NULL};
	ParticleData *pa=NULL;
	float cfra = BKE_curframe(re->scene);
	int i /*, childexists*/ /* UNUSED */;
	int total_particles, offset=0;
	int data_used = point_data_used(pd);
	float partco[3];
	float obview[4][4];
	
	/* init everything */
	if (!psys || !ob || !pd) return;

	mul_m4_m4m4(obview, re->viewinv, ob->obmat);
	
	/* Just to create a valid rendering context for particles */
	psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0);
	
	dm = mesh_create_derived_render(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
	
	if ( !psys_check_enabled(ob, psys)) {
		psys_render_restore(ob, psys);
		return;
	}
	
	sim.scene= re->scene;
	sim.ob= ob;
	sim.psys= psys;

	/* in case ob->imat isn't up-to-date */
	invert_m4_m4(ob->imat, ob->obmat);
	
	total_particles = psys->totpart+psys->totchild;
	psys->lattice=psys_get_lattice(&sim);
	
	pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
	alloc_point_data(pd, total_particles, data_used);
	pd->totpoints = total_particles;
	if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3;
	
#if 0 /* UNUSED */
	if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
		childexists = 1;
#endif

	for (i=0, pa=psys->particles; i < total_particles; i++, pa++) {

		state.time = cfra;
		if(psys_get_particle_state(&sim, i, &state, 0)) {
			
			copy_v3_v3(partco, state.co);
			
			if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
				mul_m4_v3(ob->imat, partco);
			else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
				sub_v3_v3(partco, ob->loc);
			} else {
				/* TEX_PD_WORLDSPACE */
			}
			
			BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
			
			if (data_used & POINT_DATA_VEL) {
				pd->point_data[i*3 + 0] = state.vel[0];
				pd->point_data[i*3 + 1] = state.vel[1];
				pd->point_data[i*3 + 2] = state.vel[2];
			} 
			if (data_used & POINT_DATA_LIFE) {
				float pa_time;
				
				if (i < psys->totpart) {
					pa_time = (cfra - pa->time)/pa->lifetime;
				} else {
					ChildParticle *cpa= (psys->child + i) - psys->totpart;
					float pa_birthtime, pa_dietime;
					
					pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
				}
				
				pd->point_data[offset + i] = pa_time;
				
			}
		}
	}
	
	BLI_bvhtree_balance(pd->point_tree);
	dm->release(dm);
	
	if(psys->lattice){
		end_latt_deform(psys->lattice);
		psys->lattice=0;
	}
	
	psys_render_restore(ob, psys);
}
Ejemplo n.º 17
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag flag)
{
	DerivedMesh *dm = derivedData;
	DerivedMesh *result;
	ScrewModifierData *ltmd = (ScrewModifierData *) md;
	const int useRenderParams = flag & MOD_APPLY_RENDER;
	
	int *origindex;
	int mpoly_index = 0;
	int step;
	int i, j;
	unsigned int i1, i2;
	int step_tot = useRenderParams ? ltmd->render_steps : ltmd->steps;
	const int do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0;
	int maxVerts = 0, maxEdges = 0, maxPolys = 0;
	const unsigned int totvert = dm->getNumVerts(dm);
	const unsigned int totedge = dm->getNumEdges(dm);

	char axis_char = 'X', close;
	float angle = ltmd->angle;
	float screw_ofs = ltmd->screw_ofs;
	float axis_vec[3] = {0.0f, 0.0f, 0.0f};
	float tmp_vec1[3], tmp_vec2[3]; 
	float mat3[3][3];
	float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */
	float mtx_tx_inv[4][4]; /* inverted */
	float mtx_tmp_a[4][4];
	
	int vc_tot_linked = 0;
	short other_axis_1, other_axis_2;
	float *tmpf1, *tmpf2;

	int edge_offset;
	
	MPoly *mpoly_new, *mp_new;
	MLoop *mloop_new, *ml_new;
	MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new;
	MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base;

	ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL;

	const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0;

	/* don't do anything? */
	if (!totvert)
		return CDDM_from_template(dm, 0, 0, 0, 0, 0);

	switch (ltmd->axis) {
		case 0:
			other_axis_1 = 1;
			other_axis_2 = 2;
			break;
		case 1:
			other_axis_1 = 0;
			other_axis_2 = 2;
			break;
		default: /* 2, use default to quiet warnings */
			other_axis_1 = 0;
			other_axis_2 = 1;
			break;
	}

	axis_vec[ltmd->axis] = 1.0f;

	if (ltmd->ob_axis) {
		/* calc the matrix relative to the axis object */
		invert_m4_m4(mtx_tmp_a, ob->obmat);
		copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat);
		mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv);

		/* calc the axis vec */
		mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */
		normalize_v3(axis_vec);

		/* screw */
		if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) {
			/* find the offset along this axis relative to this objects matrix */
			float totlen = len_v3(mtx_tx[3]);

			if (totlen != 0.0f) {
				float zero[3] = {0.0f, 0.0f, 0.0f};
				float cp[3];
				screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec);
			}
			else {
				screw_ofs = 0.0f;
			}
		}

		/* angle */

#if 0   /* cant incluide this, not predictable enough, though quite fun. */
		if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) {
			float mtx3_tx[3][3];
			copy_m3_m4(mtx3_tx, mtx_tx);

			float vec[3] = {0, 1, 0};
			float cross1[3];
			float cross2[3];
			cross_v3_v3v3(cross1, vec, axis_vec);

			mul_v3_m3v3(cross2, mtx3_tx, cross1);
			{
				float c1[3];
				float c2[3];
				float axis_tmp[3];

				cross_v3_v3v3(c1, cross2, axis_vec);
				cross_v3_v3v3(c2, axis_vec, c1);


				angle = angle_v3v3(cross1, c2);

				cross_v3_v3v3(axis_tmp, cross1, c2);
				normalize_v3(axis_tmp);

				if (len_v3v3(axis_tmp, axis_vec) > 1.0f)
					angle = -angle;

			}
		}
#endif
	}
	else {
		/* exis char is used by i_rotate*/
		axis_char += ltmd->axis; /* 'X' + axis */

		/* useful to be able to use the axis vec in some cases still */
		zero_v3(axis_vec);
		axis_vec[ltmd->axis] = 1.0f;
	}

	/* apply the multiplier */
	angle *= ltmd->iter;
	screw_ofs *= ltmd->iter;

	/* multiplying the steps is a bit tricky, this works best */
	step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1);

	/* will the screw be closed?
	 * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */
	if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) &&
	    fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f))
	{
		close = 1;
		step_tot--;
		if (step_tot < 3) step_tot = 3;
	
		maxVerts = totvert  * step_tot;   /* -1 because we're joining back up */
		maxEdges = (totvert * step_tot) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys = totedge * step_tot;

		screw_ofs = 0.0f;
	}
	else {
		close = 0;
		if (step_tot < 3) step_tot = 3;

		maxVerts =  totvert  * step_tot; /* -1 because we're joining back up */
		maxEdges =  (totvert * (step_tot - 1)) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys =  totedge * (step_tot - 1);
	}
	
	result = CDDM_from_template(dm, maxVerts, maxEdges, 0, maxPolys * 4, maxPolys);
	
	/* copy verts from mesh */
	mvert_orig =    dm->getVertArray(dm);
	medge_orig =    dm->getEdgeArray(dm);
	
	mvert_new =     result->getVertArray(result);
	mpoly_new =     result->getPolyArray(result);
	mloop_new =     result->getLoopArray(result);
	medge_new =     result->getEdgeArray(result);

	if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) {
		CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, maxPolys);
	}

	origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	DM_copy_vert_data(dm, result, 0, 0, totvert); /* copy first otherwise this overwrites our own vertex normals */
	
	/* Set the locations of the first set of verts */
	
	mv_new = mvert_new;
	mv_orig = mvert_orig;
	
	/* Copy the first set of edges */
	med_orig = medge_orig;
	med_new = medge_new;
	for (i = 0; i < totedge; i++, med_orig++, med_new++) {
		med_new->v1 = med_orig->v1;
		med_new->v2 = med_orig->v2;
		med_new->crease = med_orig->crease;
		med_new->flag = med_orig->flag &  ~ME_LOOSEEDGE;
	}
	
	if (ltmd->flag & MOD_SCREW_NORMAL_CALC) {
		/*
		 * Normal Calculation (for face flipping)
		 * Sort edge verts for correct face flipping
		 * NOT REALLY NEEDED but face flipping is nice.
		 *
		 * */


		/* Notice!
		 *
		 * Since we are only ordering the edges here it can avoid mallocing the
		 * extra space by abusing the vert array before its filled with new verts.
		 * The new array for vert_connect must be at least sizeof(ScrewVertConnect) * totvert
		 * and the size of our resulting meshes array is sizeof(MVert) * totvert * 3
		 * so its safe to use the second 2 thrids of MVert the array for vert_connect,
		 * just make sure ScrewVertConnect struct is no more than twice as big as MVert,
		 * at the moment there is no chance of that being a problem,
		 * unless MVert becomes half its current size.
		 *
		 * once the edges are ordered, vert_connect is not needed and it can be used for verts
		 *
		 * This makes the modifier faster with one less alloc.
		 */

		vert_connect = MEM_mallocN(sizeof(ScrewVertConnect) * totvert, "ScrewVertConnect");
		//vert_connect = (ScrewVertConnect *) &medge_new[totvert];  /* skip the first slice of verts */
		vc = vert_connect;

		/* Copy Vert Locations */
		/* - We can do this in a later loop - only do here if no normal calc */
		if (!totedge) {
			for (i = 0; i < totvert; i++, mv_orig++, mv_new++) {
				copy_v3_v3(mv_new->co, mv_orig->co);
				normalize_v3_v3(vc->no, mv_new->co); /* no edges- this is really a dummy normal */
			}
		}
		else {
			/*printf("\n\n\n\n\nStarting Modifier\n");*/
			/* set edge users */
			med_new = medge_new;
			mv_new = mvert_new;

			if (ltmd->ob_axis) {
				/*mtx_tx is initialized early on */
				for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) {
					vc->co[0] = mv_new->co[0] = mv_orig->co[0];
					vc->co[1] = mv_new->co[1] = mv_orig->co[1];
					vc->co[2] = mv_new->co[2] = mv_orig->co[2];

					vc->flag = 0;
					vc->e[0] = vc->e[1] = NULL;
					vc->v[0] = vc->v[1] = -1;

					mul_m4_v3(mtx_tx, vc->co);
					/* length in 2d, don't sqrt because this is only for comparison */
					vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] +
					           vc->co[other_axis_2] * vc->co[other_axis_2];

					/* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/
				}
			}
			else {
				for (i = 0; i < totvert; i++, mv_new++, mv_orig++, vc++) {
					vc->co[0] = mv_new->co[0] = mv_orig->co[0];
					vc->co[1] = mv_new->co[1] = mv_orig->co[1];
					vc->co[2] = mv_new->co[2] = mv_orig->co[2];

					vc->flag = 0;
					vc->e[0] = vc->e[1] = NULL;
					vc->v[0] = vc->v[1] = -1;

					/* length in 2d, don't sqrt because this is only for comparison */
					vc->dist = vc->co[other_axis_1] * vc->co[other_axis_1] +
					           vc->co[other_axis_2] * vc->co[other_axis_2];

					/* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/
				}
			}

			/* this loop builds connectivity info for verts */
			for (i = 0; i < totedge; i++, med_new++) {
				vc = &vert_connect[med_new->v1];

				if (vc->v[0] == -1) { /* unused */
					vc->v[0] = med_new->v2;
					vc->e[0] = med_new;
				}
				else if (vc->v[1] == -1) {
					vc->v[1] = med_new->v2;
					vc->e[1] = med_new;
				}
				else {
					vc->v[0] = vc->v[1] = -2; /* error value  - don't use, 3 edges on vert */
				}

				vc = &vert_connect[med_new->v2];

				/* same as above but swap v1/2 */
				if (vc->v[0] == -1) { /* unused */
					vc->v[0] = med_new->v1;
					vc->e[0] = med_new;
				}
				else if (vc->v[1] == -1) {
					vc->v[1] = med_new->v1;
					vc->e[1] = med_new;
				}
				else {
					vc->v[0] = vc->v[1] = -2; /* error value  - don't use, 3 edges on vert */
				}
			}

			/* find the first vert */
			vc = vert_connect;
			for (i = 0; i < totvert; i++, vc++) {
				/* Now do search for connected verts, order all edges and flip them
				 * so resulting faces are flipped the right way */
				vc_tot_linked = 0; /* count the number of linked verts for this loop */
				if (vc->flag == 0) {
					int v_best = -1, ed_loop_closed = 0; /* vert and vert new */
					ScrewVertIter lt_iter;
					float fl = -1.0f;

					/* compiler complains if not initialized, but it should be initialized below */
					int ed_loop_flip = 0;

					/*printf("Loop on connected vert: %i\n", i);*/

					for (j = 0; j < 2; j++) {
						/*printf("\tSide: %i\n", j);*/
						screwvert_iter_init(&lt_iter, vert_connect, i, j);
						if (j == 1) {
							screwvert_iter_step(&lt_iter);
						}
						while (lt_iter.v_poin) {
							/*printf("\t\tVERT: %i\n", lt_iter.v);*/
							if (lt_iter.v_poin->flag) {
								/*printf("\t\t\tBreaking Found end\n");*/
								//endpoints[0] = endpoints[1] = -1;
								ed_loop_closed = 1; /* circle */
								break;
							}
							lt_iter.v_poin->flag = 1;
							vc_tot_linked++;
							/*printf("Testing 2 floats %f : %f\n", fl, lt_iter.v_poin->dist);*/
							if (fl <= lt_iter.v_poin->dist) {
								fl = lt_iter.v_poin->dist;
								v_best = lt_iter.v;
								/*printf("\t\t\tVERT BEST: %i\n", v_best);*/
							}
							screwvert_iter_step(&lt_iter);
							if (!lt_iter.v_poin) {
								/*printf("\t\t\tFound End Also Num %i\n", j);*/
								/*endpoints[j] = lt_iter.v_other;*/ /* other is still valid */
								break;
							}
						}
					}

					/* now we have a collection of used edges. flip their edges the right way*/
					/*if (v_best != -1) - */

					/*printf("Done Looking - vc_tot_linked: %i\n", vc_tot_linked);*/

					if (vc_tot_linked > 1) {
						float vf_1, vf_2, vf_best;

						vc_tmp = &vert_connect[v_best];

						tmpf1 = vert_connect[vc_tmp->v[0]].co;
						tmpf2 = vert_connect[vc_tmp->v[1]].co;


						/* edge connects on each side! */
						if ((vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1)) {
							/*printf("Verts on each side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/
							/* find out which is higher */

							vf_1 = tmpf1[ltmd->axis];
							vf_2 = tmpf2[ltmd->axis];
							vf_best = vc_tmp->co[ltmd->axis];

							if (vf_1 < vf_best && vf_best < vf_2) {
								ed_loop_flip = 0;
							}
							else if (vf_1 > vf_best && vf_best > vf_2) {
								ed_loop_flip = 1;
							}
							else {
								/* not so simple to work out which edge is higher */
								sub_v3_v3v3(tmp_vec1, tmpf1, vc_tmp->co);
								sub_v3_v3v3(tmp_vec2, tmpf2, vc_tmp->co);
								normalize_v3(tmp_vec1);
								normalize_v3(tmp_vec2);

								if (tmp_vec1[ltmd->axis] < tmp_vec2[ltmd->axis]) {
									ed_loop_flip = 1;
								}
								else {
									ed_loop_flip = 0;
								}
							}
						}
						else if (vc_tmp->v[0] >= 0) { /*vertex only connected on 1 side */
							/*printf("Verts on ONE side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/
							if (tmpf1[ltmd->axis] < vc_tmp->co[ltmd->axis]) { /* best is above */
								ed_loop_flip = 1;
							}
							else { /* best is below or even... in even case we cant know whet  to do. */
								ed_loop_flip = 0;
							}

						}
#if 0
						else {
							printf("No Connected ___\n");
						}
#endif

						/*printf("flip direction %i\n", ed_loop_flip);*/


						/* switch the flip option if set
						 * note: flip is now done at face level so copying vgroup slizes is easier */
#if 0
						if (do_flip)
							ed_loop_flip = !ed_loop_flip;
#endif

						if (angle < 0.0f)
							ed_loop_flip = !ed_loop_flip;

						/* if its closed, we only need 1 loop */
						for (j = ed_loop_closed; j < 2; j++) {
							/*printf("Ordering Side J %i\n", j);*/

							screwvert_iter_init(&lt_iter, vert_connect, v_best, j);
							/*printf("\n\nStarting - Loop\n");*/
							lt_iter.v_poin->flag = 1; /* so a non loop will traverse the other side */


							/* If this is the vert off the best vert and
							 * the best vert has 2 edges connected too it
							 * then swap the flip direction */
							if (j == 1 && (vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1))
								ed_loop_flip = !ed_loop_flip;

							while (lt_iter.v_poin && lt_iter.v_poin->flag != 2) {
								/*printf("\tOrdering Vert V %i\n", lt_iter.v);*/

								lt_iter.v_poin->flag = 2;
								if (lt_iter.e) {
									if (lt_iter.v == lt_iter.e->v1) {
										if (ed_loop_flip == 0) {
											/*printf("\t\t\tFlipping 0\n");*/
											SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
										}
										/* else {
										    printf("\t\t\tFlipping Not 0\n");
										   }*/
									}
									else if (lt_iter.v == lt_iter.e->v2) {
										if (ed_loop_flip == 1) {
											/*printf("\t\t\tFlipping 1\n");*/
											SWAP(unsigned int, lt_iter.e->v1, lt_iter.e->v2);
										}
										/* else {
										    printf("\t\t\tFlipping Not 1\n");
										   }*/
									}
									/* else {
									    printf("\t\tIncorrect edge topology");
									   }*/
								}
								/* else {
								    printf("\t\tNo Edge at this point\n");
								   }*/
								screwvert_iter_step(&lt_iter);
							}
						}
Ejemplo n.º 18
0
LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
{
	/* we make an array with all differences */
	Lattice *lt = oblatt->data;
	BPoint *bp;
	DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL;
	const float *co = dl ? dl->verts : NULL;
	float *fp, imat[4][4];
	float fu, fv, fw;
	int u, v, w;
	float *latticedata;
	float latmat[4][4];
	LatticeDeformData *lattice_deform_data;

	if (lt->editlatt) lt = lt->editlatt->latt;
	bp = lt->def;
	
	fp = latticedata = MEM_mallocN(sizeof(float) * 3 * lt->pntsu * lt->pntsv * lt->pntsw, "latticedata");
	
	/* for example with a particle system: (ob == NULL) */
	if (ob == NULL) {
		/* in deformspace, calc matrix  */
		invert_m4_m4(latmat, oblatt->obmat);
	
		/* back: put in deform array */
		invert_m4_m4(imat, latmat);
	}
	else {
		/* in deformspace, calc matrix */
		invert_m4_m4(imat, oblatt->obmat);
		mul_m4_m4m4(latmat, imat, ob->obmat);
	
		/* back: put in deform array */
		invert_m4_m4(imat, latmat);
	}
	
	for (w = 0, fw = lt->fw; w < lt->pntsw; w++, fw += lt->dw) {
		for (v = 0, fv = lt->fv; v < lt->pntsv; v++, fv += lt->dv) {
			for (u = 0, fu = lt->fu; u < lt->pntsu; u++, bp++, co += 3, fp += 3, fu += lt->du) {
				if (dl) {
					fp[0] = co[0] - fu;
					fp[1] = co[1] - fv;
					fp[2] = co[2] - fw;
				}
				else {
					fp[0] = bp->vec[0] - fu;
					fp[1] = bp->vec[1] - fv;
					fp[2] = bp->vec[2] - fw;
				}

				mul_mat3_m4_v3(imat, fp);
			}
		}
	}

	lattice_deform_data = MEM_mallocN(sizeof(LatticeDeformData), "Lattice Deform Data");
	lattice_deform_data->latticedata = latticedata;
	lattice_deform_data->object = oblatt;
	copy_m4_m4(lattice_deform_data->latmat, latmat);

	return lattice_deform_data;
}
Ejemplo n.º 19
0
// parent_mat is armature-space
void ArmatureExporter::add_bone_node(Bone *bone,
                                     Object *ob_arm,
                                     SceneExporter *se,
                                     std::vector<Object *> &child_objects)
{
  if (can_export(bone)) {
    std::string node_id = translate_id(id_name(ob_arm) + "_" + bone->name);
    std::string node_name = std::string(bone->name);
    std::string node_sid = get_joint_sid(bone);

    COLLADASW::Node node(mSW);

    node.setType(COLLADASW::Node::JOINT);
    node.setNodeId(node_id);
    node.setNodeName(node_name);
    node.setNodeSid(node_sid);

    if (this->export_settings.get_use_blender_profile()) {
      if (!is_export_root(bone)) {
        if (bone->flag & BONE_CONNECTED) {
          node.addExtraTechniqueParameter("blender", "connect", true);
        }
      }
      std::string layers = BoneExtended::get_bone_layers(bone->layer);
      node.addExtraTechniqueParameter("blender", "layer", layers);

      bArmature *armature = (bArmature *)ob_arm->data;
      EditBone *ebone = bc_get_edit_bone(armature, bone->name);
      if (ebone && ebone->roll != 0) {
        node.addExtraTechniqueParameter("blender", "roll", ebone->roll);
      }
      if (bc_is_leaf_bone(bone)) {
        Vector head, tail;
        const BCMatrix &global_transform = this->export_settings.get_global_transform();
        if (this->export_settings.get_apply_global_orientation()) {
          bc_add_global_transform(head, bone->arm_head, global_transform);
          bc_add_global_transform(tail, bone->arm_tail, global_transform);
        }
        else {
          copy_v3_v3(head, bone->arm_head);
          copy_v3_v3(tail, bone->arm_tail);
        }
        node.addExtraTechniqueParameter("blender", "tip_x", tail[0] - head[0]);
        node.addExtraTechniqueParameter("blender", "tip_y", tail[1] - head[1]);
        node.addExtraTechniqueParameter("blender", "tip_z", tail[2] - head[2]);
      }
    }

    node.start();

    add_bone_transform(ob_arm, bone, node);

    // Write nodes of childobjects, remove written objects from list
    std::vector<Object *>::iterator iter = child_objects.begin();

    while (iter != child_objects.end()) {
      Object *ob = *iter;
      if (ob->partype == PARBONE && STREQ(ob->parsubstr, bone->name)) {
        float backup_parinv[4][4];
        copy_m4_m4(backup_parinv, ob->parentinv);

        // crude, temporary change to parentinv
        // so transform gets exported correctly.

        // Add bone tail- translation... don't know why
        // bone parenting is against the tail of a bone
        // and not it's head, seems arbitrary.
        ob->parentinv[3][1] += bone->length;

        // OPEN_SIM_COMPATIBILITY
        // TODO: when such objects are animated as
        // single matrix the tweak must be applied
        // to the result.
        if (export_settings.get_open_sim()) {
          // tweak objects parentinverse to match compatibility
          float temp[4][4];

          copy_m4_m4(temp, bone->arm_mat);
          temp[3][0] = temp[3][1] = temp[3][2] = 0.0f;

          mul_m4_m4m4(ob->parentinv, temp, ob->parentinv);
        }

        se->writeNode(ob);
        copy_m4_m4(ob->parentinv, backup_parinv);
        iter = child_objects.erase(iter);
      }
      else
        iter++;
    }

    for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
      add_bone_node(child, ob_arm, se, child_objects);
    }
    node.end();
  }
  else {
    for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) {
      add_bone_node(child, ob_arm, se, child_objects);
    }
  }
}
Ejemplo n.º 20
0
/**
 * \warning be sure to account for a negative return value
 * This is an error, "Too many objects in select buffer"
 * and no action should be taken (can crash blender) if this happens
 *
 * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
 */
short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest)
{
	Scene *scene = vc->scene;
	View3D *v3d = vc->v3d;
	ARegion *ar = vc->ar;
	rctf rect;
	short hits;
	const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
	const bool do_passes = do_nearest && GPU_select_query_check_active();

	G.f |= G_PICKSEL;
	
	/* case not a border select */
	if (input->xmin == input->xmax) {
		rect.xmin = input->xmin - 12;  /* seems to be default value for bones only now */
		rect.xmax = input->xmin + 12;
		rect.ymin = input->ymin - 12;
		rect.ymax = input->ymin + 12;
	}
	else {
		BLI_rctf_rcti_copy(&rect, input);
	}
	
	view3d_winmatrix_set(ar, v3d, &rect);
	mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
	
	if (v3d->drawtype > OB_WIRE) {
		v3d->zbuf = true;
		glEnable(GL_DEPTH_TEST);
	}
	
	if (vc->rv3d->rflag & RV3D_CLIPPING)
		ED_view3d_clipping_set(vc->rv3d);
	
	if (do_passes)
		GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
	else
		GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0);

	view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);

	hits = GPU_select_end();
	
	/* second pass, to get the closest object to camera */
	if (do_passes) {
		GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);

		view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);

		GPU_select_end();
	}

	G.f &= ~G_PICKSEL;
	view3d_winmatrix_set(ar, v3d, NULL);
	mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
	
	if (v3d->drawtype > OB_WIRE) {
		v3d->zbuf = 0;
		glDisable(GL_DEPTH_TEST);
	}
// XXX	persp(PERSP_WIN);
	
	if (vc->rv3d->rflag & RV3D_CLIPPING)
		ED_view3d_clipping_disable();
	
	if (hits < 0) printf("Too many objects in select buffer\n");  /* XXX make error message */

	return hits;
}
Ejemplo n.º 21
0
/* join armature exec is exported for use in object->join objects operator... */
int join_armature_exec(bContext *C, wmOperator *op)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	Object  *ob = CTX_data_active_object(C);
	bArmature *arm = (ob) ? ob->data : NULL;
	bPose *pose, *opose;
	bPoseChannel *pchan, *pchann;
	EditBone *curbone;
	float mat[4][4], oimat[4][4];
	bool ok = false;
	
	/*	Ensure we're not in editmode and that the active object is an armature*/
	if (!ob || ob->type != OB_ARMATURE)
		return OPERATOR_CANCELLED;
	if (!arm || arm->edbo)
		return OPERATOR_CANCELLED;
	
	CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
	{
		if (base->object == ob) {
			ok = true;
			break;
		}
	}
	CTX_DATA_END;

	/* that way the active object is always selected */
	if (ok == false) {
		BKE_report(op->reports, RPT_WARNING, "Active object is not a selected armature");
		return OPERATOR_CANCELLED;
	}

	/* Get editbones of active armature to add editbones to */
	ED_armature_to_edit(arm);
	
	/* get pose of active object and move it out of posemode */
	pose = ob->pose;
	ob->mode &= ~OB_MODE_POSE;

	CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
	{
		if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
			bArmature *curarm = base->object->data;
			
			/* Make a list of editbones in current armature */
			ED_armature_to_edit(base->object->data);
			
			/* Get Pose of current armature */
			opose = base->object->pose;
			base->object->mode &= ~OB_MODE_POSE;
			//BASACT->flag &= ~OB_MODE_POSE;
			
			/* Find the difference matrix */
			invert_m4_m4(oimat, ob->obmat);
			mul_m4_m4m4(mat, oimat, base->object->obmat);
			
			/* Copy bones and posechannels from the object to the edit armature */
			for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
				pchann = pchan->next;
				curbone = ED_armature_bone_find_name(curarm->edbo, pchan->name);
				
				/* Get new name */
				unique_editbone_name(arm->edbo, curbone->name, NULL);
				
				/* Transform the bone */
				{
					float premat[4][4];
					float postmat[4][4];
					float difmat[4][4];
					float imat[4][4];
					float temp[3][3];
					
					/* Get the premat */
					ED_armature_ebone_to_mat3(curbone, temp);
					
					unit_m4(premat); /* mul_m4_m3m4 only sets 3x3 part */
					mul_m4_m3m4(premat, temp, mat);
					
					mul_m4_v3(mat, curbone->head);
					mul_m4_v3(mat, curbone->tail);
					
					/* Get the postmat */
					ED_armature_ebone_to_mat3(curbone, temp);
					copy_m4_m3(postmat, temp);
					
					/* Find the roll */
					invert_m4_m4(imat, premat);
					mul_m4_m4m4(difmat, imat, postmat);
					
					curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]);
				}
				
				/* Fix Constraints and Other Links to this Bone and Armature */
				joined_armature_fix_links(ob, base->object, pchan, curbone);
				
				/* Rename pchan */
				BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
				
				/* Jump Ship! */
				BLI_remlink(curarm->edbo, curbone);
				BLI_addtail(arm->edbo, curbone);
				
				BLI_remlink(&opose->chanbase, pchan);
				BLI_addtail(&pose->chanbase, pchan);
				BKE_pose_channels_hash_free(opose);
				BKE_pose_channels_hash_free(pose);
			}
			
			ED_base_object_free_and_unlink(bmain, scene, base);
		}
	}
	CTX_DATA_END;
	
	DAG_relations_tag_update(bmain);  /* because we removed object(s) */

	ED_armature_from_edit(arm);
	ED_armature_edit_free(arm);

	WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
	
	return OPERATOR_FINISHED;
}
Ejemplo n.º 22
0
/* don't set windows active in here, is used by renderwin too */
void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d)
{
	if (rv3d->persp == RV3D_CAMOB) {      /* obs/camera */
		if (v3d->camera) {
			BKE_object_where_is_calc(scene, v3d->camera);
			obmat_to_viewmat(rv3d, v3d->camera);
		}
		else {
			quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
			rv3d->viewmat[3][2] -= rv3d->dist;
		}
	}
	else {
		bool use_lock_ofs = false;


		/* should be moved to better initialize later on XXX */
		if (rv3d->viewlock & RV3D_LOCKED)
			ED_view3d_lock(rv3d);
		
		quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
		if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist;
		if (v3d->ob_centre) {
			Object *ob = v3d->ob_centre;
			float vec[3];
			
			copy_v3_v3(vec, ob->obmat[3]);
			if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
				bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone);
				if (pchan) {
					copy_v3_v3(vec, pchan->pose_mat[3]);
					mul_m4_v3(ob->obmat, vec);
				}
			}
			translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
			use_lock_ofs = true;
		}
		else if (v3d->ob_centre_cursor) {
			float vec[3];
			copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d));
			translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
			use_lock_ofs = true;
		}
		else {
			translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
		}

		/* lock offset */
		if (use_lock_ofs) {
			float persmat[4][4], persinv[4][4];
			float vec[3];

			/* we could calculate the real persmat/persinv here
			 * but it would be unreliable so better to later */
			mul_m4_m4m4(persmat, rv3d->winmat, rv3d->viewmat);
			invert_m4_m4(persinv, persmat);

			mul_v2_v2fl(vec, rv3d->ofs_lock, rv3d->is_persp ? rv3d->dist : 1.0f);
			vec[2] = 0.0f;
			mul_mat3_m4_v3(persinv, vec);
			translate_m4(rv3d->viewmat, vec[0], vec[1], vec[2]);
		}
		/* end lock offset */
	}
}
Ejemplo n.º 23
0
static void render_view3d_startjob(void *customdata, short *stop, short *do_update, float *UNUSED(progress))
{
	RenderPreview *rp = customdata;
	Render *re;
	RenderStats *rstats;
	rctf viewplane;
	rcti cliprct;
	float clipsta, clipend, pixsize;
	bool orth, restore = 0;
	char name[32];
	int update_flag;
	bool use_border;

	update_flag = rp->engine->job_update_flag;
	rp->engine->job_update_flag = 0;

	//printf("ma %d res %d view %d db %d\n", update_flag & PR_UPDATE_MATERIAL, update_flag & PR_UPDATE_RENDERSIZE, update_flag & PR_UPDATE_VIEW, update_flag & PR_UPDATE_DATABASE);

	G.is_break = false;
	
	if (false == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &pixsize, &orth))
		return;
	
	rp->stop = stop;
	rp->do_update = do_update;

	// printf("Enter previewrender\n");
	
	/* ok, are we rendering all over? */
	sprintf(name, "View3dPreview %p", (void *)rp->ar);
	re = rp->engine->re = RE_GetRender(name);
	
	/* set this always, rp is different for each job */
	RE_test_break_cb(re, rp, render_view3d_break);
	RE_display_update_cb(re, rp, render_view3d_display_update);
	RE_stats_draw_cb(re, rp, render_view3d_renderinfo_cb);
	
	rstats = RE_GetStats(re);

	if (update_flag & PR_UPDATE_VIEW) {
		Object *object;
		rp->resolution_divider = rp->start_resolution_divider;

		/* Same as database_init_objects(), loop over all objects.
		 * We might consider de-duplicating the code between this two cases.
		 */
		for (object = rp->bmain->object.first; object; object = object->id.next) {
			float mat[4][4];
			mul_m4_m4m4(mat, rp->viewmat, object->obmat);
			invert_m4_m4(object->imat_ren, mat);
		}
	}

	use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d,
	                                    rp->rv3d, &cliprct);

	if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) {
		RenderData rdata;

		/* no osa, blur, seq, layers, savebuffer etc for preview render */
		rdata = rp->scene->r;
		rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA);
		rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE | R_EXR_TILE_FILE | R_FULL_SAMPLE);
		rdata.scemode |= R_VIEWPORT_PREVIEW;

		/* we do use layers, but only active */
		rdata.scemode |= R_SINGLE_LAYER;

		/* initalize always */
		if (use_border) {
			rdata.mode |= R_BORDER;
			RE_InitState(re, NULL, &rdata, NULL, rp->ar->winx, rp->ar->winy, &cliprct);
		}
		else
			RE_InitState(re, NULL, &rdata, NULL, rp->ar->winx, rp->ar->winy, NULL);
	}

	if (orth)
		RE_SetOrtho(re, &viewplane, clipsta, clipend);
	else
		RE_SetWindow(re, &viewplane, clipsta, clipend);

	RE_SetPixelSize(re, pixsize);
	
	if ((update_flag & PR_UPDATE_DATABASE) || rstats->convertdone == 0) {
		unsigned int lay = rp->scene->lay;

		/* allow localview render for objects with lights in normal layers */
		if (rp->v3d->lay & 0xFF000000)
			lay |= rp->v3d->lay;
		else lay = rp->v3d->lay;
		
		RE_SetView(re, rp->viewmat);

		/* copying blender data while main thread is locked, to avoid crashes */
		WM_job_main_thread_lock_acquire(rp->job);
		RE_Database_Free(re);
		RE_Database_FromScene(re, rp->bmain, rp->scene, lay, 0);		// 0= dont use camera view
		WM_job_main_thread_lock_release(rp->job);

		/* do preprocessing like building raytree, shadows, volumes, SSS */
		RE_Database_Preprocess(re);

		/* conversion not completed, need to do it again */
		if (!rstats->convertdone) {
			if (render_view3d_is_valid(rp)) {
				rp->engine->job_update_flag |= PR_UPDATE_DATABASE;
			}
		}

		// printf("dbase update\n");
	}
	else {
		// printf("dbase rotate\n");
		RE_DataBase_IncrementalView(re, rp->viewmat, 0);
		restore = 1;
	}

	RE_DataBase_ApplyWindow(re);

	/* OK, can we enter render code? */
	if (rstats->convertdone) {
		bool first_time = true;
		for (;;) {
			if (first_time == false) {
				if (restore)
					RE_DataBase_IncrementalView(re, rp->viewmat, 1);

				rp->resolution_divider /= 2;
				*do_update = 1;

				render_update_resolution(re, rp, use_border, &cliprct);

				RE_DataBase_IncrementalView(re, rp->viewmat, 0);
				RE_DataBase_ApplyWindow(re);
				restore = 1;
			}
			else {
				render_update_resolution(re, rp, use_border, &cliprct);
			}

			RE_TileProcessor(re);

			first_time = false;

			if (*stop || rp->resolution_divider == 1) {
				break;
			}
		}

		/* always rotate back */
		if (restore)
			RE_DataBase_IncrementalView(re, rp->viewmat, 1);
	}
}
Ejemplo n.º 24
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag flag)
{
	DerivedMesh *dm = derivedData;
	DerivedMesh *result;
	ScrewModifierData *ltmd = (ScrewModifierData *) md;
	const bool use_render_params = (flag & MOD_APPLY_RENDER) != 0;
	
	int *origindex;
	int mpoly_index = 0;
	unsigned int step;
	unsigned int i, j;
	unsigned int i1, i2;
	unsigned int step_tot = use_render_params ? ltmd->render_steps : ltmd->steps;
	const bool do_flip = (ltmd->flag & MOD_SCREW_NORMAL_FLIP) != 0;

	const int quad_ord[4] = {
	    do_flip ? 3 : 0,
	    do_flip ? 2 : 1,
	    do_flip ? 1 : 2,
	    do_flip ? 0 : 3,
	};
	const int quad_ord_ofs[4] = {
	    do_flip ? 2 : 0,
	    1,
	    do_flip ? 0 : 2,
	    3,
	};

	unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0;
	const unsigned int totvert = (unsigned int)dm->getNumVerts(dm);
	const unsigned int totedge = (unsigned int)dm->getNumEdges(dm);
	const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm);

	unsigned int *edge_poly_map = NULL;  /* orig edge to orig poly */
	unsigned int *vert_loop_map = NULL;  /* orig vert to orig loop */

	/* UV Coords */
	const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
	MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot);
	float uv_u_scale;
	float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX};
	float uv_v_range_inv;
	float uv_axis_plane[4];

	char axis_char = 'X';
	bool close;
	float angle = ltmd->angle;
	float screw_ofs = ltmd->screw_ofs;
	float axis_vec[3] = {0.0f, 0.0f, 0.0f};
	float tmp_vec1[3], tmp_vec2[3]; 
	float mat3[3][3];
	float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */
	float mtx_tx_inv[4][4]; /* inverted */
	float mtx_tmp_a[4][4];
	
	unsigned int vc_tot_linked = 0;
	short other_axis_1, other_axis_2;
	const float *tmpf1, *tmpf2;

	unsigned int edge_offset;
	
	MPoly *mpoly_orig, *mpoly_new, *mp_new;
	MLoop *mloop_orig, *mloop_new, *ml_new;
	MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new;
	MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base;

	ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL;

	const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0;

	/* don't do anything? */
	if (!totvert)
		return CDDM_from_template(dm, 0, 0, 0, 0, 0);

	switch (ltmd->axis) {
		case 0:
			other_axis_1 = 1;
			other_axis_2 = 2;
			break;
		case 1:
			other_axis_1 = 0;
			other_axis_2 = 2;
			break;
		default: /* 2, use default to quiet warnings */
			other_axis_1 = 0;
			other_axis_2 = 1;
			break;
	}

	axis_vec[ltmd->axis] = 1.0f;

	if (ltmd->ob_axis) {
		/* calc the matrix relative to the axis object */
		invert_m4_m4(mtx_tmp_a, ob->obmat);
		copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat);
		mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv);

		/* calc the axis vec */
		mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */
		normalize_v3(axis_vec);

		/* screw */
		if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) {
			/* find the offset along this axis relative to this objects matrix */
			float totlen = len_v3(mtx_tx[3]);

			if (totlen != 0.0f) {
				float zero[3] = {0.0f, 0.0f, 0.0f};
				float cp[3];
				screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec);
			}
			else {
				screw_ofs = 0.0f;
			}
		}

		/* angle */

#if 0   /* cant incluide this, not predictable enough, though quite fun. */
		if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) {
			float mtx3_tx[3][3];
			copy_m3_m4(mtx3_tx, mtx_tx);

			float vec[3] = {0, 1, 0};
			float cross1[3];
			float cross2[3];
			cross_v3_v3v3(cross1, vec, axis_vec);

			mul_v3_m3v3(cross2, mtx3_tx, cross1);
			{
				float c1[3];
				float c2[3];
				float axis_tmp[3];

				cross_v3_v3v3(c1, cross2, axis_vec);
				cross_v3_v3v3(c2, axis_vec, c1);


				angle = angle_v3v3(cross1, c2);

				cross_v3_v3v3(axis_tmp, cross1, c2);
				normalize_v3(axis_tmp);

				if (len_v3v3(axis_tmp, axis_vec) > 1.0f)
					angle = -angle;

			}
		}
#endif
	}
	else {
		/* exis char is used by i_rotate*/
		axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */

		/* useful to be able to use the axis vec in some cases still */
		zero_v3(axis_vec);
		axis_vec[ltmd->axis] = 1.0f;
	}

	/* apply the multiplier */
	angle *= (float)ltmd->iter;
	screw_ofs *= (float)ltmd->iter;
	uv_u_scale = 1.0f / (float)(step_tot);

	/* multiplying the steps is a bit tricky, this works best */
	step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1);

	/* will the screw be closed?
	 * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */
	if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) &&
	    fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f))
	{
		close = 1;
		step_tot--;
		if (step_tot < 3) step_tot = 3;
	
		maxVerts = totvert  * step_tot;   /* -1 because we're joining back up */
		maxEdges = (totvert * step_tot) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys = totedge * step_tot;

		screw_ofs = 0.0f;
	}
	else {
		close = 0;
		if (step_tot < 3) step_tot = 3;

		maxVerts =  totvert  * step_tot; /* -1 because we're joining back up */
		maxEdges =  (totvert * (step_tot - 1)) + /* these are the edges between new verts */
		           (totedge * step_tot);  /* -1 because vert edges join */
		maxPolys =  totedge * (step_tot - 1);
	}

	if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) {
		uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f));
	}
	
	result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys);
	
	/* copy verts from mesh */
	mvert_orig =    dm->getVertArray(dm);
	medge_orig =    dm->getEdgeArray(dm);
	
	mvert_new =     result->getVertArray(result);
	mpoly_new =     result->getPolyArray(result);
	mloop_new =     result->getLoopArray(result);
	medge_new =     result->getEdgeArray(result);

	if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) {
		CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys);
	}

	origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);

	DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */

	if (mloopuv_layers_tot) {
		float zero_co[3] = {0};
		plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec);
	}

	if (mloopuv_layers_tot) {
		unsigned int uv_lay;
		for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) {
			mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay);
		}

		if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
			for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) {
				const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane);
				uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]);
				uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]);
			}
			uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]);
			uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]);
		}

		uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0];
		uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f;
	}

	/* Set the locations of the first set of verts */
	
	mv_new = mvert_new;
	mv_orig = mvert_orig;
	
	/* Copy the first set of edges */
	med_orig = medge_orig;
	med_new = medge_new;
	for (i = 0; i < totedge; i++, med_orig++, med_new++) {
		med_new->v1 = med_orig->v1;
		med_new->v2 = med_orig->v2;
		med_new->crease = med_orig->crease;
		med_new->flag = med_orig->flag &  ~ME_LOOSEEDGE;
	}
	
	/* build polygon -> edge map */
	if (totpoly) {
		MPoly *mp_orig;

		mpoly_orig = dm->getPolyArray(dm);
		mloop_orig = dm->getLoopArray(dm);
		edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__);
		memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge);

		vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__);
		memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert);

		for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) {
			unsigned int loopstart = (unsigned int)mp_orig->loopstart;
			unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop;

			MLoop *ml_orig = &mloop_orig[loopstart];
			unsigned int k;
			for (k = loopstart; k < loopend; k++, ml_orig++) {
				edge_poly_map[ml_orig->e] = i;
				vert_loop_map[ml_orig->v] = k;

				/* also order edges based on faces */
				if (medge_new[ml_orig->e].v1 != ml_orig->v) {
					SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2);
				}
			}
		}
	}
Ejemplo n.º 25
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;
	}
}
Ejemplo n.º 26
0
/* called from within the core where_is_pose loop, all animsystems and constraints
were executed & assigned. Now as last we do an IK pass */
static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
{
    float R_parmat[3][3], identity[3][3];
    float iR_parmat[3][3];
    float R_bonemat[3][3];
    float goalrot[3][3], goalpos[3];
    float rootmat[4][4], imat[4][4];
    float goal[4][4], goalinv[4][4];
    float irest_basis[3][3], full_basis[3][3];
    float end_pose[4][4], world_pose[4][4];
    float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL;
    float resultinf=0.0f;
    int a, flag, hasstretch=0, resultblend=0;
    bPoseChannel *pchan;
    IK_Segment *seg, *parent, **iktree, *iktarget;
    IK_Solver *solver;
    PoseTarget *target;
    bKinematicConstraint *data, *poleangledata=NULL;
    Bone *bone;

    if (tree->totchannel == 0)
        return;

    iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree");

    for(a=0; a<tree->totchannel; a++) {
        pchan= tree->pchan[a];
        bone= pchan->bone;

        /* set DoF flag */
        flag= 0;
        if(!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP))
            flag |= IK_XDOF;
        if(!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP))
            flag |= IK_YDOF;
        if(!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP))
            flag |= IK_ZDOF;

        if(tree->stretch && (pchan->ikstretch > 0.0)) {
            flag |= IK_TRANS_YDOF;
            hasstretch = 1;
        }

        seg= iktree[a]= IK_CreateSegment(flag);

        /* find parent */
        if(a == 0)
            parent= NULL;
        else
            parent= iktree[tree->parent[a]];

        IK_SetParent(seg, parent);

        /* get the matrix that transforms from prevbone into this bone */
        copy_m3_m4(R_bonemat, pchan->pose_mat);

        /* gather transformations for this IK segment */

        if (pchan->parent)
            copy_m3_m4(R_parmat, pchan->parent->pose_mat);
        else
            unit_m3(R_parmat);

        /* bone offset */
        if (pchan->parent && (a > 0))
            sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail);
        else
            /* only root bone (a = 0) has no parent */
            start[0]= start[1]= start[2]= 0.0f;

        /* change length based on bone size */
        length= bone->length*len_v3(R_bonemat[1]);

        /* compute rest basis and its inverse */
        copy_m3_m3(rest_basis, bone->bone_mat);
        copy_m3_m3(irest_basis, bone->bone_mat);
        transpose_m3(irest_basis);

        /* compute basis with rest_basis removed */
        invert_m3_m3(iR_parmat, R_parmat);
        mul_m3_m3m3(full_basis, iR_parmat, R_bonemat);
        mul_m3_m3m3(basis, irest_basis, full_basis);

        /* basis must be pure rotation */
        normalize_m3(basis);

        /* transform offset into local bone space */
        normalize_m3(iR_parmat);
        mul_m3_v3(iR_parmat, start);

        IK_SetTransform(seg, start, rest_basis, basis, length);

        if (pchan->ikflag & BONE_IK_XLIMIT)
            IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]);
        if (pchan->ikflag & BONE_IK_YLIMIT)
            IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]);
        if (pchan->ikflag & BONE_IK_ZLIMIT)
            IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]);

        IK_SetStiffness(seg, IK_X, pchan->stiffness[0]);
        IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]);
        IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);

        if(tree->stretch && (pchan->ikstretch > 0.0)) {
            float ikstretch = pchan->ikstretch*pchan->ikstretch;
            IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99));
            IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10);
        }
    }

    solver= IK_CreateSolver(iktree[0]);

    /* set solver goals */

    /* first set the goal inverse transform, assuming the root of tree was done ok! */
    pchan= tree->pchan[0];
    if (pchan->parent)
        /* transform goal by parent mat, so this rotation is not part of the
           segment's basis. otherwise rotation limits do not work on the
           local transform of the segment itself. */
        copy_m4_m4(rootmat, pchan->parent->pose_mat);
    else
        unit_m4(rootmat);
    VECCOPY(rootmat[3], pchan->pose_head);

    mul_m4_m4m4(imat, rootmat, ob->obmat);
    invert_m4_m4(goalinv, imat);

    for (target=tree->targets.first; target; target=target->next) {
        float polepos[3];
        int poleconstrain= 0;

        data= (bKinematicConstraint*)target->con->data;

        /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
         * strictly speaking, it is a posechannel)
         */
        get_constraint_target_matrix(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);

        /* and set and transform goal */
        mul_m4_m4m4(goal, rootmat, goalinv);

        VECCOPY(goalpos, goal[3]);
        copy_m3_m4(goalrot, goal);

        /* same for pole vector target */
        if(data->poletar) {
            get_constraint_target_matrix(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);

            if(data->flag & CONSTRAINT_IK_SETANGLE) {
                /* don't solve IK when we are setting the pole angle */
                break;
            }
            else {
                mul_m4_m4m4(goal, rootmat, goalinv);
                VECCOPY(polepos, goal[3]);
                poleconstrain= 1;

                /* for pole targets, we blend the result of the ik solver
                 * instead of the target position, otherwise we can't get
                 * a smooth transition */
                resultblend= 1;
                resultinf= target->con->enforce;

                if(data->flag & CONSTRAINT_IK_GETANGLE) {
                    poleangledata= data;
                    data->flag &= ~CONSTRAINT_IK_GETANGLE;
                }
            }
        }

        /* do we need blending? */
        if (!resultblend && target->con->enforce!=1.0) {
            float q1[4], q2[4], q[4];
            float fac= target->con->enforce;
            float mfac= 1.0-fac;

            pchan= tree->pchan[target->tip];

            /* end effector in world space */
            copy_m4_m4(end_pose, pchan->pose_mat);
            VECCOPY(end_pose[3], pchan->pose_tail);
            mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL);

            /* blend position */
            goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0];
            goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1];
            goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2];

            /* blend rotation */
            mat3_to_quat( q1,goalrot);
            mat4_to_quat( q2,world_pose);
            interp_qt_qtqt(q, q1, q2, mfac);
            quat_to_mat3( goalrot,q);
        }

        iktarget= iktree[target->tip];

        if(data->weight != 0.0) {
            if(poleconstrain)
                IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos,
                                                 polepos, data->poleangle, (poleangledata == data));
            IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
        }
        if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0))
            if((data->flag & CONSTRAINT_IK_AUTO)==0)
                IK_SolverAddGoalOrientation(solver, iktarget, goalrot,
                                            data->orientweight);
    }

    /* solve */
    IK_Solve(solver, 0.0f, tree->iterations);

    if(poleangledata)
        poleangledata->poleangle= IK_SolverGetPoleAngle(solver);

    IK_FreeSolver(solver);

    /* gather basis changes */
    tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change");
    if(hasstretch)
        ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch");

    for(a=0; a<tree->totchannel; a++) {
        IK_GetBasisChange(iktree[a], tree->basis_change[a]);

        if(hasstretch) {
            /* have to compensate for scaling received from parent */
            float parentstretch, stretch;

            pchan= tree->pchan[a];
            parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0;

            if(tree->stretch && (pchan->ikstretch > 0.0)) {
                float trans[3], length;

                IK_GetTranslationChange(iktree[a], trans);
                length= pchan->bone->length*len_v3(pchan->pose_mat[1]);

                ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length;
            }
            else
                ikstretch[a] = 1.0;

            stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch;

            mul_v3_fl(tree->basis_change[a][0], stretch);
            mul_v3_fl(tree->basis_change[a][1], stretch);
            mul_v3_fl(tree->basis_change[a][2], stretch);
        }

        if(resultblend && resultinf!=1.0f) {
            unit_m3(identity);
            blend_m3_m3m3(tree->basis_change[a], identity,
                          tree->basis_change[a], resultinf);
        }

        IK_FreeSegment(iktree[a]);
    }

    MEM_freeN(iktree);
    if(ikstretch) MEM_freeN(ikstretch);
}
Ejemplo n.º 27
0
static void warpModifier_do(WarpModifierData *wmd, Object *ob,
                            DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
	float obinv[4][4];
	float mat_from[4][4];
	float mat_from_inv[4][4];
	float mat_to[4][4];
	float mat_unit[4][4];
	float mat_final[4][4];

	float tmat[4][4];

	float strength = wmd->strength;
	float fac = 1.0f, weight;
	int i;
	int defgrp_index;
	MDeformVert *dvert, *dv = NULL;

	float (*tex_co)[3] = NULL;

	if (!(wmd->object_from && wmd->object_to))
		return;

	modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);

	if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */
		wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);

	if (wmd->curfalloff) {
		curvemapping_initialize(wmd->curfalloff);
	}

	invert_m4_m4(obinv, ob->obmat);

	mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat);
	mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat);

	invert_m4_m4(tmat, mat_from); // swap?
	mul_m4_m4m4(mat_final, tmat, mat_to);

	invert_m4_m4(mat_from_inv, mat_from);

	unit_m4(mat_unit);

	if (strength < 0.0f) {
		float loc[3];
		strength = -strength;

		/* inverted location is not useful, just use the negative */
		copy_v3_v3(loc, mat_final[3]);
		invert_m4(mat_final);
		negate_v3_v3(mat_final[3], loc);

	}
	weight = strength;

	if (wmd->texture) {
		tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, "warpModifier_do tex_co");
		get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);

		modifier_init_texture(wmd->modifier.scene, wmd->texture);
	}

	for (i = 0; i < numVerts; i++) {
		float *co = vertexCos[i];

		if (wmd->falloff_type == eWarp_Falloff_None ||
		    ((fac = len_v3v3(co, mat_from[3])) < wmd->falloff_radius &&
		     (fac = (wmd->falloff_radius - fac) / wmd->falloff_radius)))
		{
			/* skip if no vert group found */
			if (dvert && defgrp_index != -1) {
				dv = &dvert[i];

				if (dv) {
					weight = defvert_find_weight(dv, defgrp_index) * strength;
					if (weight <= 0.0f) /* Should never occure... */
						continue;
				}
			}


			/* closely match PROP_SMOOTH and similar */
			switch (wmd->falloff_type) {
				case eWarp_Falloff_None:
					fac = 1.0f;
					break;
				case eWarp_Falloff_Curve:
					fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
					break;
				case eWarp_Falloff_Sharp:
					fac = fac * fac;
					break;
				case eWarp_Falloff_Smooth:
					fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
					break;
				case eWarp_Falloff_Root:
					fac = (float)sqrt(fac);
					break;
				case eWarp_Falloff_Linear:
					/* pass */
					break;
				case eWarp_Falloff_Const:
					fac = 1.0f;
					break;
				case eWarp_Falloff_Sphere:
					fac = (float)sqrt(2 * fac - fac * fac);
					break;
			}

			fac *= weight;

			if (tex_co) {
				TexResult texres;
				texres.nor = NULL;
				BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false);
				fac *= texres.tin;
			}

			/* into the 'from' objects space */
			mul_m4_v3(mat_from_inv, co);

			if (fac >= 1.0f) {
				mul_m4_v3(mat_final, co);
			}
			else if (fac > 0.0f) {
				if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
					/* interpolate the matrix for nicer locations */
					blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
					mul_m4_v3(tmat, co);
				}
				else {
					float tvec[3];
					mul_v3_m4v3(tvec, mat_final, co);
					interp_v3_v3v3(co, co, tvec, fac);
				}
			}

			/* out of the 'from' objects space */
			mul_m4_v3(mat_from, co);
		}
	}

	if (tex_co)
		MEM_freeN(tex_co);

}
Ejemplo n.º 28
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *dm,
                                  ModifierApplyFlag UNUSED(flag))
{
	UVWarpModifierData *umd = (UVWarpModifierData *) md;
	int numPolys, numLoops;
	MPoly *mpoly;
	MLoop *mloop;
	MLoopUV *mloopuv;
	MDeformVert *dvert;
	int defgrp_index;
	char uvname[MAX_CUSTOMDATA_LAYER_NAME];
	float mat_src[4][4];
	float mat_dst[4][4];
	float imat_dst[4][4];
	float warp_mat[4][4];
	const int axis_u = umd->axis_u;
	const int axis_v = umd->axis_v;

	/* make sure there are UV Maps available */
	if (!CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
		return dm;
	}
	else if (ELEM(NULL, umd->object_src, umd->object_dst)) {
		modifier_setError(md, "From/To objects must be set");
		return dm;
	}

	/* make sure anything moving UVs is available */
	matrix_from_obj_pchan(mat_src, umd->object_src, umd->bone_src);
	matrix_from_obj_pchan(mat_dst, umd->object_dst, umd->bone_dst);

	invert_m4_m4(imat_dst, mat_dst);
	mul_m4_m4m4(warp_mat, imat_dst, mat_src);

	/* apply warp */
	if (!is_zero_v2(umd->center)) {
		float mat_cent[4][4];
		float imat_cent[4][4];

		unit_m4(mat_cent);
		mat_cent[3][axis_u] = umd->center[0];
		mat_cent[3][axis_v] = umd->center[1];

		invert_m4_m4(imat_cent, mat_cent);

		mul_m4_m4m4(warp_mat, warp_mat, imat_cent);
		mul_m4_m4m4(warp_mat, mat_cent, warp_mat);
	}

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

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

	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);
	/* make sure we are not modifying the original UV map */
	mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops);
	modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index);

	UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv,
	                   .dvert = dvert, .defgrp_index = defgrp_index,
	                   .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v};
	BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000);

	dm->dirty |= DM_DIRTY_TESS_CDLAYERS;

	return dm;
}
Ejemplo n.º 29
0
static void waveModifier_do(WaveModifierData *md, 
                            Scene *scene, Object *ob, DerivedMesh *dm,
                            float (*vertexCos)[3], int numVerts)
{
	WaveModifierData *wmd = (WaveModifierData *) md;
	MVert *mvert = NULL;
	MDeformVert *dvert;
	int defgrp_index;
	float ctime = BKE_scene_frame_get(scene);
	float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
	float lifefac = wmd->height;
	float (*tex_co)[3] = NULL;
	const int wmd_axis = wmd->flag & (MOD_WAVE_X | MOD_WAVE_Y);
	const float falloff = wmd->falloff;
	float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */

	if ((wmd->flag & MOD_WAVE_NORM) && (ob->type == OB_MESH))
		mvert = dm->getVertArray(dm);

	if (wmd->objectcenter) {
		float mat[4][4];
		/* get the control object's location in local coordinates */
		invert_m4_m4(ob->imat, ob->obmat);
		mul_m4_m4m4(mat, ob->imat, wmd->objectcenter->obmat);

		wmd->startx = mat[3][0];
		wmd->starty = mat[3][1];
	}

	/* get the index of the deform group */
	modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);

	if (wmd->damp == 0) wmd->damp = 10.0f;

	if (wmd->lifetime != 0.0f) {
		float x = ctime - wmd->timeoffs;

		if (x > wmd->lifetime) {
			lifefac = x - wmd->lifetime;

			if (lifefac > wmd->damp) lifefac = 0.0;
			else lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp)));
		}
	}

	if (wmd->texture) {
		tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts,
		                     "waveModifier_do tex_co");
		get_texture_coords((MappingInfoModifierData *)wmd, ob, dm, vertexCos, tex_co, numVerts);

		modifier_init_texture(wmd->modifier.scene, wmd->texture);
	}

	if (lifefac != 0.0f) {
		/* avoid divide by zero checks within the loop */
		float falloff_inv = falloff ? 1.0f / falloff : 1.0f;
		int i;

		for (i = 0; i < numVerts; i++) {
			float *co = vertexCos[i];
			float x = co[0] - wmd->startx;
			float y = co[1] - wmd->starty;
			float amplit = 0.0f;
			float def_weight = 1.0f;

			/* get weights */
			if (dvert) {
				def_weight = defvert_find_weight(&dvert[i], defgrp_index);

				/* if this vert isn't in the vgroup, don't deform it */
				if (def_weight == 0.0f) {
					continue;
				}
			}

			switch (wmd_axis) {
				case MOD_WAVE_X | MOD_WAVE_Y:
					amplit = sqrtf(x * x + y * y);
					break;
				case MOD_WAVE_X:
					amplit = x;
					break;
				case MOD_WAVE_Y:
					amplit = y;
					break;
			}

			/* this way it makes nice circles */
			amplit -= (ctime - wmd->timeoffs) * wmd->speed;

			if (wmd->flag & MOD_WAVE_CYCL) {
				amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) +
				         wmd->width;
			}

			if (falloff != 0.0f) {
				float dist = 0.0f;

				switch (wmd_axis) {
					case MOD_WAVE_X | MOD_WAVE_Y:
						dist = sqrtf(x * x + y * y);
						break;
					case MOD_WAVE_X:
						dist = fabsf(x);
						break;
					case MOD_WAVE_Y:
						dist = fabsf(y);
						break;
				}

				falloff_fac = (1.0f - (dist * falloff_inv));
				CLAMP(falloff_fac, 0.0f, 1.0f);
			}

			/* GAUSSIAN */
			if ((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) {
				amplit = amplit * wmd->narrow;
				amplit = (float)(1.0f / expf(amplit * amplit) - minfac);

				/*apply texture*/
				if (wmd->texture) {
					TexResult texres;
					texres.nor = NULL;
					BKE_texture_get_value(wmd->modifier.scene, wmd->texture, tex_co[i], &texres, false);
					amplit *= texres.tin;
				}

				/*apply weight & falloff */
				amplit *= def_weight * falloff_fac;

				if (mvert) {
					/* move along normals */
					if (wmd->flag & MOD_WAVE_NORM_X) {
						co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
					}
					if (wmd->flag & MOD_WAVE_NORM_Y) {
						co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
					}
					if (wmd->flag & MOD_WAVE_NORM_Z) {
						co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
					}
				}
				else {
					/* move along local z axis */
					co[2] += lifefac * amplit;
				}
			}
		}
	}

	if (wmd->texture) MEM_freeN(tex_co);
}
Ejemplo n.º 30
0
static DerivedMesh *arrayModifier_doArray(
        ArrayModifierData *amd,
        Scene *scene, Object *ob, DerivedMesh *dm,
        ModifierApplyFlag flag)
{
	const float eps = 1e-6f;
	const MVert *src_mvert;
	MVert *mv, *mv_prev, *result_dm_verts;

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

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

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

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

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

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

	count = amd->count;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	if (count < 1)
		count = 1;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	copy_m4_m4(final_offset, current_offset);

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

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

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

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

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

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

	return result;
}