Ejemplo n.º 1
0
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
{
	const MLoop *mloop = dm->getLoopArray(dm);
	const MLoopTri *looptri = dm->getLoopTriArray(dm);
	const unsigned int mvert_num = dm->getNumVerts(dm);
	const unsigned int looptri_num = dm->getNumLoopTri(dm);

	/* Allocate our vertices. */
	clmd->clothObject->mvert_num = mvert_num;
	clmd->clothObject->verts = MEM_callocN(sizeof(ClothVertex) * clmd->clothObject->mvert_num, "clothVertex");
	if (clmd->clothObject->verts == NULL) {
		cloth_free_modifier(clmd);
		modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts");
		printf("cloth_free_modifier clmd->clothObject->verts\n");
		return;
	}

	/* save face information */
	clmd->clothObject->tri_num = looptri_num;
	clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
	if (clmd->clothObject->tri == NULL) {
		cloth_free_modifier(clmd);
		modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri");
		printf("cloth_free_modifier clmd->clothObject->looptri\n");
		return;
	}
	DM_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);

	/* Free the springs since they can't be correct if the vertices
	 * changed.
	 */
	if ( clmd->clothObject->springs != NULL )
		MEM_freeN ( clmd->clothObject->springs );

}
Ejemplo n.º 2
0
static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
{
	PointCache *cache;

	cache= clmd->point_cache;

	/* initialize simulation data if it didn't exist already */
	if (clmd->clothObject == NULL) {
		if (!cloth_from_object(ob, clmd, result, framenr, 1)) {
			BKE_ptcache_invalidate(cache);
			modifier_setError(&(clmd->modifier), "Can't initialize cloth");
			return 0;
		}
	
		if (clmd->clothObject == NULL) {
			BKE_ptcache_invalidate(cache);
			modifier_setError(&(clmd->modifier), "Null cloth object");
			return 0;
		}
	
		implicit_set_positions(clmd);

		clmd->clothObject->last_frame= MINFRAME-1;
	}

	return 1;
}
Ejemplo n.º 3
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag flag)
{
	SubsurfModifierData *smd = (SubsurfModifierData *) md;
	SubsurfFlags subsurf_flags = 0;
	DerivedMesh *result;
	const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0;
	const bool isFinalCalc = (flag & MOD_APPLY_USECACHE) != 0;

#ifdef WITH_OPENSUBDIV
	const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
	const bool do_cddm_convert = useRenderParams || (!isFinalCalc && !smd->use_opensubdiv);
#else
	const bool do_cddm_convert = useRenderParams || !isFinalCalc;
#endif

	if (useRenderParams)
		subsurf_flags |= SUBSURF_USE_RENDER_PARAMS;
	if (isFinalCalc)
		subsurf_flags |= SUBSURF_IS_FINAL_CALC;
	if (ob->mode & OB_MODE_EDIT)
		subsurf_flags |= SUBSURF_IN_EDIT_MODE;

#ifdef WITH_OPENSUBDIV
	/* TODO(sergey): Not entirely correct, modifiers on top of subsurf
	 * could be disabled.
	 */
	if (md->next == NULL &&
	    allow_gpu &&
	    do_cddm_convert == false &&
	    smd->use_opensubdiv)
	{
		if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
			modifier_setError(md, "OpenSubdiv is disabled in User Preferences");
		}
		else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) {
			subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
		}
		else {
			modifier_setError(md, "OpenSubdiv is disabled due to dependencies");
		}
	}
#endif

	result = subsurf_make_derived_from_derived(derivedData, smd, NULL, subsurf_flags);
	result->cd_flag = derivedData->cd_flag;

	if (do_cddm_convert) {
		DerivedMesh *cddm = CDDM_copy(result);
		result->release(result);
		result = cddm;
	}

	return result;
}
Ejemplo n.º 4
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
	DerivedMesh *dm = derivedData;
	ReportList reports;

	/* Only used to check wehther we are operating on org data or not... */
	Mesh *me = ob->data;
	MVert *mvert;

	const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0;

	const float max_dist = (dtmd->flags & MOD_DATATRANSFER_MAP_MAXDIST) ? dtmd->map_max_distance : FLT_MAX;

	SpaceTransform space_transform_data;
	SpaceTransform *space_transform = (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) ? &space_transform_data : NULL;

	if (space_transform) {
		BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source);
	}

	mvert = dm->getVertArray(dm);
	if ((me->mvert == mvert) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
		/* We need to duplicate data here, otherwise setting custom normals, edges' shaprness, etc., could
		 * modify org mesh, see T43671. */
		dm = CDDM_copy(dm);
	}

	BKE_reports_init(&reports, RPT_STORE);

	/* Note: no islands precision for now here. */
	BKE_object_data_transfer_dm(md->scene, dtmd->ob_source, ob, dm, dtmd->data_types, false,
	                     dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode,
	                     space_transform, max_dist, dtmd->map_ray_radius, 0.0f,
	                     dtmd->layers_select_src, dtmd->layers_select_dst,
	                     dtmd->mix_mode, dtmd->mix_factor, dtmd->defgrp_name, invert_vgroup, &reports);

	if (BKE_reports_contain(&reports, RPT_ERROR)) {
		modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR));
	}
	else if (dm->getNumVerts(dm) > HIGH_POLY_WARNING || ((Mesh *)(dtmd->ob_source->data))->totvert > HIGH_POLY_WARNING) {
		modifier_setError(md, "You are using a rather high poly as source or destination, computation might be slow");
	}

	return dm;
}
Ejemplo n.º 5
0
static bool is_valid_target(NormalEditModifierData *enmd)
{
	if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
		return true;
	}
	else if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) {
		return true;
	}
	modifier_setError((ModifierData *)enmd, "Invalid target settings");
	return false;
}
Ejemplo n.º 6
0
static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
{
	unsigned int numverts = dm->getNumVerts ( dm );
	unsigned int numfaces = dm->getNumFaces ( dm );
	MFace *mface = dm->getFaceArray( dm );
	unsigned int i = 0;

	/* Allocate our vertices. */
	clmd->clothObject->numverts = numverts;
	clmd->clothObject->verts = MEM_callocN ( sizeof ( ClothVertex ) * clmd->clothObject->numverts, "clothVertex" );
	if ( clmd->clothObject->verts == NULL )
	{
		cloth_free_modifier ( clmd );
		modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->verts." );
		printf("cloth_free_modifier clmd->clothObject->verts\n");
		return;
	}

	// save face information
	clmd->clothObject->numfaces = numfaces;
	clmd->clothObject->mfaces = MEM_callocN ( sizeof ( MFace ) * clmd->clothObject->numfaces, "clothMFaces" );
	if ( clmd->clothObject->mfaces == NULL )
	{
		cloth_free_modifier ( clmd );
		modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject->mfaces." );
		printf("cloth_free_modifier clmd->clothObject->mfaces\n");
		return;
	}
	for ( i = 0; i < numfaces; i++ )
		memcpy ( &clmd->clothObject->mfaces[i], &mface[i], sizeof ( MFace ) );

	/* Free the springs since they can't be correct if the vertices
	* changed.
	*/
	if ( clmd->clothObject->springs != NULL )
		MEM_freeN ( clmd->clothObject->springs );

}
Ejemplo n.º 7
0
static DerivedMesh *applyModifierEM(ModifierData *md, Object *UNUSED(ob),
                                    struct BMEditMesh *UNUSED(editData),
                                    DerivedMesh *derivedData,
                                    ModifierApplyFlag flag)
{
	SubsurfModifierData *smd = (SubsurfModifierData *) md;
	DerivedMesh *result;
	/* 'orco' using editmode flags would cause cache to be used twice in editbmesh_calc_modifiers */
	SubsurfFlags ss_flags = (flag & MOD_APPLY_ORCO) ? 0 : (SUBSURF_FOR_EDIT_MODE | SUBSURF_IN_EDIT_MODE);
#ifdef WITH_OPENSUBDIV
	const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
	if (md->next == NULL && allow_gpu && smd->use_opensubdiv) {
		modifier_setError(md, "OpenSubdiv is not supported in edit mode");
	}
#endif

	result = subsurf_make_derived_from_derived(derivedData, smd, NULL, ss_flags);

	return result;
}
Ejemplo n.º 8
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag flag)
{
	BooleanModifierData *bmd = (BooleanModifierData *) md;
	DerivedMesh *dm;

	if (!bmd->object)
		return derivedData;

	dm = get_dm_for_modifier(bmd->object, flag);

	if (dm) {
		DerivedMesh *result;

		/* when one of objects is empty (has got no faces) we could speed up
		 * calculation a bit returning one of objects' derived meshes (or empty one)
		 * Returning mesh is depended on modifiers operation (sergey) */
		result = get_quick_derivedMesh(derivedData, dm, bmd->operation);

		if (result == NULL) {
			// TIMEIT_START(NewBooleanDerivedMesh)

			result = NewBooleanDerivedMesh(dm, bmd->object, derivedData, ob,
			                               1 + bmd->operation);

			// TIMEIT_END(NewBooleanDerivedMesh)
		}

		/* if new mesh returned, return it; otherwise there was
		 * an error, so delete the modifier object */
		if (result)
			return result;
		else
			modifier_setError(md, "Cannot execute boolean operation");
	}
	
	return derivedData;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *dm,
                                  ModifierApplyFlag flag)
{
#ifdef WITH_ALEMBIC
	MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *) md;

	Scene *scene = md->scene;
	const float frame = BKE_scene_frame_get(scene);
	const float time = BKE_cachefile_time_offset(mcmd->cache_file, frame, FPS);

	const char *err_str = NULL;

	CacheFile *cache_file = mcmd->cache_file;

	BKE_cachefile_ensure_handle(G.main, cache_file);

	DerivedMesh *result = ABC_read_mesh(cache_file->handle,
	                                    ob,
	                                    dm,
	                                    mcmd->object_path,
	                                    time,
	                                    &err_str,
	                                    mcmd->read_flag);

	if (err_str) {
		modifier_setError(md, "%s", err_str);
	}

	return result ? result : dm;
	UNUSED_VARS(flag);
