Example #1
0
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
  BLI_assert(mesh != NULL);

  WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;

  MDeformVert *dvert = NULL;
  MDeformWeight **dw1, **tdw1, **dw2, **tdw2;
  float *org_w;
  float *new_w;
  int *tidx, *indices = NULL;
  int numIdx = 0;
  int i;
  /* Flags. */
#if 0
  const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
#endif

  /* Get number of verts. */
  const int numVerts = mesh->totvert;

  /* Check if we can just return the original mesh.
   * Must have verts and therefore verts assigned to vgroups to do anything useful!
   */
  if ((numVerts == 0) || BLI_listbase_is_empty(&ctx->object->defbase)) {
    return mesh;
  }

  /* Get vgroup idx from its name. */
  const int defgrp_index = defgroup_name_index(ctx->object, wmd->defgrp_name_a);
  if (defgrp_index == -1) {
    return mesh;
  }
  /* Get second vgroup idx from its name, if given. */
  int defgrp_index_other = -1;
  if (wmd->defgrp_name_b[0] != '\0') {
    defgrp_index_other = defgroup_name_index(ctx->object, wmd->defgrp_name_b);
    if (defgrp_index_other == -1) {
      return mesh;
    }
  }

  const bool has_mdef = CustomData_has_layer(&mesh->vdata, CD_MDEFORMVERT);
  /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
  if (!has_mdef) {
    /* If not affecting all vertices, just return. */
    if (wmd->mix_set != MOD_WVG_SET_ALL) {
      return mesh;
    }
  }

  if (has_mdef) {
    dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
  }
  else {
    /* Add a valid data layer! */
    dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
  }
  /* Ultimate security check. */
  if (!dvert) {
    return mesh;
  }
  mesh->dvert = dvert;

  /* Find out which vertices to work on. */
  tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx");
  tdw1 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw1");
  tdw2 = MEM_malloc_arrayN(numVerts, sizeof(MDeformWeight *), "WeightVGMix Modifier, tdw2");
  switch (wmd->mix_set) {
    case MOD_WVG_SET_A:
      /* All vertices in first vgroup. */
      for (i = 0; i < numVerts; i++) {
        MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_index);
        if (dw) {
          tdw1[numIdx] = dw;
          tdw2[numIdx] = (defgrp_index_other >= 0) ?
                             defvert_find_index(&dvert[i], defgrp_index_other) :
                             NULL;
          tidx[numIdx++] = i;
        }
      }
      break;
    case MOD_WVG_SET_B:
      /* All vertices in second vgroup. */
      for (i = 0; i < numVerts; i++) {
        MDeformWeight *dw = (defgrp_index_other >= 0) ?
                                defvert_find_index(&dvert[i], defgrp_index_other) :
                                NULL;
        if (dw) {
          tdw1[numIdx] = defvert_find_index(&dvert[i], defgrp_index);
          tdw2[numIdx] = dw;
          tidx[numIdx++] = i;
        }
      }
      break;
    case MOD_WVG_SET_OR:
      /* All vertices in one vgroup or the other. */
      for (i = 0; i < numVerts; i++) {
        MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_index);
        MDeformWeight *bdw = (defgrp_index_other >= 0) ?
                                 defvert_find_index(&dvert[i], defgrp_index_other) :
                                 NULL;
        if (adw || bdw) {
          tdw1[numIdx] = adw;
          tdw2[numIdx] = bdw;
          tidx[numIdx++] = i;
        }
      }
      break;
    case MOD_WVG_SET_AND:
      /* All vertices in both vgroups. */
      for (i = 0; i < numVerts; i++) {
        MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_index);
        MDeformWeight *bdw = (defgrp_index_other >= 0) ?
                                 defvert_find_index(&dvert[i], defgrp_index_other) :
                                 NULL;
        if (adw && bdw) {
          tdw1[numIdx] = adw;
          tdw2[numIdx] = bdw;
          tidx[numIdx++] = i;
        }
      }
      break;
    case MOD_WVG_SET_ALL:
    default:
      /* Use all vertices. */
      for (i = 0; i < numVerts; i++) {
        tdw1[i] = defvert_find_index(&dvert[i], defgrp_index);
        tdw2[i] = (defgrp_index_other >= 0) ? defvert_find_index(&dvert[i], defgrp_index_other) :
                                              NULL;
      }
      numIdx = -1;
      break;
  }
  if (numIdx == 0) {
    /* Use no vertices! Hence, return org data. */
    MEM_freeN(tdw1);
    MEM_freeN(tdw2);
    MEM_freeN(tidx);
    return mesh;
  }
  if (numIdx != -1) {
    indices = MEM_malloc_arrayN(numIdx, sizeof(int), "WeightVGMix Modifier, indices");
    memcpy(indices, tidx, sizeof(int) * numIdx);
    dw1 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw1");
    memcpy(dw1, tdw1, sizeof(MDeformWeight *) * numIdx);
    MEM_freeN(tdw1);
    dw2 = MEM_malloc_arrayN(numIdx, sizeof(MDeformWeight *), "WeightVGMix Modifier, dw2");
    memcpy(dw2, tdw2, sizeof(MDeformWeight *) * numIdx);
    MEM_freeN(tdw2);
  }
  else {
    /* Use all vertices. */
    numIdx = numVerts;
    /* Just copy MDeformWeight pointers arrays, they will be freed at the end. */
    dw1 = tdw1;
    dw2 = tdw2;
  }
  MEM_freeN(tidx);

  org_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, org_w");
  new_w = MEM_malloc_arrayN(numIdx, sizeof(float), "WeightVGMix Modifier, new_w");

  /* Mix weights. */
  for (i = 0; i < numIdx; i++) {
    float weight2;
    org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
    weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;

    new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
  }

  /* Do masking. */
  struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
  weightvg_do_mask(ctx,
                   numIdx,
                   indices,
                   org_w,
                   new_w,
                   ctx->object,
                   mesh,
                   wmd->mask_constant,
                   wmd->mask_defgrp_name,
                   scene,
                   wmd->mask_texture,
                   wmd->mask_tex_use_channel,
                   wmd->mask_tex_mapping,
                   wmd->mask_tex_map_obj,
                   wmd->mask_tex_uvlayer_name);

  /* Update (add to) vgroup.
   * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
   */
  weightvg_update_vg(
      dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f);

  /* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
  if (do_prev)
    DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices);
#endif

  /* Freeing stuff. */
  MEM_freeN(org_w);
  MEM_freeN(new_w);
  MEM_freeN(dw1);
  MEM_freeN(dw2);
  MEM_SAFE_FREE(indices);

  /* Return the vgroup-modified mesh. */
  return mesh;
}
void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float weight)
{
	Object *ob = lattice_deform_data->object;
	Lattice *lt = ob->data;
	float u, v, w, tu[4], tv[4], tw[4];
	float vec[3];
	int idx_w, idx_v, idx_u;
	int ui, vi, wi, uu, vv, ww;

	/* vgroup influence */
	int defgrp_index = -1;
	float co_prev[3], weight_blend = 0.0f;
	MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);


	if (lt->editlatt) lt = lt->editlatt->latt;
	if (lattice_deform_data->latticedata == NULL) return;

	if (lt->vgroup[0] && dvert) {
		defgrp_index = defgroup_name_index(ob, lt->vgroup);
		copy_v3_v3(co_prev, co);
	}

	/* co is in local coords, treat with latmat */
	mul_v3_m4v3(vec, lattice_deform_data->latmat, co);

	/* u v w coords */

	if (lt->pntsu > 1) {
		u = (vec[0] - lt->fu) / lt->du;
		ui = (int)floor(u);
		u -= ui;
		key_curve_position_weights(u, tu, lt->typeu);
	}
	else {
		tu[0] = tu[2] = tu[3] = 0.0; tu[1] = 1.0;
		ui = 0;
	}

	if (lt->pntsv > 1) {
		v = (vec[1] - lt->fv) / lt->dv;
		vi = (int)floor(v);
		v -= vi;
		key_curve_position_weights(v, tv, lt->typev);
	}
	else {
		tv[0] = tv[2] = tv[3] = 0.0; tv[1] = 1.0;
		vi = 0;
	}

	if (lt->pntsw > 1) {
		w = (vec[2] - lt->fw) / lt->dw;
		wi = (int)floor(w);
		w -= wi;
		key_curve_position_weights(w, tw, lt->typew);
	}
	else {
		tw[0] = tw[2] = tw[3] = 0.0; tw[1] = 1.0;
		wi = 0;
	}

	for (ww = wi - 1; ww <= wi + 2; ww++) {
		w = tw[ww - wi + 1];

		if (w != 0.0f) {
			if (ww > 0) {
				if (ww < lt->pntsw) idx_w = ww * lt->pntsu * lt->pntsv;
				else                idx_w = (lt->pntsw - 1) * lt->pntsu * lt->pntsv;
			}
			else {
				idx_w = 0;
			}

			for (vv = vi - 1; vv <= vi + 2; vv++) {
				v = w * tv[vv - vi + 1];

				if (v != 0.0f) {
					if (vv > 0) {
						if (vv < lt->pntsv) idx_v = idx_w + vv * lt->pntsu;
						else                idx_v = idx_w + (lt->pntsv - 1) * lt->pntsu;
					}
					else {
						idx_v = idx_w;
					}

					for (uu = ui - 1; uu <= ui + 2; uu++) {
						u = weight * v * tu[uu - ui + 1];

						if (u != 0.0f) {
							if (uu > 0) {
								if (uu < lt->pntsu) idx_u = idx_v + uu;
								else                idx_u = idx_v + (lt->pntsu - 1);
							}
							else {
								idx_u = idx_v;
							}

							madd_v3_v3fl(co, &lattice_deform_data->latticedata[idx_u * 3], u);

							if (defgrp_index != -1)
								weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index));
						}
					}
				}
			}
		}
	}

	if (defgrp_index != -1)
		interp_v3_v3v3(co, co_prev, co, weight_blend);

}
void curve_deform_verts(
        Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
        int numVerts, const char *vgroup, short defaxis)
{
	Curve *cu;
	int a;
	CurveDeform cd;
	MDeformVert *dvert = NULL;
	int defgrp_index = -1;
	const bool is_neg_axis = (defaxis > 2);

	if (cuOb->type != OB_CURVE)
		return;

	cu = cuOb->data;

	init_curve_deform(cuOb, target, &cd);

	/* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
	if (is_neg_axis == false) {
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
	}
	else {
		/* negative, these bounds give a good rest position */
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] =  0.0f;
	}
	
	/* Check whether to use vertex groups (only possible if target is a Mesh or Lattice).
	 * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
	 */
	if (vgroup && vgroup[0] && ELEM(target->type, OB_MESH, OB_LATTICE)) {
		defgrp_index = defgroup_name_index(target, vgroup);

		if (defgrp_index != -1) {
			/* if there's derived data without deformverts, don't use vgroups */
			if (dm) {
				dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
			}
			else if (target->type == OB_LATTICE) {
				dvert = ((Lattice *)target->data)->dvert;
			}
			else {
				dvert = ((Mesh *)target->data)->dvert;
			}
		}
	}

	if (dvert) {
		MDeformVert *dvert_iter;
		float vec[3];

		if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
			for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
				const float weight = defvert_find_weight(dvert_iter, defgrp_index);

				if (weight > 0.0f) {
					mul_m4_v3(cd.curvespace, vertexCos[a]);
					copy_v3_v3(vec, vertexCos[a]);
					calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
					interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
					mul_m4_v3(cd.objectspace, vertexCos[a]);
				}
			}
		}
		else {
			/* set mesh min/max bounds */
			INIT_MINMAX(cd.dmin, cd.dmax);

			for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
				if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) {
					mul_m4_v3(cd.curvespace, vertexCos[a]);
					minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
				}
			}

			for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
				const float weight = defvert_find_weight(dvert_iter, defgrp_index);

				if (weight > 0.0f) {
					/* already in 'cd.curvespace', prev for loop */
					copy_v3_v3(vec, vertexCos[a]);
					calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
					interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
					mul_m4_v3(cd.objectspace, vertexCos[a]);
				}
			}
		}
	}
	else {
		if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
		else {
			/* set mesh min max bounds */
			INIT_MINMAX(cd.dmin, cd.dmax);
				
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
			}
	
			for (a = 0; a < numVerts; a++) {
				/* already in 'cd.curvespace', prev for loop */
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
	}
}
Example #4
0
void curve_deform_verts(Scene *scene, Object *cuOb, Object *target,
                        DerivedMesh *dm, float (*vertexCos)[3],
                        int numVerts, const char *vgroup, short defaxis)
{
	Curve *cu;
	int a, flag;
	CurveDeform cd;
	int use_vgroups;
	const int is_neg_axis = (defaxis > 2);

	if (cuOb->type != OB_CURVE)
		return;

	cu = cuOb->data;
	flag = cu->flag;
	cu->flag |= (CU_PATH | CU_FOLLOW); // needed for path & bevlist

	init_curve_deform(cuOb, target, &cd);

	/* dummy bounds, keep if CU_DEFORM_BOUNDS_OFF is set */
	if (is_neg_axis == FALSE) {
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = 0.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 1.0f;
	}
	else {
		/* negative, these bounds give a good rest position */
		cd.dmin[0] = cd.dmin[1] = cd.dmin[2] = -1.0f;
		cd.dmax[0] = cd.dmax[1] = cd.dmax[2] =  0.0f;
	}
	
	/* check whether to use vertex groups (only possible if target is a Mesh)
	 * we want either a Mesh with no derived data, or derived data with
	 * deformverts
	 */
	if (target && target->type == OB_MESH) {
		/* if there's derived data without deformverts, don't use vgroups */
		if (dm) {
			use_vgroups = (dm->getVertData(dm, 0, CD_MDEFORMVERT) != NULL);
		}
		else {
			Mesh *me = target->data;
			use_vgroups = (me->dvert != NULL);
		}
	}
	else {
		use_vgroups = FALSE;
	}
	
	if (vgroup && vgroup[0] && use_vgroups) {
		Mesh *me = target->data;
		const int defgrp_index = defgroup_name_index(target, vgroup);

		if (defgrp_index != -1 && (me->dvert || dm)) {
			MDeformVert *dvert = me->dvert;
			float vec[3];
			float weight;
	

			if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
				dvert = me->dvert;
				for (a = 0; a < numVerts; a++, dvert++) {
					if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
					weight = defvert_find_weight(dvert, defgrp_index);
	
					if (weight > 0.0f) {
						mul_m4_v3(cd.curvespace, vertexCos[a]);
						copy_v3_v3(vec, vertexCos[a]);
						calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
						interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
						mul_m4_v3(cd.objectspace, vertexCos[a]);
					}
				}
			}
			else {
				/* set mesh min/max bounds */
				INIT_MINMAX(cd.dmin, cd.dmax);
	
				for (a = 0; a < numVerts; a++, dvert++) {
					if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
					
					if (defvert_find_weight(dvert, defgrp_index) > 0.0f) {
						mul_m4_v3(cd.curvespace, vertexCos[a]);
						minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
					}
				}
	
				dvert = me->dvert;
				for (a = 0; a < numVerts; a++, dvert++) {
					if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
					
					weight = defvert_find_weight(dvert, defgrp_index);
	
					if (weight > 0.0f) {
						/* already in 'cd.curvespace', prev for loop */
						copy_v3_v3(vec, vertexCos[a]);
						calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
						interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
						mul_m4_v3(cd.objectspace, vertexCos[a]);
					}
				}
			}
		}
	}
	else {
		if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
		else {
			/* set mesh min max bounds */
			INIT_MINMAX(cd.dmin, cd.dmax);
				
			for (a = 0; a < numVerts; a++) {
				mul_m4_v3(cd.curvespace, vertexCos[a]);
				minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
			}
	
			for (a = 0; a < numVerts; a++) {
				/* already in 'cd.curvespace', prev for loop */
				calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
				mul_m4_v3(cd.objectspace, vertexCos[a]);
			}
		}
	}
	cu->flag = flag;
}
/* 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);
		}
	}
}
Example #6
0
static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(
    ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights,
    const int num_elem_dst, const bool use_create, const bool use_delete,
    Object *ob_src, Object *ob_dst, MDeformVert *data_src, MDeformVert *data_dst,
    CustomData *UNUSED(cd_src), CustomData *cd_dst, const bool UNUSED(use_dupref_dst),
    const int tolayers, bool *use_layers_src, const int num_layers_src)
{
    int idx_src;
    int idx_dst;
    int tot_dst = BLI_listbase_count(&ob_dst->defbase);

    const size_t elem_size = sizeof(*((MDeformVert *)NULL));

    switch (tolayers) {
    case DT_LAYERS_INDEX_DST:
        idx_dst = tot_dst;

        /* Find last source actually used! */
        idx_src = num_layers_src;
        while (idx_src-- && !use_layers_src[idx_src]);
        idx_src++;

        if (idx_dst < idx_src) {
            if (!use_create) {
                return false;
            }
            /* Create as much vgroups as necessary! */
            for (; idx_dst < idx_src; idx_dst++) {
                BKE_object_defgroup_add(ob_dst);
            }
        }
        else if (use_delete && idx_dst > idx_src) {
            while (idx_dst-- > idx_src) {
                BKE_object_defgroup_remove(ob_dst, ob_dst->defbase.last);
            }
        }
        if (r_map) {
            /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
             * Again, use_create is not relevant in this case */
            if (!data_dst) {
                data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
            }

            while (idx_src--) {
                if (!use_layers_src[idx_src]) {
                    continue;
                }
                data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
                                                     data_src, data_dst, idx_src, idx_src,
                                                     elem_size, 0, 0, 0, vgroups_datatransfer_interp);
            }
        }
        break;
    case DT_LAYERS_NAME_DST:
    {
        bDeformGroup *dg_src, *dg_dst;

        if (use_delete) {
            /* Remove all unused dst vgroups first, simpler in this case. */
            for (dg_dst = ob_dst->defbase.first; dg_dst;) {
                bDeformGroup *dg_dst_next = dg_dst->next;

                if (defgroup_name_index(ob_src, dg_dst->name) == -1) {
                    BKE_object_defgroup_remove(ob_dst, dg_dst);
                }
                dg_dst = dg_dst_next;
            }
        }

        for (idx_src = 0, dg_src = ob_src->defbase.first;
                idx_src < num_layers_src;
                idx_src++, dg_src = dg_src->next)
        {
            if (!use_layers_src[idx_src]) {
                continue;
            }

            if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) {
                if (!use_create) {
                    if (r_map) {
                        BLI_freelistN(r_map);
                    }
                    return false;
                }
                BKE_object_defgroup_add_name(ob_dst, dg_src->name);
                idx_dst = ob_dst->actdef - 1;
            }
            if (r_map) {
                /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
                 * use_create is not relevant in this case */
                if (!data_dst) {
                    data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
                }

                data_transfer_layersmapping_add_item(
                    r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
                    data_src, data_dst, idx_src, idx_dst,
                    elem_size, 0, 0, 0, vgroups_datatransfer_interp);
            }
        }
        break;
    }
    default:
        return false;
    }

    return true;
}
Example #7
0
bool data_transfer_layersmapping_vgroups(
    ListBase *r_map, const int mix_mode, const float mix_factor, const float *mix_weights,
    const int num_elem_dst, const bool use_create, const bool use_delete, Object *ob_src, Object *ob_dst,
    CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst, const int fromlayers, const int tolayers)
{
    int idx_src, idx_dst;
    MDeformVert *data_src, *data_dst = NULL;

    const size_t elem_size = sizeof(*((MDeformVert *)NULL));

    /* Note: VGroups are a bit hairy, since their layout is defined on object level (ob->defbase), while their actual
     *       data is a (mesh) CD layer.
     *       This implies we may have to handle data layout itself while having NULL data itself,
     *       and even have to support NULL data_src in transfer data code (we always create a data_dst, though).
     */

    if (BLI_listbase_is_empty(&ob_src->defbase)) {
        if (use_delete) {
            BKE_object_defgroup_remove_all(ob_dst);
        }
        return true;
    }

    data_src = CustomData_get_layer(cd_src, CD_MDEFORMVERT);

    data_dst = CustomData_get_layer(cd_dst, CD_MDEFORMVERT);
    if (data_dst && use_dupref_dst && r_map) {
        /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
        data_dst = CustomData_duplicate_referenced_layer(cd_dst, CD_MDEFORMVERT, num_elem_dst);
    }

    if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
        /* Note: use_delete has not much meaning in this case, ignored. */

        if (fromlayers >= 0) {
            idx_src = fromlayers;
            BLI_assert(idx_src < BLI_listbase_count(&ob_src->defbase));
        }
        else if ((idx_src = ob_src->actdef - 1) == -1) {
            return false;
        }

        if (tolayers >= 0) {
            /* Note: in this case we assume layer exists! */
            idx_dst = tolayers;
            BLI_assert(idx_dst < BLI_listbase_count(&ob_dst->defbase));
        }
        else if (tolayers == DT_LAYERS_ACTIVE_DST) {
            if ((idx_dst = ob_dst->actdef - 1) == -1) {
                bDeformGroup *dg_src;
                if (!use_create) {
                    return true;
                }
                dg_src = BLI_findlink(&ob_src->defbase, idx_src);
                BKE_object_defgroup_add_name(ob_dst, dg_src->name);
                idx_dst = ob_dst->actdef - 1;
            }
        }
        else if (tolayers == DT_LAYERS_INDEX_DST) {
            int num = BLI_listbase_count(&ob_src->defbase);
            idx_dst = idx_src;
            if (num <= idx_dst) {
                if (!use_create) {
                    return true;
                }
                /* Create as much vgroups as necessary! */
                for (; num <= idx_dst; num++) {
                    BKE_object_defgroup_add(ob_dst);
                }
            }
        }
        else if (tolayers == DT_LAYERS_NAME_DST) {
            bDeformGroup *dg_src = BLI_findlink(&ob_src->defbase, idx_src);
            if ((idx_dst = defgroup_name_index(ob_dst, dg_src->name)) == -1) {
                if (!use_create) {
                    return true;
                }
                BKE_object_defgroup_add_name(ob_dst, dg_src->name);
                idx_dst = ob_dst->actdef - 1;
            }
        }
        else {
            return false;
        }

        if (r_map) {
            /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest!
             * use_create is not relevant in this case */
            if (!data_dst) {
                data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst);
            }

            data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
                                                 data_src, data_dst, idx_src, idx_dst,
                                                 elem_size, 0, 0, 0, vgroups_datatransfer_interp);
        }
    }
    else {
        int num_src, num_sel_unused;
        bool *use_layers_src = NULL;
        bool ret = false;

        switch (fromlayers) {
        case DT_LAYERS_ALL_SRC:
            use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_ALL,
                             &num_src, &num_sel_unused);
            break;
        case DT_LAYERS_VGROUP_SRC_BONE_SELECT:
            use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_SELECT,
                             &num_src, &num_sel_unused);
            break;
        case DT_LAYERS_VGROUP_SRC_BONE_DEFORM:
            use_layers_src = BKE_object_defgroup_subset_from_select_type(ob_src, WT_VGROUP_BONE_DEFORM,
                             &num_src, &num_sel_unused);
            break;
        }

        if (use_layers_src) {
            ret = data_transfer_layersmapping_vgroups_multisrc_to_dst(
                      r_map, mix_mode, mix_factor, mix_weights, num_elem_dst, use_create, use_delete,
                      ob_src, ob_dst, data_src, data_dst, cd_src, cd_dst, use_dupref_dst,
                      tolayers, use_layers_src, num_src);
        }

        MEM_SAFE_FREE(use_layers_src);
        return ret;
    }

    return true;
}
bool BKE_object_data_transfer_dm(
        Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create,
        const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
        SpaceTransform *space_transform, const bool auto_transform,
        const float max_distance, const float ray_radius, const float islands_handling_precision,
        const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
        const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
        ReportList *reports)
{
#define VDATA 0
#define EDATA 1
#define LDATA 2
#define PDATA 3
#define DATAMAX 4

	SpaceTransform auto_space_transform;

	DerivedMesh *dm_src;
	Mesh *me_dst, *me_src;
	bool dirty_nors_dst = true;  /* Assumed always true if not using a dm as destination. */
	int i;

	MDeformVert *mdef = NULL;
	int vg_idx = -1;
	float *weights[DATAMAX] = {NULL};

	MeshPairRemap geom_map[DATAMAX] = {{0}};
	bool geom_map_init[DATAMAX] = {0};
	ListBase lay_map = {NULL};
	bool changed = false;

	const bool use_delete = false;  /* We never delete data layers from destination here. */

	CustomDataMask dm_src_mask = CD_MASK_BAREMESH;

	BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));

	me_dst = ob_dst->data;
	me_src = ob_src->data;
	if (dm_dst) {
		dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0;
		use_create = false;  /* Never create needed custom layers on DM (modifier case). */
	}

	if (vgroup_name) {
		if (dm_dst) {
			mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT);
		}
		else {
			mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
		}
		if (mdef) {
			vg_idx = defgroup_name_index(ob_dst, vgroup_name);
		}
	}

	/* Get source DM.*/
	dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
	/* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm,
	 *     can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers...
	 *     Issue is, this means we cannot be sure to have requested cd layers in source.
	 *
	 *     Also, we need to make a local copy of dm_src, otherwise we may end with concurrent creation
	 *     of data in it (multi-threaded evaluation of the modifier stack, see T46672).
	 */
	dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask);
	if (!dm_src) {
		return changed;
	}
	dm_src = CDDM_copy(dm_src);

	if (auto_transform) {
		MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
		const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;

		if (space_transform == NULL) {
			space_transform = &auto_space_transform;
		}

		BKE_mesh_remap_find_best_match_from_dm(verts_dst, num_verts_dst, dm_src, space_transform);
	}

	/* Check all possible data types.
	 * Note item mappings and dest mix weights are cached. */
	for (i = 0; i < DT_TYPE_MAX; i++) {
		const int dtdata_type = 1 << i;
		int cddata_type;
		int fromlayers, tolayers, fromto_idx;

		if (!(data_types & dtdata_type)) {
			continue;
		}

		data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst,
		                                     dtdata_type, dirty_nors_dst,
		                                     (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh);

		cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);

		fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
		if (fromto_idx != DT_MULTILAYER_INDEX_INVALID) {
			fromlayers = fromlayers_select[fromto_idx];
			tolayers = tolayers_select[fromto_idx];
		}
		else {
			fromlayers = tolayers = 0;
		}

		if (DT_DATATYPE_IS_VERT(dtdata_type)) {
			MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
			const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;

			if (!geom_map_init[VDATA]) {
				const int num_verts_src = dm_src->getNumVerts(dm_src);

				if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source and destination meshes do not have the same amount of vertices, "
					           "'Topology' mapping cannot be used in this case");
					continue;
				}
				if (ELEM(0, num_verts_dst, num_verts_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source or destination meshes do not have any vertices, cannot transfer vertex data");
					continue;
				}

				BKE_mesh_remap_calc_verts_from_dm(
				        map_vert_mode, space_transform, max_distance, ray_radius,
				        verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]);
				geom_map_init[VDATA] = true;
			}

			if (mdef && vg_idx != -1 && !weights[VDATA]) {
				weights[VDATA] = MEM_mallocN(sizeof(*(weights[VDATA])) * (size_t)num_verts_dst, __func__);
				BKE_defvert_extract_vgroup_to_vertweights(mdef, vg_idx, num_verts_dst, weights[VDATA], invert_vgroup);
			}

			if (data_transfer_layersmapping_generate(
			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT,
			        cddata_type, mix_mode, mix_factor, weights[VDATA],
			        num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
			{
				CustomDataTransferLayerMap *lay_mapit;

				changed = (lay_map.first != NULL);

				for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
					CustomData_data_transfer(&geom_map[VDATA], lay_mapit);
				}

				BLI_freelistN(&lay_map);
			}
		}
		if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
			MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
			const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
			MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
			const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;

			if (!geom_map_init[EDATA]) {
				const int num_edges_src = dm_src->getNumEdges(dm_src);

				if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source and destination meshes do not have the same amount of edges, "
					           "'Topology' mapping cannot be used in this case");
					continue;
				}
				if (ELEM(0, num_edges_dst, num_edges_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source or destination meshes do not have any edges, cannot transfer edge data");
					continue;
				}

				BKE_mesh_remap_calc_edges_from_dm(
				        map_edge_mode, space_transform, max_distance, ray_radius,
				        verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst,
				        dm_src, &geom_map[EDATA]);
				geom_map_init[EDATA] = true;
			}

			if (mdef && vg_idx != -1 && !weights[EDATA]) {
				weights[EDATA] = MEM_mallocN(sizeof(*weights[EDATA]) * (size_t)num_edges_dst, __func__);
				BKE_defvert_extract_vgroup_to_edgeweights(
				        mdef, vg_idx, num_verts_dst, edges_dst, num_edges_dst,
				        weights[EDATA], invert_vgroup);
			}

			if (data_transfer_layersmapping_generate(
			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE,
			        cddata_type, mix_mode, mix_factor, weights[EDATA],
			        num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
			{
				CustomDataTransferLayerMap *lay_mapit;

				changed = (lay_map.first != NULL);

				for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
					CustomData_data_transfer(&geom_map[EDATA], lay_mapit);
				}

				BLI_freelistN(&lay_map);
			}
		}
		if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
			MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
			const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
			MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
			const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
			MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
			const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
			MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
			const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
			CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
			CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;

			MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);

			if (!geom_map_init[LDATA]) {
				const int num_loops_src = dm_src->getNumLoops(dm_src);

				if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source and destination meshes do not have the same amount of face corners, "
					           "'Topology' mapping cannot be used in this case");
					continue;
				}
				if (ELEM(0, num_loops_dst, num_loops_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source or destination meshes do not have any polygons, cannot transfer loop data");
					continue;
				}

				BKE_mesh_remap_calc_loops_from_dm(
				        map_loop_mode, space_transform, max_distance, ray_radius,
				        verts_dst, num_verts_dst, edges_dst, num_edges_dst,
				        loops_dst, num_loops_dst, polys_dst, num_polys_dst,
				        ldata_dst, pdata_dst,
				        (me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst,
				        dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh,
				        island_callback, islands_handling_precision, &geom_map[LDATA]);
				geom_map_init[LDATA] = true;
			}

			if (mdef && vg_idx != -1 && !weights[LDATA]) {
				weights[LDATA] = MEM_mallocN(sizeof(*weights[LDATA]) * (size_t)num_loops_dst, __func__);
				BKE_defvert_extract_vgroup_to_loopweights(
				        mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst,
				        weights[LDATA], invert_vgroup);
			}

			if (data_transfer_layersmapping_generate(
			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP,
			        cddata_type, mix_mode, mix_factor, weights[LDATA],
			        num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
			{
				CustomDataTransferLayerMap *lay_mapit;

				changed = (lay_map.first != NULL);

				for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
					CustomData_data_transfer(&geom_map[LDATA], lay_mapit);
				}

				BLI_freelistN(&lay_map);
			}
		}
		if (DT_DATATYPE_IS_POLY(dtdata_type)) {
			MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
			const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
			MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
			const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
			MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
			const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
			CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;

			if (!geom_map_init[PDATA]) {
				const int num_polys_src = dm_src->getNumPolys(dm_src);

				if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source and destination meshes do not have the same amount of faces, "
					           "'Topology' mapping cannot be used in this case");
					continue;
				}
				if (ELEM(0, num_polys_dst, num_polys_src)) {
					BKE_report(reports, RPT_ERROR,
					           "Source or destination meshes do not have any polygons, cannot transfer poly data");
					continue;
				}

				BKE_mesh_remap_calc_polys_from_dm(
				        map_poly_mode, space_transform, max_distance, ray_radius,
				        verts_dst, num_verts_dst, loops_dst, num_loops_dst,
				        polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst,
				        dm_src, &geom_map[PDATA]);
				geom_map_init[PDATA] = true;
			}

			if (mdef && vg_idx != -1 && !weights[PDATA]) {
				weights[PDATA] = MEM_mallocN(sizeof(*weights[PDATA]) * (size_t)num_polys_dst, __func__);
				BKE_defvert_extract_vgroup_to_polyweights(
				        mdef, vg_idx, num_verts_dst, loops_dst, num_loops_dst,
				        polys_dst, num_polys_dst, weights[PDATA], invert_vgroup);
			}

			if (data_transfer_layersmapping_generate(
			        &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY,
			        cddata_type, mix_mode, mix_factor, weights[PDATA],
			        num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
			{
				CustomDataTransferLayerMap *lay_mapit;

				changed = (lay_map.first != NULL);

				for (lay_mapit = lay_map.first; lay_mapit; lay_mapit = lay_mapit->next) {
					CustomData_data_transfer(&geom_map[PDATA], lay_mapit);
				}

				BLI_freelistN(&lay_map);
			}
		}

		data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed);
	}

	for (i = 0; i < DATAMAX; i++) {
		BKE_mesh_remap_free(&geom_map[i]);
		MEM_SAFE_FREE(weights[i]);
	}
	dm_src->release(dm_src);

	return changed;

