/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
        DisplaceModifierData *dmd, Object *ob,
        DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
	int i;
	MVert *mvert;
	MDeformVert *dvert;
	int direction = dmd->direction;
	int defgrp_index;
	float (*tex_co)[3];
	float weight = 1.0f; /* init value unused but some compilers may complain */
	const float delta_fixed = 1.0f - dmd->midlevel;  /* when no texture is used, we fallback to white */
	float (*vert_clnors)[3] = NULL;

	if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
	if (dmd->strength == 0.0f) return;

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

	if (dmd->texture) {
		tex_co = MEM_callocN(sizeof(*tex_co) * numVerts,
		                     "displaceModifier_do tex_co");
		get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts);

		modifier_init_texture(dmd->modifier.scene, dmd->texture);
	}
	else {
		tex_co = NULL;
	}

	if (direction == MOD_DISP_DIR_CLNOR) {
		CustomData *ldata = dm->getLoopDataLayout(dm);

		if (CustomData_has_layer(ldata, CD_CUSTOMLOOPNORMAL)) {
			float (*clnors)[3] = NULL;

			if ((dm->dirty & DM_DIRTY_NORMALS) || !CustomData_has_layer(ldata, CD_NORMAL)) {
				dm->calcLoopNormals(dm, true, (float)M_PI);
			}

			clnors = CustomData_get_layer(ldata, CD_NORMAL);
			vert_clnors = MEM_mallocN(sizeof(*vert_clnors) * (size_t)numVerts, __func__);
			BKE_mesh_normals_loop_to_vertex(numVerts, dm->getLoopArray(dm), dm->getNumLoops(dm),
			                                (const float (*)[3])clnors, vert_clnors);
		}
		else {
			direction = MOD_DISP_DIR_NOR;
		}
	}

	for (i = 0; i < numVerts; i++) {
		TexResult texres;
		float strength = dmd->strength;
		float delta;

		if (dvert) {
			weight = defvert_find_weight(dvert + i, defgrp_index);
			if (weight == 0.0f) continue;
		}

		if (dmd->texture) {
			texres.nor = NULL;
			BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false);
			delta = texres.tin - dmd->midlevel;
		}
		else {
			delta = delta_fixed;  /* (1.0f - dmd->midlevel) */  /* never changes */
		}

		if (dvert) strength *= weight;

		delta *= strength;
		CLAMP(delta, -10000, 10000);

		switch (direction) {
			case MOD_DISP_DIR_X:
				vertexCos[i][0] += delta;
				break;
			case MOD_DISP_DIR_Y:
				vertexCos[i][1] += delta;
				break;
			case MOD_DISP_DIR_Z:
				vertexCos[i][2] += delta;
				break;
			case MOD_DISP_DIR_RGB_XYZ:
				vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength;
				vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength;
				vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength;
				break;
			case MOD_DISP_DIR_NOR:
				vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f);
				vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f);
				vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f);
				break;
			case MOD_DISP_DIR_CLNOR:
				madd_v3_v3fl(vertexCos[i], vert_clnors[i], delta);
				break;
		}
	}

	if (tex_co) {
		MEM_freeN(tex_co);
	}

	if (vert_clnors) {
		MEM_freeN(vert_clnors);
	}
}
Exemple #2
0
static void warpModifier_do(WarpModifierData *wmd,
                            const ModifierEvalContext *ctx,
                            Mesh *mesh,
                            float (*vertexCos)[3],
                            int numVerts)
{
  Object *ob = ctx->object;
  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];

  const float falloff_radius_sq = SQUARE(wmd->falloff_radius);
  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;
  }

  MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index);
  if (dvert == NULL) {
    defgrp_index = -1;
  }

  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;

  Tex *tex_target = wmd->texture;
  if (mesh != NULL && tex_target != NULL) {
    tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co");
    MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co);

    MOD_init_texture((MappingInfoModifierData *)wmd, ctx);
  }

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

    if (wmd->falloff_type == eWarp_Falloff_None ||
        ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq &&
         (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius))) {
      /* skip if no vert group found */
      if (defgrp_index != -1) {
        dv = &dvert[i];
        weight = defvert_find_weight(dv, defgrp_index) * strength;
        if (weight <= 0.0f) {
          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 = sqrtf(fac);
          break;
        case eWarp_Falloff_Linear:
          /* pass */
          break;
        case eWarp_Falloff_Const:
          fac = 1.0f;
          break;
        case eWarp_Falloff_Sphere:
          fac = sqrtf(2 * fac - fac * fac);
          break;
        case eWarp_Falloff_InvSquare:
          fac = fac * (2.0f - fac);
          break;
      }

      fac *= weight;

      if (tex_co) {
        struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
        TexResult texres;
        texres.nor = NULL;
        BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
        fac *= texres.tin;
      }

      if (fac != 0.0f) {
        /* into the 'from' objects space */
        mul_m4_v3(mat_from_inv, co);

        if (fac == 1.0f) {
          mul_m4_v3(mat_final, co);
        }
        else {
          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);
  }
}
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
        DisplaceModifierData *dmd, Object *ob,
        DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
	int i;
	MVert *mvert;
	MDeformVert *dvert;
	int defgrp_index;
	float (*tex_co)[3];
	float weight = 1.0f; /* init value unused but some compilers may complain */
	const float delta_fixed = 1.0f - dmd->midlevel;  /* when no texture is used, we fallback to white */

	if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return;
	if (dmd->strength == 0.0f) return;

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

	if (dmd->texture) {
		tex_co = MEM_callocN(sizeof(*tex_co) * numVerts,
		                     "displaceModifier_do tex_co");
		get_texture_coords((MappingInfoModifierData *)dmd, ob, dm, vertexCos, tex_co, numVerts);

		modifier_init_texture(dmd->modifier.scene, dmd->texture);
	}
	else {
		tex_co = NULL;
	}

	for (i = 0; i < numVerts; i++) {
		TexResult texres;
		float strength = dmd->strength;
		float delta;

		if (dvert) {
			weight = defvert_find_weight(dvert + i, defgrp_index);
			if (weight == 0.0f) continue;
		}

		if (dmd->texture) {
			texres.nor = NULL;
			BKE_texture_get_value(dmd->modifier.scene, dmd->texture, tex_co[i], &texres, false);
			delta = texres.tin - dmd->midlevel;
		}
		else {
			delta = delta_fixed;  /* (1.0f - dmd->midlevel) */  /* never changes */
		}

		if (dvert) strength *= weight;

		delta *= strength;
		CLAMP(delta, -10000, 10000);

		switch (dmd->direction) {
			case MOD_DISP_DIR_X:
				vertexCos[i][0] += delta;
				break;
			case MOD_DISP_DIR_Y:
				vertexCos[i][1] += delta;
				break;
			case MOD_DISP_DIR_Z:
				vertexCos[i][2] += delta;
				break;
			case MOD_DISP_DIR_RGB_XYZ:
				vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength;
				vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength;
				vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength;
				break;
			case MOD_DISP_DIR_NOR:
				vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f);
				vertexCos[i][1] += delta * (mvert[i].no[1] / 32767.0f);
				vertexCos[i][2] += delta * (mvert[i].no[2] / 32767.0f);
				break;
		}
	}

	if (tex_co) {
		MEM_freeN(tex_co);
	}
}
/* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
 * Return values are in org_w.
 * If indices is not NULL, it must be a table of same length as org_w and new_w, mapping to the real
 * vertex index (in case the weight tables do not cover the whole vertices...).
 * XXX The standard "factor" value is assumed in [0.0, 1.0] range. Else, weird results might appear.
 */