#else
	return dm;
	UNUSED_VARS(md, ob, flag);
#endif
}
static void correctivesmooth_modifier_do(
        ModifierData *md, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], unsigned int numVerts,
        struct BMEditMesh *em)
{
	CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;

	const bool force_delta_cache_update =
	        /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
	        ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
	         (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC));

	bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
	MDeformVert *dvert = NULL;
	int defgrp_index;

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

	/* if rest bind_coords not are defined, set them (only run during bind) */
	if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) &&
	    /* signal to recalculate, whoever sets MUST also free bind coords */
	    (csmd->bind_coords_num == (unsigned int)-1))
	{
		BLI_assert(csmd->bind_coords == NULL);
		csmd->bind_coords = MEM_dupallocN(vertexCos);
		csmd->bind_coords_num = numVerts;
		BLI_assert(csmd->bind_coords != NULL);
	}

	if (UNLIKELY(use_only_smooth)) {
		smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);
		return;
	}

	if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
		modifier_setError(md, "Bind data required");
		goto error;
	}

	/* If the number of verts has changed, the bind is invalid, so we do nothing */
	if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
		if (csmd->bind_coords_num != numVerts) {
			modifier_setError(md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
			goto error;
		}
	}
	else {
		/* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
		if (ob->type != OB_MESH) {
			modifier_setError(md, "Object is not a mesh");
			goto error;
		}
		else {
			unsigned int me_numVerts = (unsigned int)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);

			if (me_numVerts != numVerts) {
				modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
				goto error;
			}
		}
	}

	/* check to see if our deltas are still valid */
	if (!csmd->delta_cache || (csmd->delta_cache_num != numVerts) || force_delta_cache_update) {
		const float (*rest_coords)[3];
		bool is_rest_coords_alloc = false;

		if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
			/* caller needs to do sanity check here */
			csmd->bind_coords_num = numVerts;
			rest_coords = (const float (*)[3])csmd->bind_coords;
		}
		else {
			int me_numVerts;
			rest_coords = (const float (*)[3]) ((em) ?
			        BKE_editmesh_vertexCos_get_orco(em, &me_numVerts) :
			        BKE_mesh_vertexCos_get(ob->data, &me_numVerts));

			BLI_assert((unsigned int)me_numVerts == numVerts);
			is_rest_coords_alloc = true;
		}

#ifdef DEBUG_TIME
	TIMEIT_START(corrective_smooth_deltas);
#endif

		calc_deltas(csmd, dm, dvert, defgrp_index, rest_coords, numVerts);

#ifdef DEBUG_TIME
	TIMEIT_END(corrective_smooth_deltas);
#endif
		if (is_rest_coords_alloc) {
			MEM_freeN((void *)rest_coords);
		}
	}

	if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
		/* this could be a check, but at this point it _must_ be valid */
		BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache);
	}


#ifdef DEBUG_TIME
	TIMEIT_START(corrective_smooth);
#endif

	/* do the actual delta mush */
	smooth_verts(csmd, dm, dvert, defgrp_index, vertexCos, numVerts);

	{
		unsigned int i;

		float (*tangent_spaces)[3][3];

		/* calloc, since values are accumulated */
		tangent_spaces = MEM_callocN((size_t)numVerts * sizeof(float[3][3]), __func__);

		calc_tangent_spaces(dm, vertexCos, tangent_spaces);

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

#ifdef USE_TANGENT_CALC_INLINE
			calc_tangent_ortho(tangent_spaces[i]);
#endif

			mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache[i]);
			add_v3_v3(vertexCos[i], delta);
		}

		MEM_freeN(tangent_spaces);
	}

#ifdef DEBUG_TIME
	TIMEIT_END(corrective_smooth);
#endif

	return;

	/* when the modifier fails to execute */