#undef VDATA
#undef EDATA
#undef LDATA
#undef PDATA
#undef DATAMAX
}
Example #9
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
						DerivedMesh *derivedData,
						int UNUSED(useRenderParams),
						int UNUSED(isFinalCalc))
{
	MaskModifierData *mmd= (MaskModifierData *)md;
	DerivedMesh *dm= derivedData, *result= NULL;
	GHash *vertHash=NULL, *edgeHash, *faceHash;
	GHashIterator *hashIter;
	MDeformVert *dvert= NULL, *dv;
	int numFaces=0, numEdges=0, numVerts=0;
	int maxVerts, maxEdges, maxFaces;
	int i;
	
	/* Overview of Method:
	 *	1. Get the vertices that are in the vertexgroup of interest 
	 *	2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
	 *	3. Make a new mesh containing only the mapping data
	 */
	
	/* get original number of verts, edges, and faces */
	maxVerts= dm->getNumVerts(dm);
	maxEdges= dm->getNumEdges(dm);
	maxFaces= dm->getNumFaces(dm);
	
	/* check if we can just return the original mesh 
	 *	- must have verts and therefore verts assigned to vgroups to do anything useful
	 */
	if ( !(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
		 (maxVerts == 0) || (ob->defbase.first == NULL) )
	{
		return derivedData;
	}
	
	/* if mode is to use selected armature bones, aggregate the bone groups */
	if (mmd->mode == MOD_MASK_MODE_ARM) /* --- using selected bones --- */
	{
		GHash *vgroupHash;
		Object *oba= mmd->ob_arm;
		bPoseChannel *pchan;
		bDeformGroup *def;
		char *bone_select_array;
		int bone_select_tot= 0;
		
		/* check that there is armature object with bones to use, otherwise return original mesh */
		if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first))
			return derivedData;

		bone_select_array= MEM_mallocN(BLI_countlist(&ob->defbase) * sizeof(char), "mask array");

		for (i = 0, def = ob->defbase.first; def; def = def->next, i++)
		{
			if (((pchan= get_pose_channel(oba->pose, def->name)) && pchan->bone && (pchan->bone->flag & BONE_SELECTED)))
			{
				bone_select_array[i]= TRUE;
				bone_select_tot++;
			}
			else {
				bone_select_array[i]= FALSE;
			}
		}

		/* hashes for finding mapping of:
		 * 	- vgroups to indices -> vgroupHash  (string, int)
		 *	- bones to vgroup indices -> boneHash (index of vgroup, dummy)
		 */
		vgroupHash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh");
		
		/* build mapping of names of vertex groups to indices */
		for (i = 0, def = ob->defbase.first; def; def = def->next, i++) 
			BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i));
		
		/* if no bones selected, free hashes and return original mesh */
		if (bone_select_tot == 0)
		{
			BLI_ghash_free(vgroupHash, NULL, NULL);
			MEM_freeN(bone_select_array);
			
			return derivedData;
		}
		
		/* repeat the previous check, but for dverts */
		dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT);
		if (dvert == NULL)
		{
			BLI_ghash_free(vgroupHash, NULL, NULL);
			MEM_freeN(bone_select_array);
			
			return derivedData;
		}
		
		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh");
		
		/* add vertices which exist in vertexgroups into vertHash for filtering */
		for (i= 0, dv= dvert; i < maxVerts; i++, dv++)
		{
			MDeformWeight *dw= dv->dw;
			int j;

			for (j= dv->totweight; j > 0; j--, dw++)
			{
				if (bone_select_array[dw->def_nr])
				{
					if(dw->weight != 0.0f) {
						break;
					}
				}
			}
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (dw) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!dw) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
		
		/* free temp hashes */
		BLI_ghash_free(vgroupHash, NULL, NULL);
		MEM_freeN(bone_select_array);
	}
	else		/* --- Using Nominated VertexGroup only --- */ 
	{
		int defgrp_index = defgroup_name_index(ob, mmd->vgroup);
		
		/* get dverts */
		if (defgrp_index >= 0)
			dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
			
		/* if no vgroup (i.e. dverts) found, return the initial mesh */
		if ((defgrp_index < 0) || (dvert == NULL))
			return dm;
			
		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert2 bh");
		
		/* add vertices which exist in vertexgroup into ghash for filtering */
		for (i= 0, dv= dvert; i < maxVerts; i++, dv++)
		{
			const int weight_set= defvert_find_weight(dv, defgrp_index) != 0.0f;
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (weight_set) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!weight_set) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
	}
	
	/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
	edgeHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh");
	faceHash= BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh");
	
	/* loop over edges and faces, and do the same thing to 
	 * ensure that they only reference existing verts 
	 */
	for (i = 0; i < maxEdges; i++) 
	{
		MEdge me;
		dm->getEdge(dm, i, &me);
		
		/* only add if both verts will be in new mesh */
		if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) &&
			 BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)) )
		{
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges));
			numEdges++;
		}
	}
	for (i = 0; i < maxFaces; i++) 
	{
		MFace mf;
		dm->getFace(dm, i, &mf);
		
		/* all verts must be available */
		if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) &&
			 BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2)) &&
			 BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3)) &&
			(mf.v4==0 || BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) )
		{
			BLI_ghash_insert(faceHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numFaces));
			numFaces++;
		}
	}
	
	
	/* now we know the number of verts, edges and faces, 
	 * we can create the new (reduced) mesh
	 */
	result = CDDM_from_template(dm, numVerts, numEdges, numFaces);
	
	
	/* using ghash-iterators, map data into new mesh */
		/* vertices */
	for ( hashIter = BLI_ghashIterator_new(vertHash);
		  !BLI_ghashIterator_isDone(hashIter);
		  BLI_ghashIterator_step(hashIter) ) 
	{
		MVert source;
		MVert *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getVert(dm, oldIndex, &source);
		dest = CDDM_get_vert(result, newIndex);
		
		DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
		
		/* edges */
	for ( hashIter = BLI_ghashIterator_new(edgeHash);
		  !BLI_ghashIterator_isDone(hashIter);
		  BLI_ghashIterator_step(hashIter) ) 
	{
		MEdge source;
		MEdge *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getEdge(dm, oldIndex, &source);
		dest = CDDM_get_edge(result, newIndex);
		
		source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
		source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
		
		DM_copy_edge_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
	
		/* faces */
	for ( hashIter = BLI_ghashIterator_new(faceHash);
		  !BLI_ghashIterator_isDone(hashIter);
		  BLI_ghashIterator_step(hashIter) ) 
	{
		MFace source;
		MFace *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		int orig_v4;
		
		dm->getFace(dm, oldIndex, &source);
		dest = CDDM_get_face(result, newIndex);
		
		orig_v4 = source.v4;
		
		source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
		source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
		source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3)));
		if (source.v4)
		   source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4)));
		
		DM_copy_face_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
		
		test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3));
	}
	BLI_ghashIterator_free(hashIter);
	
	/* recalculate normals */
	CDDM_calc_normals(result);
	
	/* free hashes */
	BLI_ghash_free(vertHash, NULL, NULL);
	BLI_ghash_free(edgeHash, NULL, NULL);
	BLI_ghash_free(faceHash, NULL, NULL);
	
	/* return the new mesh */
	return result;
}
Example #10
0
static DerivedMesh *applyModifier(
        ModifierData *md, Object *ob,
        DerivedMesh *dm,
        ModifierApplyFlag UNUSED(flag))
{
	MaskModifierData *mmd = (MaskModifierData *)md;
	const bool found_test = (mmd->flag & MOD_MASK_INV) == 0;
	DerivedMesh *result = NULL;
	GHash *vertHash = NULL, *edgeHash, *polyHash;
	GHashIterator gh_iter;
	MDeformVert *dvert, *dv;
	int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0;
	int maxVerts, maxEdges, maxPolys;
	int i;

	const MVert *mvert_src;
	const MEdge *medge_src;
	const MPoly *mpoly_src;
	const MLoop *mloop_src;

	MPoly *mpoly_dst;
	MLoop *mloop_dst;
	MEdge *medge_dst;
	MVert *mvert_dst;

	int *loop_mapping;

	dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
	if (dvert == NULL) {
		return found_test ? CDDM_from_template(dm, 0, 0, 0, 0, 0) : dm;
	}

	/* Overview of Method:
	 *	1. Get the vertices that are in the vertexgroup of interest
	 *	2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
	 *	3. Make a new mesh containing only the mapping data
	 */

	/* get original number of verts, edges, and faces */
	maxVerts = dm->getNumVerts(dm);
	maxEdges = dm->getNumEdges(dm);
	maxPolys = dm->getNumPolys(dm);

	/* check if we can just return the original mesh
	 *	- must have verts and therefore verts assigned to vgroups to do anything useful
	 */
	if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
	    (maxVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
	{
		return dm;
	}

	/* if mode is to use selected armature bones, aggregate the bone groups */
	if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */
		Object *oba = mmd->ob_arm;
		bPoseChannel *pchan;
		bDeformGroup *def;
		bool *bone_select_array;
		int bone_select_tot = 0;
		const int defbase_tot = BLI_listbase_count(&ob->defbase);

		/* check that there is armature object with bones to use, otherwise return original mesh */
		if (ELEM(NULL, oba, oba->pose, ob->defbase.first))
			return dm;

		/* determine whether each vertexgroup is associated with a selected bone or not
		 * - each cell is a boolean saying whether bone corresponding to the ith group is selected
		 * - groups that don't match a bone are treated as not existing (along with the corresponding ungrouped verts)
		 */
		bone_select_array = MEM_malloc_arrayN((size_t)defbase_tot, sizeof(char), "mask array");

		for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
			pchan = BKE_pose_channel_find_name(oba->pose, def->name);
			if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
				bone_select_array[i] = true;
				bone_select_tot++;
			}
			else {
				bone_select_array[i] = false;
			}
		}

		/* verthash gives mapping from original vertex indices to the new indices (including selected matches only)
		 * key = oldindex, value = newindex
		 */
		vertHash = BLI_ghash_int_new_ex("mask vert gh", (unsigned int)maxVerts);

		/* add vertices which exist in vertexgroups into vertHash for filtering
		 * - dv = for each vertex, what vertexgroups does it belong to
		 * - dw = weight that vertex was assigned to a vertexgroup it belongs to
		 */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			MDeformWeight *dw = dv->dw;
			bool found = false;
			int j;

			/* check the groups that vertex is assigned to, and see if it was any use */
			for (j = 0; j < dv->totweight; j++, dw++) {
				if (dw->def_nr < defbase_tot) {
					if (bone_select_array[dw->def_nr]) {
						if (dw->weight != 0.0f) {
							found = true;
							break;
						}
					}
				}
			}

			if (found_test != found) {
				continue;
			}

			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}

		/* free temp hashes */
		MEM_freeN(bone_select_array);
	}
	else {  /* --- Using Nominated VertexGroup only --- */
		int defgrp_index = defgroup_name_index(ob, mmd->vgroup);

		/* if no vgroup (i.e. dverts) found, return the initial mesh */
		if (defgrp_index == -1)
			return dm;

		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash = BLI_ghash_int_new_ex("mask vert2 bh", (unsigned int)maxVerts);

		/* add vertices which exist in vertexgroup into ghash for filtering */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			const bool found = defvert_find_weight(dv, defgrp_index) != 0.0f;
			if (found_test != found) {
				continue;
			}

			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
	}

	/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
	edgeHash = BLI_ghash_int_new_ex("mask ed2 gh", (unsigned int)maxEdges);
	polyHash = BLI_ghash_int_new_ex("mask fa2 gh", (unsigned int)maxPolys);

	mvert_src = dm->getVertArray(dm);
	medge_src = dm->getEdgeArray(dm);
	mpoly_src = dm->getPolyArray(dm);
	mloop_src = dm->getLoopArray(dm);

	/* overalloc, assume all polys are seen */
	loop_mapping = MEM_malloc_arrayN((size_t)maxPolys, sizeof(int), "mask loopmap");

	/* loop over edges and faces, and do the same thing to
	 * ensure that they only reference existing verts
	 */
	for (i = 0; i < maxEdges; i++) {
		const MEdge *me = &medge_src[i];

		/* only add if both verts will be in new mesh */
		if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v1)) &&
		    BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me->v2)))
		{
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges));
			numEdges++;
		}
	}
	for (i = 0; i < maxPolys; i++) {
		const MPoly *mp_src = &mpoly_src[i];
		const MLoop *ml_src = &mloop_src[mp_src->loopstart];
		bool ok = true;
		int j;

		for (j = 0; j < mp_src->totloop; j++, ml_src++) {
			if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml_src->v))) {
				ok = false;
				break;
			}
		}

		/* all verts must be available */
		if (ok) {
			BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys));
			loop_mapping[numPolys] = numLoops;
			numPolys++;
			numLoops += mp_src->totloop;
		}
	}


	/* now we know the number of verts, edges and faces,
	 * we can create the new (reduced) mesh
	 */
	result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys);

	mpoly_dst = CDDM_get_polys(result);
	mloop_dst = CDDM_get_loops(result);
	medge_dst = CDDM_get_edges(result);
	mvert_dst = CDDM_get_verts(result);

	/* using ghash-iterators, map data into new mesh */
	/* vertices */
	GHASH_ITER (gh_iter, vertHash) {
		const MVert *v_src;
		MVert *v_dst;
		const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
		const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));

		v_src = &mvert_src[i_src];
		v_dst = &mvert_dst[i_dst];

		*v_dst = *v_src;
		DM_copy_vert_data(dm, result, i_src, i_dst, 1);
	}

	/* edges */
	GHASH_ITER (gh_iter, edgeHash) {
		const MEdge *e_src;
		MEdge *e_dst;
		const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
		const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));

		e_src = &medge_src[i_src];
		e_dst = &medge_dst[i_dst];

		DM_copy_edge_data(dm, result, i_src, i_dst, 1);
		*e_dst = *e_src;
		e_dst->v1 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v1)));
		e_dst->v2 = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(e_src->v2)));
	}

	/* faces */
	GHASH_ITER (gh_iter, polyHash) {
		const int i_src = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
		const int i_dst = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
		const MPoly *mp_src = &mpoly_src[i_src];
		MPoly *mp_dst = &mpoly_dst[i_dst];
		const int i_ml_src = mp_src->loopstart;
		const int i_ml_dst = loop_mapping[i_dst];
		const MLoop *ml_src = &mloop_src[i_ml_src];
		MLoop *ml_dst = &mloop_dst[i_ml_dst];

		DM_copy_poly_data(dm, result, i_src, i_dst, 1);
		DM_copy_loop_data(dm, result, i_ml_src, i_ml_dst, mp_src->totloop);

		*mp_dst = *mp_src;
		mp_dst->loopstart = i_ml_dst;
		for (i = 0; i < mp_src->totloop; i++) {
			ml_dst[i].v = GET_UINT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_UINT_IN_POINTER(ml_src[i].v)));
			ml_dst[i].e = GET_UINT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_UINT_IN_POINTER(ml_src[i].e)));
		}
	}

	MEM_freeN(loop_mapping);

	/* why is this needed? - campbell */
	/* recalculate normals */
	result->dirty |= DM_DIRTY_NORMALS;

	/* free hashes */
	BLI_ghash_free(vertHash, NULL, NULL);
	BLI_ghash_free(edgeHash, NULL, NULL);
	BLI_ghash_free(polyHash, NULL, NULL);

	/* return the new mesh */
	return result;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
	DerivedMesh *dm = derivedData;
	MDeformVert *dvert = NULL;
	MDeformWeight **dw, **tdw;
	int numVerts;
	float (*v_cos)[3] = NULL; /* The vertices coordinates. */
	Object *obr = NULL; /* Our target object. */
	int defgrp_index;
	float *tw = NULL;
	float *org_w = NULL;
	float *new_w = NULL;
	int *tidx, *indices = NULL;
	int numIdx = 0;
	int i;
	/* Flags. */