void weightvg_do_mask(int num, const int *indices, float *org_w, const float *new_w,
                      Object *ob, DerivedMesh *dm, float fact, const char defgrp_name[MAX_VGROUP_NAME],
                      Scene *scene, Tex *texture, int tex_use_channel, int tex_mapping,
                      Object *tex_map_object, const char *tex_uvlayer_name)
{
	int ref_didx;
	int i;

	/* If influence factor is null, nothing to do! */
	if (fact == 0.0f) return;

	/* If we want to mask vgroup weights from a texture. */
	if (texture) {
		/* The texture coordinates. */
		float (*tex_co)[3];
		/* See mapping note below... */
		MappingInfoModifierData t_map;
		float (*v_co)[3];
		int numVerts = dm->getNumVerts(dm);

		/* Use new generic get_texture_coords, but do not modify our DNA struct for it...
		 * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
		 *     What e.g. if a modifier wants to use several textures ?
		 *     Why use only v_co, and not MVert (or both) ?
		 */
		t_map.texture = texture;
		t_map.map_object = tex_map_object;
		BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
		t_map.texmapping = tex_mapping;
		v_co = MEM_mallocN(sizeof(*v_co) * numVerts, "WeightVG Modifier, TEX mode, v_co");
		dm->getVertCos(dm, v_co);
		tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, "WeightVG Modifier, TEX mode, tex_co");
		get_texture_coords(&t_map, ob, dm, v_co, tex_co, num);
		MEM_freeN(v_co);

		modifier_init_texture(scene, texture);

		/* For each weight (vertex), make the mix between org and new weights. */
		for (i = 0; i < num; ++i) {
			int idx = indices ? indices[i] : i;
			TexResult texres;
			float hsv[3]; /* For HSV color space. */
			bool do_color_manage;

			do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;

			texres.nor = NULL;
			BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage);
			/* Get the good channel value... */
			switch (tex_use_channel) {
				case MOD_WVG_MASK_TEX_USE_INT:
					org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
					break;
				case MOD_WVG_MASK_TEX_USE_RED:
					org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr * fact)));
					break;
				case MOD_WVG_MASK_TEX_USE_GREEN:
					org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg * fact)));
					break;
				case MOD_WVG_MASK_TEX_USE_BLUE:
					org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb * fact)));
					break;
				case MOD_WVG_MASK_TEX_USE_HUE:
					rgb_to_hsv_v(&texres.tr, hsv);
					org_w[i] = (new_w[i] * hsv[0] * fact) + (org_w[i] * (1.0f - (hsv[0] * fact)));
					break;
				case MOD_WVG_MASK_TEX_USE_SAT:
					rgb_to_hsv_v(&texres.tr, hsv);
					org_w[i] = (new_w[i] * hsv[1] * fact) + (org_w[i] * (1.0f - (hsv[1] * fact)));
					break;
				case MOD_WVG_MASK_TEX_USE_VAL:
					rgb_to_hsv_v(&texres.tr, hsv);
					org_w[i] = (new_w[i] * hsv[2] * fact) + (org_w[i] * (1.0f - (hsv[2] * fact)));
					break;
				case MOD_WVG_MASK_TEX_USE_ALPHA:
					org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta * fact)));
					break;
				default:
					org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
					break;
			}
		}

		MEM_freeN(tex_co);
	}
	else if ((ref_didx = defgroup_name_index(ob, defgrp_name)) != -1) {
		MDeformVert *dvert = NULL;

		/* Check whether we want to set vgroup weights from a constant weight factor or a vertex
		 * group.
		 */
		/* Get vgroup idx from its name. */

		/* Proceed only if vgroup is valid, else use constant factor. */
		/* Get actual dverts (ie vertex group data). */
		dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
		/* Proceed only if vgroup is valid, else assume factor = O. */
		if (dvert == NULL) return;

		/* For each weight (vertex), make the mix between org and new weights. */
		for (i = 0; i < num; i++) {
			int idx = indices ? indices[i] : i;
			const float f = defvert_find_weight(&dvert[idx], ref_didx) * fact;
			org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f - f));
			/* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
		}
	}
	else {
		/* Default "influence" behavior. */
		/* For each weight (vertex), make the mix between org and new weights. */
		const float ifact = 1.0f - fact;
		for (i = 0; i < num; i++) {
			org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
		}
	}
}
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);
}
Exemple #6
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);

}