error:
	MEM_SAFE_FREE(csmd->delta_cache);
	csmd->delta_cache_num = 0;

}
Ejemplo n.º 11
0
static DerivedMesh *normalEditModifier_do(NormalEditModifierData *enmd, Object *ob, DerivedMesh *dm)
{
	Mesh *me = ob->data;

	const int num_verts = dm->getNumVerts(dm);
	const int num_edges = dm->getNumEdges(dm);
	const int num_loops = dm->getNumLoops(dm);
	const int num_polys = dm->getNumPolys(dm);
	MVert *mvert;
	MEdge *medge;
	MLoop *mloop;
	MPoly *mpoly;

	const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
	const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
	                                  (enmd->mix_factor == 1.0f) &&
	                                  (enmd->defgrp_name[0] == '\0') &&
	                                  (enmd->mix_limit == (float)M_PI));

	int defgrp_index;
	MDeformVert *dvert;

	float (*loopnors)[3] = NULL;
	short (*clnors)[2];

	float (*polynors)[3];
	bool free_polynors = false;

	/* Do not run that modifier at all if autosmooth is disabled! */
	if (!is_valid_target(enmd) || !num_loops) {
		return dm;
	}

	if (!(me->flag & ME_AUTOSMOOTH)) {
		modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings");
		return dm;
	}

	medge = dm->getEdgeArray(dm);
	if (me->medge == medge) {
		/* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could
		 * modify org mesh, see T43671. */
		dm = CDDM_copy(dm);
		medge = dm->getEdgeArray(dm);
	}
	mvert = dm->getVertArray(dm);
	mloop = dm->getLoopArray(dm);
	mpoly = dm->getPolyArray(dm);

	if (use_current_clnors) {
		dm->calcLoopNormals(dm, true, me->smoothresh);
		loopnors = dm->getLoopDataArray(dm, CD_NORMAL);
	}

	clnors = CustomData_duplicate_referenced_layer(&dm->loopData, CD_CUSTOMLOOPNORMAL, num_loops);
	if (!clnors) {
		DM_add_loop_layer(dm, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL);
		clnors = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL);
	}

	polynors = dm->getPolyDataArray(dm, CD_NORMAL);
	if (!polynors) {
		polynors = MEM_malloc_arrayN((size_t)num_polys, sizeof(*polynors), __func__);
		BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false);
		free_polynors = true;
	}

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

	if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
		normalEditModifier_do_radial(
		            enmd, ob, dm, clnors, loopnors, polynors,
		            enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
		            mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
	}
	else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
		normalEditModifier_do_directional(
		            enmd, ob, dm, clnors, loopnors, polynors,
		            enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, dvert, defgrp_index, use_invert_vgroup,
		            mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
	}

	if (free_polynors) {
		MEM_freeN(polynors);
	}

	return dm;
}
Ejemplo n.º 12
0
static void LaplacianDeformModifier_do(
        LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	float (*filevertexCos)[3];
	int sysdif;
	LaplacianSystem *sys = NULL;
	filevertexCos = NULL;
	if (!(lmd->flag & MOD_LAPLACIANDEFORM_BIND)) {
		if (lmd->cache_system) {
			sys = lmd->cache_system;
			deleteLaplacianSystem(sys);
			lmd->cache_system = NULL;
		}
		lmd->total_verts = 0;
		MEM_SAFE_FREE(lmd->vertexco);
		return;
	}
	if (lmd->cache_system) {
		sysdif = isSystemDifferent(lmd, ob, dm, numVerts);
		sys = lmd->cache_system;
		if (sysdif) {
			if (sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_ANCHORS || sysdif == LAPDEFORM_SYSTEM_ONLY_CHANGE_GROUP) {
				filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempModDeformCoordinates");
				memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
				MEM_SAFE_FREE(lmd->vertexco);
				lmd->total_verts = 0;
				deleteLaplacianSystem(sys);
				lmd->cache_system = NULL;
				initSystem(lmd, ob, dm, filevertexCos, numVerts);
				sys = lmd->cache_system; /* may have been reallocated */
				MEM_SAFE_FREE(filevertexCos);
				if (sys) {
					laplacianDeformPreview(sys, vertexCos);
				}
			}
			else {
				if (sysdif == LAPDEFORM_SYSTEM_CHANGE_VERTEXES) {
					modifier_setError(&lmd->modifier, "Vertices changed from %d to %d", lmd->total_verts, numVerts);
				}
				else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) {
					modifier_setError(&lmd->modifier, "Edges changed from %d to %d", sys->total_edges, dm->getNumEdges(dm));
				}
				else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) {
					modifier_setError(&lmd->modifier, "Vertex group '%s' is not valid", sys->anchor_grp_name);
				}
			}
		}
		else {
			sys->repeat = lmd->repeat;
			laplacianDeformPreview(sys, vertexCos);
		}
	}
	else {
		if (lmd->total_verts > 0 && lmd->total_verts == numVerts) {
			if (isValidVertexGroup(lmd, ob, dm)) {
				filevertexCos = MEM_mallocN(sizeof(float[3]) * numVerts, "TempDeformCoordinates");
				memcpy(filevertexCos, lmd->vertexco, sizeof(float[3]) * numVerts);
				MEM_SAFE_FREE(lmd->vertexco);
				lmd->total_verts = 0;
				initSystem(lmd, ob, dm, filevertexCos, numVerts);
				sys = lmd->cache_system;
				MEM_SAFE_FREE(filevertexCos);
				laplacianDeformPreview(sys, vertexCos);
			}
		}
		else {
			if (isValidVertexGroup(lmd, ob, dm)) {
				initSystem(lmd, ob, dm, vertexCos, numVerts);
				sys = lmd->cache_system;
				laplacianDeformPreview(sys, vertexCos);
			}
		}
	}
	if (sys->is_matrix_computed && !sys->has_solution) {
		modifier_setError(&lmd->modifier, "The system did not find a solution");
	}
}
Ejemplo n.º 13
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, 0);
		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);
	mult_m4_m4m4(cagemat, imat, ob->obmat);
	mult_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.º 14