#if 0
	const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
#endif

#ifdef USE_TIMEIT
	TIMEIT_START(perf);
#endif

	/* Get number of verts. */
	numVerts = dm->getNumVerts(dm);

	/* Check if we can just return the original mesh.
	 * Must have verts and therefore verts assigned to vgroups to do anything useful!
	 */
	if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
		return dm;

	/* Get our target object. */
	obr = wmd->proximity_ob_target;
	if (obr == NULL)
		return dm;

	/* Get vgroup idx from its name. */
	defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
	if (defgrp_index == -1)
		return dm;

	dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
	/* If no vertices were ever added to an object's vgroup, dvert might be NULL.
	 * As this modifier never add vertices to vgroup, just return. */
	if (!dvert)
		return dm;

	/* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight.
	 */
	tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGProximity Modifier, tidx");
	tw = MEM_mallocN(sizeof(float) * numVerts, "WeightVGProximity Modifier, tw");
	tdw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGProximity Modifier, tdw");
	for (i = 0; i < numVerts; i++) {
		MDeformWeight *_dw = defvert_find_index(&dvert[i], defgrp_index);
		if (_dw) {
			tidx[numIdx] = i;
			tw[numIdx] = _dw->weight;
			tdw[numIdx++] = _dw;
		}
	}
	/* If no vertices found, return org data! */
	if (numIdx == 0) {
		MEM_freeN(tidx);
		MEM_freeN(tw);
		MEM_freeN(tdw);
		return dm;
	}
	if (numIdx != numVerts) {
		indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGProximity Modifier, indices");
		memcpy(indices, tidx, sizeof(int) * numIdx);
		org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, org_w");
		memcpy(org_w, tw, sizeof(float) * numIdx);
		dw = MEM_mallocN(sizeof(MDeformWeight *) * numIdx, "WeightVGProximity Modifier, dw");
		memcpy(dw, tdw, sizeof(MDeformWeight *) * numIdx);
		MEM_freeN(tw);
		MEM_freeN(tdw);
	}
	else {
		org_w = tw;
		dw = tdw;
	}
	new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGProximity Modifier, new_w");
	MEM_freeN(tidx);

	/* Get our vertex coordinates. */
	v_cos = MEM_mallocN(sizeof(float[3]) * numIdx, "WeightVGProximity Modifier, v_cos");
	if (numIdx != numVerts) {
		/* XXX In some situations, this code can be up to about 50 times more performant
		 *     than simply using getVertCo for each affected vertex...
		 */
		float (*tv_cos)[3] = MEM_mallocN(sizeof(float[3]) * numVerts, "WeightVGProximity Modifier, tv_cos");
		dm->getVertCos(dm, tv_cos);
		for (i = 0; i < numIdx; i++)
			copy_v3_v3(v_cos[i], tv_cos[indices[i]]);
		MEM_freeN(tv_cos);
	}
	else
		dm->getVertCos(dm, v_cos);

	/* Compute wanted distances. */
	if (wmd->proximity_mode == MOD_WVG_PROXIMITY_OBJECT) {
		const float dist = get_ob2ob_distance(ob, obr);
		for (i = 0; i < numIdx; i++)
			new_w[i] = dist;
	}
	else if (wmd->proximity_mode == MOD_WVG_PROXIMITY_GEOMETRY) {
		const short use_trgt_verts = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_VERTS);
		const short use_trgt_edges = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_EDGES);
		const short use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES);

		if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
			DerivedMesh *target_dm = obr->derivedFinal;
			bool free_target_dm = false;
			if (!target_dm) {
				if (ELEM(obr->type, OB_CURVE, OB_SURF, OB_FONT))
					target_dm = CDDM_from_curve(obr);
				else if (obr->type == OB_MESH) {
					Mesh *me = (Mesh *)obr->data;
					if (me->edit_btmesh)
						target_dm = CDDM_from_editbmesh(me->edit_btmesh, false, false);
					else
						target_dm = CDDM_from_mesh(me);
				}
				free_target_dm = true;
			}

			/* We must check that we do have a valid target_dm! */
			if (target_dm) {
				SpaceTransform loc2trgt;
				float *dists_v = use_trgt_verts ? MEM_mallocN(sizeof(float) * numIdx, "dists_v") : NULL;
				float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL;
				float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL;

				BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr);
				get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
				                       target_dm, &loc2trgt);
				for (i = 0; i < numIdx; i++) {
					new_w[i] = dists_v ? dists_v[i] : FLT_MAX;
					if (dists_e)
						new_w[i] = min_ff(dists_e[i], new_w[i]);
					if (dists_f)
						new_w[i] = min_ff(dists_f[i], new_w[i]);
				}
				if (free_target_dm) target_dm->release(target_dm);
				if (dists_v) MEM_freeN(dists_v);
				if (dists_e) MEM_freeN(dists_e);
				if (dists_f) MEM_freeN(dists_f);
			}
			/* Else, fall back to default obj2vert behavior. */
			else {
				get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
			}
		}
		else {
			get_vert2ob_distance(numIdx, v_cos, new_w, ob, obr);
		}
	}

	/* Map distances to weights. */
	do_map(ob, new_w, numIdx, wmd->min_dist, wmd->max_dist, wmd->falloff_type);

	/* Do masking. */
	weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant,
	                 wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
	                 wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
	                 wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);

	/* Update vgroup. Note we never add nor remove vertices from vgroup here. */
	weightvg_update_vg(dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f);

	/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
	if (do_prev)
		DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices);
