static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	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;
}
Beispiel #2
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;
}