0
static DerivedMesh *applyModifier(
        ModifierData *md, Object *ob,
        DerivedMesh *dm,
        ModifierApplyFlag UNUSED(flag))
{
	DerivedMesh *result;
	const SolidifyModifierData *smd = (SolidifyModifierData *) md;

	MVert *mv, *mvert, *orig_mvert;
	MEdge *ed, *medge, *orig_medge;
	MLoop *ml, *mloop, *orig_mloop;
	MPoly *mp, *mpoly, *orig_mpoly;
	const unsigned int numVerts = (unsigned int)dm->getNumVerts(dm);
	const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
	const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm);
	const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm);
	unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0, rimVerts = 0;

	/* only use material offsets if we have 2 or more materials  */
	const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0;
	const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
	const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;

	/* use for edges */
	/* over-alloc new_vert_arr, old_vert_arr */
	unsigned int *new_vert_arr = NULL;
	STACK_DECLARE(new_vert_arr);

	unsigned int *new_edge_arr = NULL;
	STACK_DECLARE(new_edge_arr);

	unsigned int *old_vert_arr = MEM_callocN(sizeof(*old_vert_arr) * (size_t)numVerts, "old_vert_arr in solidify");

	unsigned int *edge_users = NULL;
	char *edge_order = NULL;

	float (*vert_nors)[3] = NULL;
	float (*face_nors)[3] = NULL;

	const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN);

	const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
	const float ofs_new  = smd->offset + ofs_orig;
	const float offset_fac_vg = smd->offset_fac_vg;
	const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
	const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
	const bool do_clamp = (smd->offset_clamp != 0.0f);
	const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0;

	/* weights */
	MDeformVert *dvert;
	const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
	int defgrp_index;

	/* array size is doubled in case of using a shell */
	const unsigned int stride = do_shell ? 2 : 1;

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

	orig_mvert = dm->getVertArray(dm);
	orig_medge = dm->getEdgeArray(dm);
	orig_mloop = dm->getLoopArray(dm);
	orig_mpoly = dm->getPolyArray(dm);

	if (need_face_normals) {
		/* calculate only face normals */
		face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__);
		BKE_mesh_calc_normals_poly(
		            orig_mvert, NULL, (int)numVerts,
		            orig_mloop, orig_mpoly,
		            (int)numLoops, (int)numFaces,
		            face_nors, true);
	}

	STACK_INIT(new_vert_arr, numVerts * 2);
	STACK_INIT(new_edge_arr, numEdges * 2);

	if (smd->flag & MOD_SOLIDIFY_RIM) {
		BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
		unsigned int eidx;
		unsigned int i;

#define INVALID_UNUSED ((unsigned int)-1)
#define INVALID_PAIR ((unsigned int)-2)

		new_vert_arr = MEM_mallocN(sizeof(*new_vert_arr) * (size_t)(numVerts * 2), __func__);
		new_edge_arr = MEM_mallocN(sizeof(*new_edge_arr) * (size_t)((numEdges * 2) + numVerts), __func__);

		edge_users = MEM_mallocN(sizeof(*edge_users) * (size_t)numEdges, "solid_mod edges");
		edge_order = MEM_mallocN(sizeof(*edge_order) * (size_t)numEdges, "solid_mod eorder");


		/* save doing 2 loops here... */
#if 0
		copy_vn_i(edge_users, numEdges, INVALID_UNUSED);
#endif

		for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
			edge_users[eidx] = INVALID_UNUSED;
		}

		for (i = 0, mp = orig_mpoly; i < numFaces; i++, mp++) {
			MLoop *ml_prev;
			int j;

			ml = orig_mloop + mp->loopstart;
			ml_prev = ml + (mp->totloop - 1);

			for (j = 0; j < mp->totloop; j++, ml++) {
				/* add edge user */
				eidx = ml_prev->e;
				if (edge_users[eidx] == INVALID_UNUSED) {
					ed = orig_medge + eidx;
					BLI_assert(ELEM(ml_prev->v,    ed->v1, ed->v2) &&
					           ELEM(ml->v, ed->v1, ed->v2));
					edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numFaces);
					edge_order[eidx] = j;
				}
				else {
					edge_users[eidx] = INVALID_PAIR;
				}
				ml_prev = ml;
			}
		}

		for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
			if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
				BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1);
				BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2);
				STACK_PUSH(new_edge_arr, eidx);
				newFaces++;
				newLoops += 4;
			}
		}

		for (i = 0; i < numVerts; i++) {
			if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
				old_vert_arr[i] = STACK_SIZE(new_vert_arr);
				STACK_PUSH(new_vert_arr, i);
				rimVerts++;
			}
			else {
				old_vert_arr[i] = INVALID_UNUSED;
			}
		}

		MEM_freeN(orig_mvert_tag);
	}

	if (do_shell == false) {
		/* only add rim vertices */
		newVerts = rimVerts;
		/* each extruded face needs an opposite edge */
		newEdges = newFaces;
	}
	else {
		/* (stride == 2) in this case, so no need to add newVerts/newEdges */
		BLI_assert(newVerts == 0);
		BLI_assert(newEdges == 0);
	}

	if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
		vert_nors = MEM_callocN(sizeof(float) * (size_t)numVerts * 3, "mod_solid_vno_hq");
		dm_calc_normal(dm, face_nors, vert_nors);
	}

	result = CDDM_from_template(dm,
	                            (int)((numVerts * stride) + newVerts),
	                            (int)((numEdges * stride) + newEdges + rimVerts), 0,
	                            (int)((numLoops * stride) + newLoops),
	                            (int)((numFaces * stride) + newFaces));

	mpoly = CDDM_get_polys(result);
	mloop = CDDM_get_loops(result);
	medge = CDDM_get_edges(result);
	mvert = CDDM_get_verts(result);

	if (do_shell) {
		DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
		DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts);

		DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
		DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges);

		DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
		DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops);

		DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
		DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces);
	}
	else {
		int i, j;
		DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
		for (i = 0, j = (int)numVerts; i < numVerts; i++) {
			if (old_vert_arr[i] != INVALID_UNUSED) {
				DM_copy_vert_data(dm, result, i, j, 1);
				j++;
			}
		}

		DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);

		for (i = 0, j = (int)numEdges; i < numEdges; i++) {
			if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
				MEdge *ed_src, *ed_dst;
				DM_copy_edge_data(dm, result, i, j, 1);

				ed_src = &medge[i];
				ed_dst = &medge[j];
				ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts;
				ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts;
				j++;
			}
		}

		/* will be created later */
		DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
		DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
	}

#undef INVALID_UNUSED
#undef INVALID_PAIR


	/* initializes: (i_end, do_shell_align, mv)  */