#endif

	/* Freeing stuff. */
	MEM_freeN(org_w);
	MEM_freeN(new_w);
	MEM_freeN(dw);
	if (indices)
		MEM_freeN(indices);
	MEM_freeN(v_cos);

#ifdef USE_TIMEIT
	TIMEIT_END(perf);
#endif

	/* Return the vgroup-modified mesh. */
	return dm;
}
Example #12
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	MaskModifierData *mmd = (MaskModifierData *)md;
	DerivedMesh *dm = derivedData, *result = NULL;
	GHash *vertHash = NULL, *edgeHash, *polyHash;
	GHashIterator *hashIter;
	MDeformVert *dvert = NULL, *dv;
	int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0;
	int maxVerts, maxEdges, maxPolys;
	int i;

	MPoly *mpoly;
	MLoop *mloop;

	MPoly *mpoly_new;
	MLoop *mloop_new;
	MEdge *medge_new;
	MVert *mvert_new;


	int *loop_mapping;

	/* Overview of Method:
	 *	1. Get the vertices that are in the vertexgroup of interest 
	 *	2. Filter out unwanted geometry (i.e. not in vertexgroup), by populating mappings with new vs old indices
	 *	3. Make a new mesh containing only the mapping data
	 */
	
	/* get original number of verts, edges, and faces */
	maxVerts = dm->getNumVerts(dm);
	maxEdges = dm->getNumEdges(dm);
	maxPolys = dm->getNumPolys(dm);
	
	/* check if we can just return the original mesh 
	 *	- must have verts and therefore verts assigned to vgroups to do anything useful
	 */
	if (!(ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP)) ||
	    (maxVerts == 0) || (ob->defbase.first == NULL) )
	{
		return derivedData;
	}
	
	/* if mode is to use selected armature bones, aggregate the bone groups */
	if (mmd->mode == MOD_MASK_MODE_ARM) { /* --- using selected bones --- */
		GHash *vgroupHash;
		Object *oba = mmd->ob_arm;
		bPoseChannel *pchan;
		bDeformGroup *def;
		char *bone_select_array;
		int bone_select_tot = 0;
		const int defbase_tot = BLI_countlist(&ob->defbase);
		
		/* check that there is armature object with bones to use, otherwise return original mesh */
		if (ELEM3(NULL, mmd->ob_arm, mmd->ob_arm->pose, ob->defbase.first))
			return derivedData;
		
		bone_select_array = MEM_mallocN(defbase_tot * sizeof(char), "mask array");
		
		for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
			pchan = BKE_pose_channel_find_name(oba->pose, def->name);
			if (pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
				bone_select_array[i] = TRUE;
				bone_select_tot++;
			}
			else {
				bone_select_array[i] = FALSE;
			}
		}

		/* hashes for finding mapping of:
		 * - vgroups to indices -> vgroupHash  (string, int)
		 * - bones to vgroup indices -> boneHash (index of vgroup, dummy)
		 */
		vgroupHash = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "mask vgroup gh");
		
		/* build mapping of names of vertex groups to indices */
		for (i = 0, def = ob->defbase.first; def; def = def->next, i++) 
			BLI_ghash_insert(vgroupHash, def->name, SET_INT_IN_POINTER(i));
		
		/* if no bones selected, free hashes and return original mesh */
		if (bone_select_tot == 0) {
			BLI_ghash_free(vgroupHash, NULL, NULL);
			MEM_freeN(bone_select_array);
			
			return derivedData;
		}
		
		/* repeat the previous check, but for dverts */
		dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
		if (dvert == NULL) {
			BLI_ghash_free(vgroupHash, NULL, NULL);
			MEM_freeN(bone_select_array);
			
			return derivedData;
		}
		
		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert gh");
		
		/* add vertices which exist in vertexgroups into vertHash for filtering */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			MDeformWeight *dw = dv->dw;
			int j;
			
			for (j = dv->totweight; j > 0; j--, dw++) {
				if (dw->def_nr < defbase_tot) {
					if (bone_select_array[dw->def_nr]) {
						if (dw->weight != 0.0f) {
							break;
						}
					}
				}
			}
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (dw) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!dw) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
		
		/* free temp hashes */
		BLI_ghash_free(vgroupHash, NULL, NULL);
		MEM_freeN(bone_select_array);
	}
	else {  /* --- Using Nominated VertexGroup only --- */
		int defgrp_index = defgroup_name_index(ob, mmd->vgroup);
		
		/* get dverts */
		if (defgrp_index >= 0)
			dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
			
		/* if no vgroup (i.e. dverts) found, return the initial mesh */
		if ((defgrp_index < 0) || (dvert == NULL))
			return dm;
			
		/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
		vertHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask vert2 bh");
		
		/* add vertices which exist in vertexgroup into ghash for filtering */
		for (i = 0, dv = dvert; i < maxVerts; i++, dv++) {
			const int weight_set = defvert_find_weight(dv, defgrp_index) != 0.0f;
			
			/* check if include vert in vertHash */
			if (mmd->flag & MOD_MASK_INV) {
				/* if this vert is in the vgroup, don't include it in vertHash */
				if (weight_set) continue;
			}
			else {
				/* if this vert isn't in the vgroup, don't include it in vertHash */
				if (!weight_set) continue;
			}
			
			/* add to ghash for verts (numVerts acts as counter for mapping) */
			BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numVerts));
			numVerts++;
		}
	}

	/* hashes for quickly providing a mapping from old to new - use key=oldindex, value=newindex */
	edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask ed2 gh");
	polyHash = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp, "mask fa2 gh");
	
	mpoly = dm->getPolyArray(dm);
	mloop = dm->getLoopArray(dm);

	loop_mapping = MEM_callocN(sizeof(int) * maxPolys, "mask loopmap"); /* overalloc, assume all polys are seen */

	/* loop over edges and faces, and do the same thing to 
	 * ensure that they only reference existing verts 
	 */
	for (i = 0; i < maxEdges; i++)  {
		MEdge me;
		dm->getEdge(dm, i, &me);
		
		/* only add if both verts will be in new mesh */
		if (BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) &&
		    BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2)))
		{
			BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numEdges));
			numEdges++;
		}
	}
	for (i = 0; i < maxPolys; i++) {
		MPoly *mp = &mpoly[i];
		MLoop *ml = mloop + mp->loopstart;
		int ok = TRUE;
		int j;
		
		for (j = 0; j < mp->totloop; j++, ml++) {
			if (!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(ml->v))) {
				ok = FALSE;
				break;
			}
		}
		
		/* all verts must be available */
		if (ok) {
			BLI_ghash_insert(polyHash, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(numPolys));
			loop_mapping[numPolys] = numLoops;
			numPolys++;
			numLoops += mp->totloop;
		}
	}
	
	
	/* now we know the number of verts, edges and faces, 
	 * we can create the new (reduced) mesh
	 */
	result = CDDM_from_template(dm, numVerts, numEdges, 0, numLoops, numPolys);
	
	mpoly_new = CDDM_get_polys(result);
	mloop_new = CDDM_get_loops(result);
	medge_new = CDDM_get_edges(result);
	mvert_new = CDDM_get_verts(result);
	
	/* using ghash-iterators, map data into new mesh */
	/* vertices */
	for (hashIter = BLI_ghashIterator_new(vertHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter) )
	{
		MVert source;
		MVert *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getVert(dm, oldIndex, &source);
		dest = &mvert_new[newIndex];
		
		DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
		
	/* edges */
	for (hashIter = BLI_ghashIterator_new(edgeHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter))
	{
		MEdge source;
		MEdge *dest;
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		
		dm->getEdge(dm, oldIndex, &source);
		dest = &medge_new[newIndex];
		
		source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1)));
		source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2)));
		
		DM_copy_edge_data(dm, result, oldIndex, newIndex, 1);
		*dest = source;
	}
	BLI_ghashIterator_free(hashIter);
	
	/* faces */
	for (hashIter = BLI_ghashIterator_new(polyHash);
	     !BLI_ghashIterator_isDone(hashIter);
	     BLI_ghashIterator_step(hashIter) )
	{
		int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
		int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
		MPoly *source = &mpoly[oldIndex];
		MPoly *dest = &mpoly_new[newIndex];
		int oldLoopIndex = source->loopstart;
		int newLoopIndex = loop_mapping[newIndex];
		MLoop *source_loop = &mloop[oldLoopIndex];
		MLoop *dest_loop = &mloop_new[newLoopIndex];
		
		DM_copy_poly_data(dm, result, oldIndex, newIndex, 1);
		DM_copy_loop_data(dm, result, oldLoopIndex, newLoopIndex, source->totloop);

		*dest = *source;
		dest->loopstart = newLoopIndex;
		for (i = 0; i < source->totloop; i++) {
			dest_loop[i].v = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source_loop[i].v)));
			dest_loop[i].e = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(source_loop[i].e)));
		}
	}

	BLI_ghashIterator_free(hashIter);

	MEM_freeN(loop_mapping);

	/* why is this needed? - campbell */
	/* recalculate normals */
	CDDM_calc_normals(result);
	
	/* free hashes */
	BLI_ghash_free(vertHash, NULL, NULL);
	BLI_ghash_free(edgeHash, NULL, NULL);
	BLI_ghash_free(polyHash, NULL, NULL);

	/* return the new mesh */
	return result;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
	DerivedMesh *dm = derivedData;
	MDeformVert *dvert = NULL;
	MDeformWeight **dw = NULL;
	float *org_w; /* Array original weights. */
	float *new_w; /* Array new weights. */
	int numVerts;
	int defgrp_index;
	int i;
	/* Flags. */
	const bool do_add  = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0;
	const bool do_rem  = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0;
	/* Only do weight-preview in Object, Sculpt and Pose modes! */