#define INIT_VERT_ARRAY_OFFSETS(test) \
	if (((ofs_new >= ofs_orig) == do_flip) == test) { \
		i_end = numVerts; \
		do_shell_align = true; \
		mv = mvert; \
	} \
	else { \
		if (do_shell) { \
			i_end = numVerts; \
			do_shell_align = true; \
		} \
		else { \
			i_end = newVerts ; \
			do_shell_align = false; \
		} \
		mv = &mvert[numVerts]; \
	} (void)0


	/* flip normals */

	if (do_shell) {
		unsigned int i;

		mp = mpoly + numFaces;
		for (i = 0; i < dm->numPolyData; i++, mp++) {
			MLoop *ml2;
			unsigned int e;
			int j;

			/* reverses the loop direction (MLoop.v as well as custom-data)
			 * MLoop.e also needs to be corrected too, done in a separate loop below. */
			ml2 = mloop + mp->loopstart + dm->numLoopData;
			for (j = 0; j < mp->totloop; j++) {
				CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
				                     mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1);
			}

			if (mat_ofs) {
				mp->mat_nr += mat_ofs;
				CLAMP(mp->mat_nr, 0, mat_nr_max);
			}

			e = ml2[0].e;
			for (j = 0; j < mp->totloop - 1; j++) {
				ml2[j].e = ml2[j + 1].e;
			}
			ml2[mp->totloop - 1].e = e;

			mp->loopstart += dm->numLoopData;

			for (j = 0; j < mp->totloop; j++) {
				ml2[j].e += numEdges;
				ml2[j].v += numVerts;
			}
		}

		for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
			ed->v1 += numVerts;
			ed->v2 += numVerts;
		}
	}

	/* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
	if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
		/* no even thickness, very simple */
		float scalar_short;
		float scalar_short_vgroup;

		/* for clamping */
		float *vert_lens = NULL;
		const float offset    = fabsf(smd->offset) * smd->offset_clamp;
		const float offset_sq = offset * offset;

		if (do_clamp) {
			unsigned int i;

			vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
			copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
			for (i = 0; i < numEdges; i++) {
				const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
				vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
				vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq);
			}
		}

		if (ofs_new != 0.0f) {
			unsigned int i_orig, i_end;
			bool do_shell_align;

			scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;

			INIT_VERT_ARRAY_OFFSETS(false);

			for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
				const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
				if (dvert) {
					MDeformVert *dv = &dvert[i];
					if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
					else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
					scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
				}
				if (do_clamp) {
					/* always reset becaise we may have set before */
					if (dvert == NULL) {
						scalar_short_vgroup = scalar_short;
					}
					if (vert_lens[i] < offset_sq) {
						float scalar = sqrtf(vert_lens[i]) / offset;
						scalar_short_vgroup *= scalar;
					}
				}
				madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
			}
		}

		if (ofs_orig != 0.0f) {
			unsigned int i_orig, i_end;
			bool do_shell_align;

			scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;

			/* as above but swapped */
			INIT_VERT_ARRAY_OFFSETS(true);

			for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
				const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
				if (dvert) {
					MDeformVert *dv = &dvert[i];
					if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
					else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
					scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
				}
				if (do_clamp) {
					/* always reset becaise we may have set before */
					if (dvert == NULL) {
						scalar_short_vgroup = scalar_short;
					}
					if (vert_lens[i] < offset_sq) {
						float scalar = sqrtf(vert_lens[i]) / offset;
						scalar_short_vgroup *= scalar;
					}
				}
				madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
			}
		}

		if (do_clamp) {
			MEM_freeN(vert_lens);
		}
	}
	else {
#ifdef USE_NONMANIFOLD_WORKAROUND
		const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
#endif
		/* same as EM_solidify() in editmesh_lib.c */
		float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
		float *vert_accum = vert_angles + numVerts;
		unsigned int vidx;
		unsigned int i;

		if (vert_nors == NULL) {
			vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
			for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
				normal_short_to_float_v3(vert_nors[i], mv->no);
			}
		}

		for (i = 0, mp = mpoly; i < numFaces; i++, mp++) {
			/* #BKE_mesh_calc_poly_angles logic is inlined here */
			float nor_prev[3];
			float nor_next[3];

			int i_curr = mp->totloop - 1;
			int i_next = 0;

			ml = &mloop[mp->loopstart];

			sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co);
			normalize_v3(nor_prev);

			while (i_next < mp->totloop) {
				float angle;
				sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co);
				normalize_v3(nor_next);
				angle = angle_normalized_v3v3(nor_prev, nor_next);


				/* --- not related to angle calc --- */
				if (angle < FLT_EPSILON) {
					angle = FLT_EPSILON;
				}

				vidx = ml[i_curr].v;
				vert_accum[vidx] += angle;

#ifdef USE_NONMANIFOLD_WORKAROUND
				/* skip 3+ face user edges */
				if ((check_non_manifold == false) ||
				    LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) &&
				           ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0)))
				{
					vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle;
				}
				else {
					vert_angles[vidx] += angle;
				}
#else
				vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_nors[i]) * angle;
#endif
				/* --- end non-angle-calc section --- */


				/* step */
				copy_v3_v3(nor_prev, nor_next);
				i_curr = i_next;
				i_next++;
			}
		}

		/* vertex group support */
		if (dvert) {
			MDeformVert *dv = dvert;
			float scalar;

			if (defgrp_invert) {
				for (i = 0; i < numVerts; i++, dv++) {
					scalar = 1.0f - defvert_find_weight(dv, defgrp_index);
					scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
					vert_angles[i] *= scalar;
				}
			}
			else {
				for (i = 0; i < numVerts; i++, dv++) {
					scalar = defvert_find_weight(dv, defgrp_index);
					scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
					vert_angles[i] *= scalar;
				}
			}
		}

		if (do_clamp) {
			float *vert_lens_sq = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
			const float offset    = fabsf(smd->offset) * smd->offset_clamp;
			const float offset_sq = offset * offset;
			copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
			for (i = 0; i < numEdges; i++) {
				const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
				vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
				vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len);
			}
			for (i = 0; i < numVerts; i++) {
				if (vert_lens_sq[i] < offset_sq) {
					float scalar = sqrtf(vert_lens_sq[i]) / offset;
					vert_angles[i] *= scalar;
				}
			}
			MEM_freeN(vert_lens_sq);
		}

		if (ofs_new != 0.0f) {
			unsigned int i_orig, i_end;
			bool do_shell_align;

			INIT_VERT_ARRAY_OFFSETS(false);

			for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
				const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
				if (vert_accum[i_other]) { /* zero if unselected */
					madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
				}
			}
		}

		if (ofs_orig != 0.0f) {
			unsigned int i_orig, i_end;
			bool do_shell_align;

			/* same as above but swapped, intentional use of 'ofs_new' */
			INIT_VERT_ARRAY_OFFSETS(true);

			for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
				const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
				if (vert_accum[i_other]) { /* zero if unselected */
					madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
				}
			}
		}

		MEM_freeN(vert_angles);
	}

	if (vert_nors)
		MEM_freeN(vert_nors);

	/* must recalculate normals with vgroups since they can displace unevenly [#26888] */
	if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
		result->dirty |= DM_DIRTY_NORMALS;
	}
	else if (do_shell) {
		unsigned int i;
		/* flip vertex normals for copied verts */
		mv = mvert + numVerts;
		for (i = 0; i < numVerts; i++, mv++) {
			negate_v3_short(mv->no);
		}
	}

	if (smd->flag & MOD_SOLIDIFY_RIM) {
		unsigned int i;

		/* bugger, need to re-calculate the normals for the new edge faces.
		 * This could be done in many ways, but probably the quickest way
		 * is to calculate the average normals for side faces only.
		 * Then blend them with the normals of the edge verts.
		 *
		 * at the moment its easiest to allocate an entire array for every vertex,
		 * even though we only need edge verts - campbell
		 */

#define SOLIDIFY_SIDE_NORMALS

#ifdef SOLIDIFY_SIDE_NORMALS
		const bool do_side_normals = !(result->dirty & DM_DIRTY_NORMALS);
		/* annoying to allocate these since we only need the edge verts, */
		float (*edge_vert_nos)[3] = do_side_normals ? MEM_callocN(sizeof(float) * numVerts * 3, __func__) : NULL;
		float nor[3];
#endif
		const unsigned char crease_rim = smd->crease_rim * 255.0f;
		const unsigned char crease_outer = smd->crease_outer * 255.0f;
		const unsigned char crease_inner = smd->crease_inner * 255.0f;

		int *origindex_edge;
		int *orig_ed;
		unsigned int j;

		if (crease_rim || crease_outer || crease_inner) {
			result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
		}

		/* add faces & edges */
		origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
		ed = &medge[(numEdges * stride) + newEdges];  /* start after copied edges */
		orig_ed = &origindex_edge[(numEdges * stride) + newEdges];
		for (i = 0; i < rimVerts; i++, ed++, orig_ed++) {
			ed->v1 = new_vert_arr[i];
			ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts;
			ed->flag |= ME_EDGEDRAW;

			*orig_ed = ORIGINDEX_NONE;

			if (crease_rim) {
				ed->crease = crease_rim;
			}
		}

		/* faces */
		mp = mpoly + (numFaces * stride);
		ml = mloop + (numLoops * stride);
		j = 0;
		for (i = 0; i < newFaces; i++, mp++) {
			unsigned int eidx = new_edge_arr[i];
			unsigned int fidx = edge_users[eidx];
			int k1, k2;
			bool flip;

			if (fidx >= numFaces) {
				fidx -= numFaces;
				flip = true;
			}
			else {
				flip = false;
			}

			ed = medge + eidx;

			/* copy most of the face settings */
			DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1);
			mp->loopstart = (int)(j + (numLoops * stride));
			mp->flag = mpoly[fidx].flag;

			/* notice we use 'mp->totloop' which is later overwritten,
			 * we could lookup the original face but theres no point since this is a copy
			 * and will have the same value, just take care when changing order of assignment */
			k1 = mpoly[fidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop);  /* prev loop */
			k2 = mpoly[fidx].loopstart +   (edge_order[eidx]);

			mp->totloop = 4;

			CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1);
			CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1);
			CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1);
			CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1);

			if (flip == false) {
				ml[j].v = ed->v1;
				ml[j++].e = eidx;

				ml[j].v = ed->v2;
				ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;

				ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
				ml[j++].e = (do_shell ? eidx : i) + numEdges;

				ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
				ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
			}
			else {
				ml[j].v = ed->v2;
				ml[j++].e = eidx;

				ml[j].v = ed->v1;
				ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;

				ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
				ml[j++].e = (do_shell ? eidx : i) + numEdges;

				ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
				ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
			}

			origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
			origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;

			/* use the next material index if option enabled */
			if (mat_ofs_rim) {
				mp->mat_nr += mat_ofs_rim;
				CLAMP(mp->mat_nr, 0, mat_nr_max);
			}
			if (crease_outer) {
				/* crease += crease_outer; without wrapping */
				char *cr = &(ed->crease);
				int tcr = *cr + crease_outer;
				*cr = tcr > 255 ? 255 : tcr;
			}

			if (crease_inner) {
				/* crease += crease_inner; without wrapping */
				char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease);
				int tcr = *cr + crease_inner;
				*cr = tcr > 255 ? 255 : tcr;
			}