#if 0
	const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
#endif

	/* Get number of verts. */
	numVerts = dm->getNumVerts(dm);

	/* Check if we can just return the original mesh.
	 * Must have verts and therefore verts assigned to vgroups to do anything useful!
	 */
	if ((numVerts == 0) || BLI_listbase_is_empty(&ob->defbase))
		return dm;

	/* Get vgroup idx from its name. */
	defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
	if (defgrp_index == -1)
		return dm;

	dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
	/* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
	if (!dvert) {
		/* If this modifier is not allowed to add vertices, just return. */
		if (!do_add)
			return dm;
		/* Else, add a valid data layer! */
		dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
		                                   NULL, numVerts, wmd->defgrp_name);
		/* Ultimate security check. */
		if (!dvert)
			return dm;
	}

	/* Get org weights, assuming 0.0 for vertices not in given vgroup. */
	org_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, org_w");
	new_w = MEM_mallocN(sizeof(float) * numVerts, "WeightVGEdit Modifier, new_w");
	dw = MEM_mallocN(sizeof(MDeformWeight *) * numVerts, "WeightVGEdit Modifier, dw");
	for (i = 0; i < numVerts; i++) {
		dw[i] = defvert_find_index(&dvert[i], defgrp_index);
		if (dw[i]) {
			org_w[i] = new_w[i] = dw[i]->weight;
		}
		else {
			org_w[i] = new_w[i] = wmd->default_weight;
		}
	}

	/* Do mapping. */
	if (wmd->falloff_type != MOD_WVG_MAPPING_NONE) {
		RNG *rng = NULL;

		if (wmd->falloff_type == MOD_WVG_MAPPING_RANDOM)
			rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2));

		weightvg_do_map(numVerts, new_w, wmd->falloff_type, wmd->cmap_curve, rng);

		if (rng)
			BLI_rng_free(rng);
	}

	/* Do masking. */
	weightvg_do_mask(numVerts, NULL, org_w, new_w, ob, dm, wmd->mask_constant,
	                 wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
	                 wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
	                 wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);

	/* Update/add/remove from vgroup. */
	weightvg_update_vg(dvert, defgrp_index, dw, numVerts, NULL, org_w, do_add, wmd->add_threshold,
	                   do_rem, wmd->rem_threshold);

	/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
	if (do_prev)
		DM_update_weight_mcol(ob, dm, 0, org_w, 0, NULL);
#endif

	/* Freeing stuff. */
	MEM_freeN(org_w);
	MEM_freeN(new_w);
	MEM_freeN(dw);

	/* Return the vgroup-modified mesh. */
	return dm;
}
Example #14
0
static void smoothModifier_do(
				  SmoothModifierData *smd, Object *ob, DerivedMesh *dm,
	 float (*vertexCos)[3], int numVerts)
{
	MDeformVert *dvert = NULL;
	MEdge *medges = NULL;

	int i, j, numDMEdges, defgrp_index;
	unsigned char *uctmp;
	float *ftmp, fac, facm;

	ftmp = (float*)MEM_callocN(3*sizeof(float)*numVerts,
		"smoothmodifier_f");
	if (!ftmp) return;
	uctmp = (unsigned char*)MEM_callocN(sizeof(unsigned char)*numVerts,
		 "smoothmodifier_uc");
	if (!uctmp) {
		if (ftmp) MEM_freeN(ftmp);
		return;
	}

	fac = smd->fac;
	facm = 1 - fac;

	medges = dm->getEdgeArray(dm);
	numDMEdges = dm->getNumEdges(dm);

	defgrp_index = defgroup_name_index(ob, smd->defgrp_name);

	if (defgrp_index >= 0)
		dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);

	/* NOTICE: this can be optimized a little bit by moving the
	* if (dvert) out of the loop, if needed */
	for (j = 0; j < smd->repeat; j++) {
		for (i = 0; i < numDMEdges; i++) {
			float fvec[3];
			float *v1, *v2;
			unsigned int idx1, idx2;

			idx1 = medges[i].v1;
			idx2 = medges[i].v2;

			v1 = vertexCos[idx1];
			v2 = vertexCos[idx2];

			fvec[0] = (v1[0] + v2[0]) / 2.0;
			fvec[1] = (v1[1] + v2[1]) / 2.0;
			fvec[2] = (v1[2] + v2[2]) / 2.0;

			v1 = &ftmp[idx1*3];
			v2 = &ftmp[idx2*3];

			if (uctmp[idx1] < 255) {
				uctmp[idx1]++;
				add_v3_v3(v1, fvec);
			}
			if (uctmp[idx2] < 255) {
				uctmp[idx2]++;
				add_v3_v3(v2, fvec);
			}
		}

		if (dvert) {
			for (i = 0; i < numVerts; i++) {
				MDeformWeight *dw = NULL;
				float f, fm, facw, *fp, *v;
				int k;
				short flag = smd->flag;

				v = vertexCos[i];
				fp = &ftmp[i*3];

				for (k = 0; k < dvert[i].totweight; ++k) {
					if(dvert[i].dw[k].def_nr == defgrp_index) {
						dw = &dvert[i].dw[k];
						break;
					}
				}
				if (!dw) continue;

				f = fac * dw->weight;
				fm = 1.0f - f;

				/* fp is the sum of uctmp[i] verts, so must be averaged */
				facw = 0.0f;
				if (uctmp[i]) 
					facw = f / (float)uctmp[i];

				if (flag & MOD_SMOOTH_X)
					v[0] = fm * v[0] + facw * fp[0];
				if (flag & MOD_SMOOTH_Y)
					v[1] = fm * v[1] + facw * fp[1];
				if (flag & MOD_SMOOTH_Z)
					v[2] = fm * v[2] + facw * fp[2];
			}
		}
		else { /* no vertex group */
			for (i = 0; i < numVerts; i++) {
				float facw, *fp, *v;
				short flag = smd->flag;

				v = vertexCos[i];
				fp = &ftmp[i*3];

				/* fp is the sum of uctmp[i] verts, so must be averaged */
				facw = 0.0f;
				if (uctmp[i]) 
					facw = fac / (float)uctmp[i];

				if (flag & MOD_SMOOTH_X)
					v[0] = facm * v[0] + facw * fp[0];
				if (flag & MOD_SMOOTH_Y)
					v[1] = facm * v[1] + facw * fp[1];
				if (flag & MOD_SMOOTH_Z)
					v[2] = facm * v[2] + facw * fp[2];
			}

		}

		memset(ftmp, 0, 3*sizeof(float)*numVerts);
		memset(uctmp, 0, sizeof(unsigned char)*numVerts);
	}

	MEM_freeN(ftmp);
	MEM_freeN(uctmp);
}
Example #15
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                  int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
{
	WeightVGMixModifierData *wmd = (WeightVGMixModifierData*) md;
	DerivedMesh *dm = derivedData;
	MDeformVert *dvert = NULL;
	MDeformWeight **dw1, **tdw1, **dw2, **tdw2;
	int numVerts;
	int defgrp_idx, defgrp_idx2 = -1;
	float *org_w;
	float *new_w;
	int *tidx, *indices = NULL;
	int numIdx = 0;
	int i;
	/* Flags. */
#if 0
	int do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
#endif

	/* Get number of verts. */
	numVerts = dm->getNumVerts(dm);

	/* Check if we can just return the original mesh.
	 * Must have verts and therefore verts assigned to vgroups to do anything useful!
	 */
	if ((numVerts == 0) || (ob->defbase.first == NULL))
		return dm;

	/* Get vgroup idx from its name. */
	defgrp_idx = defgroup_name_index(ob, wmd->defgrp_name_a);
	if (defgrp_idx < 0)
		return dm;
	/* Get seconf vgroup idx from its name, if given. */
	if (wmd->defgrp_name_b[0] != (char)0) {
		defgrp_idx2 = defgroup_name_index(ob, wmd->defgrp_name_b);
		if (defgrp_idx2 < 0)
			return dm;
	}

	dvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MDEFORMVERT, numVerts);
	/* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
	if (!dvert) {
		/* If not affecting all vertices, just return. */
		if (wmd->mix_set != MOD_WVG_SET_ALL)
			return dm;
		/* Else, add a valid data layer! */
		dvert = CustomData_add_layer_named(&dm->vertData, CD_MDEFORMVERT, CD_CALLOC,
		                                   NULL, numVerts, wmd->defgrp_name_a);
		/* Ultimate security check. */
		if (!dvert)
			return dm;
	}
	/* Find out which vertices to work on. */
	tidx = MEM_mallocN(sizeof(int) * numVerts, "WeightVGMix Modifier, tidx");
	tdw1 = MEM_mallocN(sizeof(MDeformWeight*) * numVerts, "WeightVGMix Modifier, tdw1");
	tdw2 = MEM_mallocN(sizeof(MDeformWeight*) * numVerts, "WeightVGMix Modifier, tdw2");
	switch (wmd->mix_set) {
	case MOD_WVG_SET_A:
		/* All vertices in first vgroup. */
		for (i = 0; i < numVerts; i++) {
			MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_idx);
			if (dw) {
				tdw1[numIdx] = dw;
				tdw2[numIdx] = defvert_find_index(&dvert[i], defgrp_idx2);
				tidx[numIdx++] = i;
			}
		}
		break;
	case MOD_WVG_SET_B:
		/* All vertices in second vgroup. */
		for (i = 0; i < numVerts; i++) {
			MDeformWeight *dw = defvert_find_index(&dvert[i], defgrp_idx2);
			if (dw) {
				tdw1[numIdx] = defvert_find_index(&dvert[i], defgrp_idx);
				tdw2[numIdx] = dw;
				tidx[numIdx++] = i;
			}
		}
		break;
	case MOD_WVG_SET_OR:
		/* All vertices in one vgroup or the other. */
		for (i = 0; i < numVerts; i++) {
			MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_idx);
			MDeformWeight *bdw = defvert_find_index(&dvert[i], defgrp_idx2);
			if (adw || bdw) {
				tdw1[numIdx] = adw;
				tdw2[numIdx] = bdw;
				tidx[numIdx++] = i;
			}
		}
		break;
	case MOD_WVG_SET_AND:
		/* All vertices in both vgroups. */
		for (i = 0; i < numVerts; i++) {
			MDeformWeight *adw = defvert_find_index(&dvert[i], defgrp_idx);
			MDeformWeight *bdw = defvert_find_index(&dvert[i], defgrp_idx2);
			if (adw && bdw) {
				tdw1[numIdx] = adw;
				tdw2[numIdx] = bdw;
				tidx[numIdx++] = i;
			}
		}
		break;
	case MOD_WVG_SET_ALL:
	default:
		/* Use all vertices. */
		for (i = 0; i < numVerts; i++) {
			tdw1[i] = defvert_find_index(&dvert[i], defgrp_idx);
			tdw2[i] = defvert_find_index(&dvert[i], defgrp_idx2);
		}
		numIdx = -1;
		break;
	}
	if (numIdx == 0) {
		/* Use no vertices! Hence, return org data. */
		MEM_freeN(tdw1);
		MEM_freeN(tdw2);
		MEM_freeN(tidx);
		return dm;
	}
	if (numIdx != -1) {
		indices = MEM_mallocN(sizeof(int) * numIdx, "WeightVGMix Modifier, indices");
		memcpy(indices, tidx, sizeof(int) * numIdx);
		dw1 = MEM_mallocN(sizeof(MDeformWeight*) * numIdx, "WeightVGMix Modifier, dw1");
		memcpy(dw1, tdw1, sizeof(MDeformWeight*) * numIdx);
		MEM_freeN(tdw1);
		dw2 = MEM_mallocN(sizeof(MDeformWeight*) * numIdx, "WeightVGMix Modifier, dw2");
		memcpy(dw2, tdw2, sizeof(MDeformWeight*) * numIdx);
		MEM_freeN(tdw2);
	}
	else {
		/* Use all vertices. */
		numIdx = numVerts;
		/* Just copy MDeformWeight pointers arrays, they will be freed at the end. */
		dw1 = tdw1;
		dw2 = tdw2;
	}
	MEM_freeN(tidx);

	org_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, org_w");
	new_w = MEM_mallocN(sizeof(float) * numIdx, "WeightVGMix Modifier, new_w");

	/* Mix weights. */
	for (i = 0; i < numIdx; i++) {
		float weight2 = 0.0;
		org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
		weight2  = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;

		new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
	}

	/* Do masking. */
	weightvg_do_mask(numIdx, indices, org_w, new_w, ob, dm, wmd->mask_constant,
	                 wmd->mask_defgrp_name, wmd->modifier.scene, wmd->mask_texture,
	                 wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
	                 wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);

	/* Update (add to) vgroup.
	 * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
	 */
	weightvg_update_vg(dvert, defgrp_idx, dw1, numIdx, indices, org_w, TRUE, -FLT_MAX, FALSE, 0.0f);

	/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
	if (do_prev)
		DM_update_weight_mcol(ob, dm, 0, org_w, numIdx, indices);