#ifdef SOLIDIFY_SIDE_NORMALS
			if (do_side_normals) {
				normal_quad_v3(nor,
				               mvert[ml[j - 4].v].co,
				               mvert[ml[j - 3].v].co,
				               mvert[ml[j - 2].v].co,
				               mvert[ml[j - 1].v].co);

				add_v3_v3(edge_vert_nos[ed->v1], nor);
				add_v3_v3(edge_vert_nos[ed->v2], nor);
			}
#endif
		}

#ifdef SOLIDIFY_SIDE_NORMALS
		if (do_side_normals) {
			ed = medge + (numEdges * stride);
			for (i = 0; i < rimVerts; i++, ed++) {
				float nor_cpy[3];
				short *nor_short;
				int k;

				/* note, only the first vertex (lower half of the index) is calculated */
				normalize_v3_v3(nor_cpy, edge_vert_nos[ed->v1]);

				for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
					nor_short = mvert[*(&ed->v1 + k)].no;
					normal_short_to_float_v3(nor, nor_short);
					add_v3_v3(nor, nor_cpy);
					normalize_v3(nor);
					normal_float_to_short_v3(nor_short, nor);
				}
			}

			MEM_freeN(edge_vert_nos);
		}
#endif

		MEM_freeN(new_vert_arr);
		MEM_freeN(new_edge_arr);

		MEM_freeN(edge_users);
		MEM_freeN(edge_order);
	}

	if (old_vert_arr)
		MEM_freeN(old_vert_arr);

	if (face_nors)
		MEM_freeN(face_nors);

	if (numFaces == 0 && numEdges != 0) {
		modifier_setError(md, "Faces needed for useful output");
	}

	return result;
}
Ejemplo n.º 15
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.º 16
0
static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
{
	LinearSolver *context;
	float vec[3], gridvec[3];
	int a, b, x, y, z, totvar;
	char message[256];

	/* setup variable indices */
	mdb->varidx = MEM_callocN(sizeof(int) * mdb->size3, "MeshDeformDSvaridx");
	for (a = 0, totvar = 0; a < mdb->size3; a++)
		mdb->varidx[a] = (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR) ? -1 : totvar++;

	if (totvar == 0) {
		MEM_freeN(mdb->varidx);
		return;
	}

	progress_bar(0, "Starting mesh deform solve");

	/* setup linear solver */
	context = EIG_linear_solver_new(totvar, totvar, 1);

	/* build matrix */
	for (z = 0; z < mdb->size; z++)
		for (y = 0; y < mdb->size; y++)
			for (x = 0; x < mdb->size; x++)
				meshdeform_matrix_add_cell(mdb, context, x, y, z);

	/* solve for each cage vert */
	for (a = 0; a < mdb->totcagevert; a++) {
		/* fill in right hand side and solve */
		for (z = 0; z < mdb->size; z++)
			for (y = 0; y < mdb->size; y++)
				for (x = 0; x < mdb->size; x++)
					meshdeform_matrix_add_rhs(mdb, context, x, y, z, a);

		if (EIG_linear_solver_solve(context)) {
			for (z = 0; z < mdb->size; z++)
				for (y = 0; y < mdb->size; y++)
					for (x = 0; x < mdb->size; x++)
						meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a);

			for (z = 0; z < mdb->size; z++)
				for (y = 0; y < mdb->size; y++)
					for (x = 0; x < mdb->size; x++)
						meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a);

			for (b = 0; b < mdb->size3; b++) {
				if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
					mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]);
				mdb->totalphi[b] += mdb->phi[b];
			}

			if (mdb->weights) {
				/* static bind : compute weights for each vertex */
				for (b = 0; b < mdb->totvert; b++) {
					if (mdb->inside[b]) {
						copy_v3_v3(vec, mdb->vertexcos[b]);
						gridvec[0] = (vec[0] - mdb->min[0] - mdb->halfwidth[0]) / mdb->width[0];
						gridvec[1] = (vec[1] - mdb->min[1] - mdb->halfwidth[1]) / mdb->width[1];
						gridvec[2] = (vec[2] - mdb->min[2] - mdb->halfwidth[2]) / mdb->width[2];

						mdb->weights[b * mdb->totcagevert + a] = meshdeform_interp_w(mdb, gridvec, vec, a);
					}
				}
			}
			else {
				MDefBindInfluence *inf;

				/* dynamic bind */
				for (b = 0; b < mdb->size3; b++) {
					if (mdb->phi[b] >= MESHDEFORM_MIN_INFLUENCE) {
						inf = BLI_memarena_alloc(mdb->memarena, sizeof(*inf));
						inf->vertex = a;
						inf->weight = mdb->phi[b];
						inf->next = mdb->dyngrid[b];
						mdb->dyngrid[b] = inf;
					}
				}
			}
		}
		else {
			modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)");
			error("Mesh Deform: failed to find bind solution.");
			break;
		}

		BLI_snprintf(message, sizeof(message), "Mesh deform solve %d / %d       |||", a + 1, mdb->totcagevert);
		progress_bar((float)(a + 1) / (float)(mdb->totcagevert), message);
	}