#endif

	/* Freeing stuff. */
	MEM_freeN(org_w);
	MEM_freeN(new_w);
	MEM_freeN(dw1);
	MEM_freeN(dw2);

	if (indices)
		MEM_freeN(indices);

	/* Return the vgroup-modified mesh. */
	return dm;
}
Example #16
0
/* Main shrinkwrap function */
void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{

	DerivedMesh *ss_mesh	= NULL;
	ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;

	//remove loop dependencies on derived meshs (TODO should this be done elsewhere?)
	if (smd->target == ob) smd->target = NULL;
	if (smd->auxTarget == ob) smd->auxTarget = NULL;


	//Configure Shrinkwrap calc data
	calc.smd = smd;
	calc.ob = ob;
	calc.numVerts = numVerts;
	calc.vertexCos = vertexCos;

	//DeformVertex
	calc.vgroup = defgroup_name_index(calc.ob, calc.smd->vgroup_name);
	if (dm) {
		calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
	}
	else if (calc.ob->type == OB_LATTICE) {
		calc.dvert = BKE_lattice_deform_verts_get(calc.ob);
	}


	if (smd->target) {
		calc.target = object_get_derived_final(smd->target);

		//TODO there might be several "bugs" on non-uniform scales matrixs
		//because it will no longer be nearest surface, not sphere projection
		//because space has been deformed
		space_transform_setup(&calc.local2target, ob, smd->target);

		//TODO: smd->keepDist is in global units.. must change to local
		calc.keepDist = smd->keepDist;
	}



	calc.vgroup = defgroup_name_index(calc.ob, smd->vgroup_name);

	if (dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
		//Setup arrays to get vertexs positions, normals and deform weights
		calc.vert   = dm->getVertDataArray(dm, CD_MVERT);
		calc.dvert  = dm->getVertDataArray(dm, CD_MDEFORMVERT);

		//Using vertexs positions/normals as if a subsurface was applied 
		if (smd->subsurfLevels) {
			SubsurfModifierData ssmd= {{NULL}};
			ssmd.subdivType	= ME_CC_SUBSURF;		//catmull clark
			ssmd.levels		= smd->subsurfLevels;	//levels

			ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, FALSE, NULL, 0, 0, (ob->mode & OB_MODE_EDIT));

			if (ss_mesh) {
				calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT);
				if (calc.vert) {
					/* TRICKY: this code assumes subsurface will have the transformed original vertices
					 * in their original order at the end of the vert array. */
					calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm);
				}
			}

			//Just to make sure we are not leaving any memory behind
			assert(ssmd.emCache == NULL);
			assert(ssmd.mCache == NULL);
		}
	}

	//Projecting target defined - lets work!
	if (calc.target) {
		switch (smd->shrinkType) {
			case MOD_SHRINKWRAP_NEAREST_SURFACE:
				BENCH(shrinkwrap_calc_nearest_surface_point(&calc));
			break;

			case MOD_SHRINKWRAP_PROJECT:
				BENCH(shrinkwrap_calc_normal_projection(&calc));
			break;

			case MOD_SHRINKWRAP_NEAREST_VERTEX:
				BENCH(shrinkwrap_calc_nearest_vertex(&calc));
			break;
		}
	}

	//free memory
	if (ss_mesh)
		ss_mesh->release(ss_mesh);
}