#if 0
	/* sanity check */
	for (b = 0; b < mdb->size3; b++)
		if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
			if (fabsf(mdb->totalphi[b] - 1.0f) > 1e-4f)
				printf("totalphi deficiency [%s|%d] %d: %.10f\n",
				       (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR) ? "interior" : "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
#endif
	
	/* free */
	MEM_freeN(mdb->varidx);

	EIG_linear_solver_delete(context);
}
Ejemplo n.º 17
0
static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first)
{
	int i = 0;
	MVert *mvert = NULL;
	ClothVertex *verts = NULL;
	float (*shapekey_rest)[3]= NULL;
	float tnull[3] = {0,0,0};
	Cloth *cloth = NULL;
	float maxdist = 0;

	// If we have a clothObject, free it. 
	if ( clmd->clothObject != NULL )
	{
		cloth_free_modifier ( clmd );
		if(G.rt > 0)
			printf("cloth_free_modifier cloth_from_object\n");
	}

	// Allocate a new cloth object.
	clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" );
	if ( clmd->clothObject )
	{
		clmd->clothObject->old_solver_type = 255;
		// clmd->clothObject->old_collision_type = 255;
		cloth = clmd->clothObject;
		clmd->clothObject->edgehash = NULL;
	}
	else if ( !clmd->clothObject )
	{
		modifier_setError ( & ( clmd->modifier ), "Out of memory on allocating clmd->clothObject." );
		return 0;
	}

	// mesh input objects need DerivedMesh
	if ( !dm )
		return 0;

	cloth_from_mesh ( clmd, dm );

	// create springs 
	clmd->clothObject->springs = NULL;
	clmd->clothObject->numsprings = -1;
	
	if( clmd->sim_parms->shapekey_rest )
		shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO );

	mvert = dm->getVertArray ( dm );

	verts = clmd->clothObject->verts;

	// set initial values
	for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ )
	{
		if(first)
		{
			copy_v3_v3( verts->x, mvert[i].co );

			mul_m4_v3( ob->obmat, verts->x );

			if( shapekey_rest ) {
				verts->xrest= shapekey_rest[i];
				mul_m4_v3( ob->obmat, verts->xrest );
			}
			else
				verts->xrest = verts->x;
		}
		
		/* no GUI interface yet */
		verts->mass = clmd->sim_parms->mass; 
		verts->impulse_count = 0;

		if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
			verts->goal= clmd->sim_parms->defgoal;
		else
			verts->goal= 0.0f;

		verts->flags = 0;
		copy_v3_v3 ( verts->xold, verts->x );
		copy_v3_v3 ( verts->xconst, verts->x );
		copy_v3_v3 ( verts->txold, verts->x );
		copy_v3_v3 ( verts->tx, verts->x );
		mul_v3_fl( verts->v, 0.0f );

		verts->impulse_count = 0;
		copy_v3_v3 ( verts->impulse, tnull );
	}
	
	// apply / set vertex groups
	// has to be happen before springs are build!
	cloth_apply_vgroup (clmd, dm);

	if ( !cloth_build_springs ( clmd, dm ) )
	{
		cloth_free_modifier ( clmd );
		modifier_setError ( & ( clmd->modifier ), "Can't build springs." );
		printf("cloth_free_modifier cloth_build_springs\n");
		return 0;
	}
	
	for ( i = 0; i < dm->getNumVerts(dm); i++)
	{
		if((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO))
		{
			cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL);
		}
	}
	
	// init our solver
	if ( solvers [clmd->sim_parms->solver_type].init ) {
		solvers [clmd->sim_parms->solver_type].init ( ob, clmd );
	}
	
	if(!first)
		implicit_set_positions(clmd);

	clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
	
	for(i = 0; i < dm->getNumVerts(dm); i++)
	{
		maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f));
	}
	
	clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );

	return 1;
}
Ejemplo n.º 18
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *dm,
                                  ModifierApplyFlag UNUSED(flag))
{
	UVWarpModifierData *umd = (UVWarpModifierData *) md;
	int i, 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);

	if (dvert) {
#pragma omp parallel for if (numPolys > OMP_LIMIT)
		for (i = 0; i < numPolys; i++) {
			float uv[2];
			MPoly *mp     = &mpoly[i];
			MLoop *ml     = &mloop[mp->loopstart];
			MLoopUV *mluv = &mloopuv[mp->loopstart];
			int l;
			for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
				const float weight = defvert_find_weight(&dvert[ml->v], defgrp_index);
				uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat, axis_u, axis_v);
				interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight);
			}
		}
	}
	else {
#pragma omp parallel for if (numPolys > OMP_LIMIT)
		for (i = 0; i < numPolys; i++) {
			MPoly *mp     = &mpoly[i];
			// MLoop *ml     = &mloop[mp->loopstart];
			MLoopUV *mluv = &mloopuv[mp->loopstart];
			int l;
			for (l = 0; l < mp->totloop; l++, /* ml++, */ mluv++) {
				uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v);
			}
		}
	}

	dm->dirty |= DM_DIRTY_TESS_CDLAYERS;

	return dm;
}
Ejemplo n.º 19
0
static void meshcache_do(
        MeshCacheModifierData *mcmd, Object *ob, DerivedMesh *UNUSED(dm),
        float (*vertexCos_Real)[3], int numVerts)
{
	const bool use_factor = mcmd->factor < 1.0f;
	float (*vertexCos_Store)[3] = (use_factor || (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ?
	                              MEM_mallocN(sizeof(*vertexCos_Store) * numVerts, __func__) : NULL;
	float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real;

	Scene *scene = mcmd->modifier.scene;
	const float fps = FPS;

	char filepath[FILE_MAX];
	const char *err_str = NULL;
	bool ok;

	float time;


	/* -------------------------------------------------------------------- */
	/* Interpret Time (the reading functions also do some of this ) */
	if (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA) {
		const float cfra = BKE_scene_frame_get(scene);

		switch (mcmd->time_mode) {
			case MOD_MESHCACHE_TIME_FRAME:
			{
				time = cfra;
				break;
			}
			case MOD_MESHCACHE_TIME_SECONDS:
			{
				time = cfra / fps;
				break;
			}
			case MOD_MESHCACHE_TIME_FACTOR:
			default:
			{
				time = cfra / fps;
				break;
			}
		}

		/* apply offset and scale */
		time = (mcmd->frame_scale * time) - mcmd->frame_start;
	}
	else {  /*  if (mcmd->play_mode == MOD_MESHCACHE_PLAY_EVAL) { */
		switch (mcmd->time_mode) {
			case MOD_MESHCACHE_TIME_FRAME:
			{
				time = mcmd->eval_frame;
				break;
			}
			case MOD_MESHCACHE_TIME_SECONDS:
			{
				time = mcmd->eval_time;
				break;
			}
			case MOD_MESHCACHE_TIME_FACTOR:
			default:
			{
				time = mcmd->eval_factor;
				break;
			}
		}
	}


	/* -------------------------------------------------------------------- */
	/* Read the File (or error out when the file is bad) */

	/* would be nice if we could avoid doing this _every_ frame */
	BLI_strncpy(filepath, mcmd->filepath, sizeof(filepath));
	BLI_path_abs(filepath, ID_BLEND_PATH(G.main, (ID *)ob));

	switch (mcmd->type) {
		case MOD_MESHCACHE_TYPE_MDD:
			ok = MOD_meshcache_read_mdd_times(filepath, vertexCos, numVerts,
			                                  mcmd->interp, time, fps, mcmd->time_mode, &err_str);
			break;
		case MOD_MESHCACHE_TYPE_PC2:
			ok = MOD_meshcache_read_pc2_times(filepath, vertexCos, numVerts,
			                                  mcmd->interp, time, fps, mcmd->time_mode, &err_str);
			break;
		default:
			ok = false;
			break;
	}


	/* -------------------------------------------------------------------- */
	/* tricky shape key integration (slow!) */
	if (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE) {
		Mesh *me = ob->data;

		/* we could support any object type */
		if (UNLIKELY(ob->type != OB_MESH)) {
			modifier_setError(&mcmd->modifier, "'Integrate' only valid for Mesh objects");
		}
		else if (UNLIKELY(me->totvert != numVerts)) {
			modifier_setError(&mcmd->modifier, "'Integrate' original mesh vertex mismatch");
		}
		else if (UNLIKELY(me->totpoly == 0)) {
			modifier_setError(&mcmd->modifier, "'Integrate' requires faces");
		}
		else {
			/* the moons align! */
			int i;

			float (*vertexCos_Source)[3] = MEM_mallocN(sizeof(*vertexCos_Source) * numVerts, __func__);
			float (*vertexCos_New)[3]    = MEM_mallocN(sizeof(*vertexCos_New) * numVerts, __func__);
			MVert *mv = me->mvert;

			for (i = 0; i < numVerts; i++, mv++) {
				copy_v3_v3(vertexCos_Source[i], mv->co);
			}

			BKE_mesh_calc_relative_deform(
			        me->mpoly, me->totpoly,
			        me->mloop, me->totvert,

			        (const float (*)[3])vertexCos_Source,   /* from the original Mesh*/
			        (const float (*)[3])vertexCos_Real,     /* the input we've been given (shape keys!) */

			        (const float (*)[3])vertexCos,          /* the result of this modifier */
			        vertexCos_New                           /* the result of this function */
			        );

			/* write the corrected locations back into the result */
			memcpy(vertexCos, vertexCos_New, sizeof(*vertexCos) * numVerts);

			MEM_freeN(vertexCos_Source);
			MEM_freeN(vertexCos_New);
		}
	}


	/* -------------------------------------------------------------------- */
	/* Apply the transformation matrix (if needed) */
	if (UNLIKELY(err_str)) {
		modifier_setError(&mcmd->modifier, "%s", err_str);
	}
	else if (ok) {
		bool use_matrix = false;
		float mat[3][3];
		unit_m3(mat);

		if (mat3_from_axis_conversion(mcmd->forward_axis, mcmd->up_axis, 1, 2, mat)) {
			use_matrix = true;
		}

		if (mcmd->flip_axis) {
			float tmat[3][3];
			unit_m3(tmat);
			if (mcmd->flip_axis & (1 << 0)) tmat[0][0] = -1.0f;
			if (mcmd->flip_axis & (1 << 1)) tmat[1][1] = -1.0f;
			if (mcmd->flip_axis & (1 << 2)) tmat[2][2] = -1.0f;
			mul_m3_m3m3(mat, tmat, mat);

			use_matrix = true;
		}

		if (use_matrix) {
			int i;
			for (i = 0; i < numVerts; i++) {
				mul_m3_v3(mat, vertexCos[i]);
			}
		}
	}

	if (vertexCos_Store) {
		if (ok) {
			if (use_factor) {
				interp_vn_vn(*vertexCos_Real, *vertexCos_Store, mcmd->factor, numVerts * 3);
			}
			else {
				memcpy(vertexCos_Real, vertexCos_Store, sizeof(*vertexCos_Store) * numVerts);
			}
		}

		MEM_freeN(vertexCos_Store);
	}
}
Ejemplo n.º 20
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DecimateModifierData *dmd = (DecimateModifierData *) md;
	DerivedMesh *dm = derivedData, *result = NULL;
	BMesh *bm;
	bool calc_face_normal;

	float *vweights = NULL;

#ifdef USE_TIMEIT
	TIMEIT_START(decim);
#endif

	/* set up front so we dont show invalid info in the UI */
	dmd->face_count = dm->getNumPolys(dm);

	switch (dmd->mode) {
		case MOD_DECIM_MODE_COLLAPSE:
			if (dmd->percent == 1.0f) {
				return dm;
			}
			calc_face_normal = true;
			break;
		case MOD_DECIM_MODE_UNSUBDIV:
			if (dmd->iter == 0) {
				return dm;
			}
			calc_face_normal = false;
			break;
		case MOD_DECIM_MODE_DISSOLVE:
			if (dmd->angle == 0.0f) {
				return dm;
			}
			calc_face_normal = true;
			break;
		default:
			return dm;
	}

	if (dmd->face_count <= 3) {
		modifier_setError(md, "Modifier requires more than 3 input faces");
		return dm;
	}

	if (dmd->mode == MOD_DECIM_MODE_COLLAPSE) {
		if (dmd->defgrp_name[0]) {
			MDeformVert *dvert;
			int defgrp_index;

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

			if (dvert) {
				const unsigned int vert_tot = dm->getNumVerts(dm);
				unsigned int i;

				vweights = MEM_mallocN(vert_tot * sizeof(float), __func__);

				if (dmd->flag & MOD_DECIM_FLAG_INVERT_VGROUP) {
					for (i = 0; i < vert_tot; i++) {
						const float f = 1.0f - defvert_find_weight(&dvert[i], defgrp_index);
						vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
					}
				}
				else {
					for (i = 0; i < vert_tot; i++) {
						const float f = defvert_find_weight(&dvert[i], defgrp_index);
						vweights[i] = f > BM_MESH_DECIM_WEIGHT_EPS ? (1.0f / f) : BM_MESH_DECIM_WEIGHT_MAX;
					}
				}
			}
		}
	}

	bm = DM_to_bmesh(dm, calc_face_normal);

	switch (dmd->mode) {
		case MOD_DECIM_MODE_COLLAPSE:
		{
			const int do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
			BM_mesh_decimate_collapse(bm, dmd->percent, vweights, do_triangulate);
			break;
		}
		case MOD_DECIM_MODE_UNSUBDIV:
		{
			BM_mesh_decimate_unsubdivide(bm, dmd->iter);
			break;
		}
		case MOD_DECIM_MODE_DISSOLVE:
		{
			const int do_dissolve_boundaries = (dmd->flag & MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS) != 0;
			BM_mesh_decimate_dissolve(bm, dmd->angle, do_dissolve_boundaries, (BMO_Delimit)dmd->delimit);
			break;
		}
	}

	if (vweights) {
		MEM_freeN(vweights);
	}

	/* update for display only */
	dmd->face_count = bm->totface;
	result = CDDM_from_bmesh(bm, false);
	BLI_assert(bm->vtoolflagpool == NULL &&
	           bm->etoolflagpool == NULL &&
	           bm->ftoolflagpool == NULL);  /* make sure we never alloc'd these */
	BLI_assert(bm->vtable == NULL &&
	           bm->etable == NULL &&
	           bm->ftable == NULL);

	BM_mesh_free(bm);

#ifdef USE_TIMEIT
	TIMEIT_END(decim);
#endif

	result->dirty = DM_DIRTY_NORMALS;

	return result;
}