Пример #1
0
static void rna_render_slots_active_index_set(PointerRNA *ptr, int value)
{
  Image *image = (Image *)ptr->id.data;
  int num_slots = BLI_listbase_count(&image->renderslots);
  image->render_slot = value;
  CLAMP(image->render_slot, 0, num_slots - 1);
}
Пример #2
0
static void rna_render_slots_active_index_range(
    PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
{
  Image *image = (Image *)ptr->id.data;
  *min = 0;
  *max = max_ii(0, BLI_listbase_count(&image->renderslots) - 1);
}
void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par,
                                  const int mode, const bool mirror)
{
	/* Lets try to create some vertex groups 
	 * based on the bones of the parent armature.
	 */
	bArmature *arm = par->data;

	if (mode == ARM_GROUPS_NAME) {
		const int defbase_tot = BLI_listbase_count(&ob->defbase);
		int defbase_add;
		/* Traverse the bone list, trying to create empty vertex 
		 * groups corresponding to the bone.
		 */
		defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);

		if (defbase_add) {
			/* its possible there are DWeight's outside the range of the current
			 * objects deform groups, in this case the new groups wont be empty [#33889] */
			ED_vgroup_data_clamp_range(ob->data, defbase_tot);
		}
	}
	else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
		/* Traverse the bone list, trying to create vertex groups 
		 * that are populated with the vertices for which the
		 * bone is closest.
		 */
		add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
	}
}
Пример #4
0
/* cache init */
static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
{
  bGPdata *gpd = (bGPdata *)ob->data;

  GpencilBatchCache *cache = gpencil_batch_get_element(ob);

  if (!cache) {
    cache = MEM_callocN(sizeof(*cache), __func__);
    ob->runtime.gpencil_cache = cache;
  }
  else {
    memset(cache, 0, sizeof(*cache));
  }

  cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);

  cache->is_dirty = true;

  cache->cache_frame = cfra;

  /* create array of derived frames equal to number of layers */
  cache->tot_layers = BLI_listbase_count(&gpd->layers);
  CLAMP_MIN(cache->tot_layers, 1);
  cache->derived_array = MEM_callocN(sizeof(struct bGPDframe) * cache->tot_layers, "Derived GPF");

  return cache;
}
Пример #5
0
DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
{
	DupliApplyData *apply_data = NULL;
	int num_objects = BLI_listbase_count(duplilist);
	
	if (num_objects > 0) {
		DupliObject *dob;
		int i;
		apply_data = MEM_mallocN(sizeof(DupliApplyData), "DupliObject apply data");
		apply_data->num_objects = num_objects;
		apply_data->extra = MEM_mallocN(sizeof(DupliExtraData) * (size_t) num_objects,
		                                "DupliObject apply extra data");

		for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
			/* copy obmat from duplis */
			copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);

			/* make sure derivedmesh is calculated once, before drawing */
			if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
				mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
				dob->ob->transflag |= OB_DUPLICALCDERIVED;
			}

			copy_m4_m4(dob->ob->obmat, dob->mat);
			
			/* copy layers from the main duplicator object */
			apply_data->extra[i].lay = dob->ob->lay;
			dob->ob->lay = ob->lay;
		}
	}
	return apply_data;
}
Пример #6
0
/* note, must be freed */
int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_default, int defgroup)
{
	int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);

	if (defbase_tot == 0) {
		return NULL;
	}
	else {
		bDeformGroup *dg;
		char name_flip[sizeof(dg->name)];
		int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);

		for (i = 0; i < defbase_tot; i++) {
			map[i] = use_default ? i : -1;
		}

		dg = BLI_findlink(&ob->defbase, defgroup);

		BKE_deform_flip_side_name(name_flip, dg->name, false);
		if (!STREQ(name_flip, dg->name)) {
			flip_num = defgroup_name_index(ob, name_flip);

			if (flip_num != -1) {
				map[defgroup] = flip_num;
				map[flip_num] = defgroup;
			}
		}

		return map;
	}
}
Пример #7
0
static void rna_Surface_active_point_range(PointerRNA *ptr, int *min, int *max,
                                           int *UNUSED(softmin), int *UNUSED(softmax))
{
	DynamicPaintCanvasSettings *canvas = (DynamicPaintCanvasSettings *)ptr->data;

	*min = 0;
	*max = BLI_listbase_count(&canvas->surfaces) - 1;
}
Пример #8
0
static void rna_KeyingSet_active_ksPath_index_range(PointerRNA *ptr, int *min, int *max,
        int *UNUSED(softmin), int *UNUSED(softmax))
{
    KeyingSet *ks = (KeyingSet *)ptr->data;

    *min = 0;
    *max = max_ii(0, BLI_listbase_count(&ks->paths) - 1);
}
Пример #9
0
static void rna_Action_active_pose_marker_index_range(PointerRNA *ptr, int *min, int *max,
                                                      int *UNUSED(softmin), int *UNUSED(softmax))
{
	bAction *act = (bAction *)ptr->data;

	*min = 0;
	*max = max_ii(0, BLI_listbase_count(&act->markers) - 1);
}
Пример #10
0
static void console_scrollback_limit(SpaceConsole *sc)
{
	int tot;
	
	if (U.scrollback < 32) U.scrollback = 256;  // XXX - save in user defaults
	
	for (tot = BLI_listbase_count(&sc->scrollback); tot > U.scrollback; tot--)
		console_scrollback_free(sc, sc->scrollback.first);
}
Пример #11
0
/* invoke callback which presents a list of bone-groups for the user to choose from */
static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
	Object *ob = ED_pose_object_from_context(C);
	bPose *pose;
	PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");

	uiPopupMenu *pup;
	uiLayout *layout;
	bActionGroup *grp;
	int i;

	/* only continue if there's an object, and a pose there too */
	if (ELEM(NULL, ob, ob->pose))
		return OPERATOR_CANCELLED;
	pose = ob->pose;

	/* If group index is set, try to use it! */
	if (RNA_property_is_set(op->ptr, prop)) {
		const int num_groups = BLI_listbase_count(&pose->agroups);
		const int group = RNA_property_int_get(op->ptr, prop);

		/* just use the active group index, and call the exec callback for the calling operator */
		if (group > 0 && group <= num_groups) {
			return op->type->exec(C, op);
		}
	}

	/* if there's no active group (or active is invalid), create a new menu to find it */
	if (pose->active_group <= 0) {
		/* create a new menu, and start populating it with group names */
		pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
		layout = UI_popup_menu_layout(pup);

		/* special entry - allow to create new group, then use that
		 *	(not to be used for removing though)
		 */
		if (strstr(op->idname, "assign")) {
			uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
			uiItemS(layout);
		}

		/* add entries for each group */
		for (grp = pose->agroups.first, i = 1; grp; grp = grp->next, i++)
			uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);

		/* finish building the menu, and process it (should result in calling self again) */
		UI_popup_menu_end(C, pup);

		return OPERATOR_INTERFACE;
	}
	else {
		/* just use the active group index, and call the exec callback for the calling operator */
		RNA_int_set(op->ptr, "type", pose->active_group);
		return op->type->exec(C, op);
	}
}
Пример #12
0
static void console_lb_debug__internal(ListBase *lb)
{
	ConsoleLine *cl;

	printf("%d: ", BLI_listbase_count(lb));
	for (cl = lb->first; cl; cl = cl->next)
		printf("<%s> ", cl->line);
	printf("\n");

}
Пример #13
0
static void text_drawcache_init(SpaceText *st)
{
	DrawCache *drawcache = MEM_callocN(sizeof(DrawCache), "text draw cache");

	drawcache->winx = -1;
	drawcache->nlines = BLI_listbase_count(&st->text->lines);
	drawcache->text_id[0] = '\0';

	st->drawcache = drawcache;
}
Пример #14
0
static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
{
	bGPdata *gpd = (bGPdata *)ptr->id.data;

	*min = 0;
	*max = max_ii(0, BLI_listbase_count(&gpd->layers) - 1);

	*softmin = *min;
	*softmax = *max;
}
Пример #15
0
/**
 * The automatic/fallback name of a new collection.
 */
void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
{
  char *name;

  if (!collection_parent) {
    name = BLI_strdup("Collection");
  }
  else if (collection_parent->flag & COLLECTION_IS_MASTER) {
    name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1);
  }
  else {
    const int number = BLI_listbase_count(&collection_parent->children) + 1;
    const int digits = integer_digits_i(number);
    const int max_len = sizeof(collection_parent->id.name) - 1 /* NULL terminator */ -
                        (1 + digits) /* " %d" */ - 2 /* ID */;
    name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number);
  }

  BLI_strncpy(rname, name, MAX_NAME);
  MEM_freeN(name);
}
Пример #16
0
void BKE_mask_layer_evaluate_animation(MaskLayer *masklay, const float ctime)
{
	/* animation if available */
	MaskLayerShape *masklay_shape_a;
	MaskLayerShape *masklay_shape_b;
	int found;
	if ((found = BKE_mask_layer_shape_find_frame_range(
	        masklay, ctime, &masklay_shape_a, &masklay_shape_b)))
	{
		if (found == 1) {
#if 0
			printf("%s: exact %d %d (%d)\n",
			       __func__,
			       (int)ctime,
			       BLI_listbase_count(&masklay->splines_shapes),
			       masklay_shape_a->frame);
#endif
			BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a);
		}
		else if (found == 2) {
			float w = masklay_shape_b->frame - masklay_shape_a->frame;
#if 0
			printf("%s: tween %d %d (%d %d)\n",
			       __func__,
			       (int)ctime,
			       BLI_listbase_count(&masklay->splines_shapes),
			       masklay_shape_a->frame, masklay_shape_b->frame);
#endif
			BKE_mask_layer_shape_to_mask_interp(
			        masklay,
			        masklay_shape_a, masklay_shape_b,
			        (ctime - masklay_shape_a->frame) / w);
		}
		else {
			/* always fail, should never happen */
			BLI_assert(found == 2);
		}
	}
}
Пример #17
0
static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *image_p)
{
  uiBlock *block = uiLayoutGetBlock(layout);
  Image *image = image_p;
  int slot_id;

  uiDefBut(block,
           UI_BTYPE_LABEL,
           0,
           IFACE_("Slot"),
           0,
           0,
           UI_UNIT_X * 5,
           UI_UNIT_Y,
           NULL,
           0.0,
           0.0,
           0,
           0,
           "");
  uiItemS(layout);

  slot_id = BLI_listbase_count(&image->renderslots) - 1;
  for (RenderSlot *slot = image->renderslots.last; slot; slot = slot->prev) {
    char str[64];
    if (slot->name[0] != '\0') {
      BLI_strncpy(str, slot->name, sizeof(str));
    }
    else {
      BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot_id + 1);
    }
    uiDefButS(block,
              UI_BTYPE_BUT_MENU,
              B_NOP,
              str,
              0,
              0,
              UI_UNIT_X * 5,
              UI_UNIT_X,
              &image->render_slot,
              (float)slot_id,
              0.0,
              0,
              -1,
              "");
    slot_id--;
  }
}
Пример #18
0
static void layer_eval_view_layer(struct Depsgraph *depsgraph,
                                  struct Scene *UNUSED(scene),
                                  ViewLayer *view_layer)
{
  DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer);

  /* Create array of bases, for fast index-based lookup. */
  const int num_object_bases = BLI_listbase_count(&view_layer->object_bases);
  MEM_SAFE_FREE(view_layer->object_bases_array);
  view_layer->object_bases_array = MEM_malloc_arrayN(
      num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
  int base_index = 0;
  for (Base *base = view_layer->object_bases.first; base; base = base->next) {
    view_layer->object_bases_array[base_index++] = base;
  }
}
Пример #19
0
static void buttons_texture_user_node_add(ListBase *users, ID *id, 
                                          bNodeTree *ntree, bNode *node,
                                          const char *category, int icon, const char *name)
{
	ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");

	user->id = id;
	user->ntree = ntree;
	user->node = node;
	user->category = category;
	user->icon = icon;
	user->name = name;
	user->index = BLI_listbase_count(users);

	BLI_addtail(users, user);
}
Пример #20
0
static void buttons_texture_user_property_add(ListBase *users, ID *id, 
                                              PointerRNA ptr, PropertyRNA *prop,
                                              const char *category, int icon, const char *name)
{
	ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser");

	user->id = id;
	user->ptr = ptr;
	user->prop = prop;
	user->category = category;
	user->icon = icon;
	user->name = name;
	user->index = BLI_listbase_count(users);

	BLI_addtail(users, user);
}
Пример #21
0
/* Adds a new bone-group (name may be NULL) */
bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
{
	bActionGroup *grp;
	
	if (!name) {
		name = DATA_("Group");
	}
	
	grp = MEM_callocN(sizeof(bActionGroup), "PoseGroup");
	BLI_strncpy(grp->name, name, sizeof(grp->name));
	BLI_addtail(&pose->agroups, grp);
	BLI_uniquename(&pose->agroups, grp, name, '.', offsetof(bActionGroup, name), sizeof(grp->name));
	
	pose->active_group = BLI_listbase_count(&pose->agroups);
	
	return grp;
}
Пример #22
0
/* called on event handling by event_system.c */
void wm_operator_register(bContext *C, wmOperator *op)
{
	wmWindowManager *wm = CTX_wm_manager(C);
	int tot;

	BLI_addtail(&wm->operators, op);
	tot = BLI_listbase_count(&wm->operators);
	
	while (tot > MAX_OP_REGISTERED) {
		wmOperator *opt = wm->operators.first;
		BLI_remlink(&wm->operators, opt);
		WM_operator_free(opt);
		tot--;
	}
	
	/* so the console is redrawn */
	WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
	WM_event_add_notifier(C, NC_WM | ND_HISTORY, NULL);
}
Пример #23
0
/* Markers inside an action strip */
static void nla_actionclip_draw_markers(
    NlaStrip *strip, float yminc, float ymaxc, int shade, const bool dashed)
{
  const bAction *act = strip->act;

  if (ELEM(NULL, act, act->markers.first)) {
    return;
  }

  const uint shdr_pos = GPU_vertformat_attr_add(
      immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
  if (dashed) {
    immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);

    float viewport_size[4];
    GPU_viewport_size_get_f(viewport_size);
    immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC);

    immUniform1i("colors_len", 0); /* "simple" mode */
    immUniform1f("dash_width", 6.0f);
    immUniform1f("dash_factor", 0.5f);
  }
  else {
    immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
  }
  immUniformThemeColorShade(TH_STRIP_SELECT, shade);

  immBeginAtMost(GPU_PRIM_LINES, BLI_listbase_count(&act->markers) * 2);
  for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
    if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
      float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);

      /* just a simple line for now */
      /* XXX: draw a triangle instead... */
      immVertex2f(shdr_pos, frame, yminc + 1);
      immVertex2f(shdr_pos, frame, ymaxc - 1);
    }
  }
  immEnd();

  immUnbindProgram();
}
Пример #24
0
int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
{
  NodeImageMultiFile *nimf = node->storage;
  bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input);
  int totinputs = BLI_listbase_count(&node->inputs);

  if (!sock) {
    return 0;
  }

  if (nimf->active_input == totinputs - 1) {
    --nimf->active_input;
  }

  /* free format data */
  MEM_freeN(sock->storage);

  nodeRemoveSocket(ntree, node, sock);
  return 1;
}
Пример #25
0
static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
    void **rnd_data = rnd_pt;
    uiBlock *block = uiLayoutGetBlock(layout);
    Image *image = rnd_data[0];
    ImageUser *iuser = rnd_data[1];
    Scene *scene = iuser->scene;
    RenderResult *rr;
    RenderLayer *rl;
    RenderLayer rl_fake = {NULL};
    const char *fake_name;
    int nr;

    /* may have been freed since drawing */
    rr = BKE_image_acquire_renderresult(scene, image);
    if (UNLIKELY(rr == NULL)) {
        return;
    }

    UI_block_layout_set_current(block, layout);
    uiLayoutColumn(layout, false);

    uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Layer"),
             0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
    uiItemS(layout);

    nr = BLI_listbase_count(&rr->layers) - 1;
    fake_name = ui_imageuser_layer_fake_name(rr);

    if (fake_name) {
        BLI_strncpy(rl_fake.name, fake_name, sizeof(rl_fake.name));
        nr += 1;
    }

    for (rl = rr->layers.last; rl; rl = rl->prev, nr--) {
final:
        uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, rl->name, 0, 0,
                  UI_UNIT_X * 5, UI_UNIT_X, &iuser->layer, (float) nr, 0.0, 0, -1, "");
    }
Пример #26
0
static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
{
	Scene *scene = CTX_data_scene(C);
	Paint *paint = BKE_paint_get_active_from_context(C);
	Brush *brush = paint->brush;
	PaintMode mode = BKE_paintmode_get_active_from_context(C);
	Palette *palette = paint->palette;
	PaletteColor *color;

	color = BKE_palette_color_add(palette);
	palette->active_color = BLI_listbase_count(&palette->colors) - 1;

	if (ELEM(mode, ePaintTextureProjective, ePaintTexture2D, ePaintVertex)) {
		copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
		color->value = 0.0;
	}
	else if (mode == ePaintWeight) {
		zero_v3(color->rgb);
		color->value = brush->weight;
	}

	return OPERATOR_FINISHED;
}
Пример #27
0
/* note, must be freed */
int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
{
	int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);

	if (defbase_tot == 0) {
		return NULL;
	}
	else {
		bDeformGroup *dg;
		char name_flip[sizeof(dg->name)];
		int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);

		for (i = 0; i < defbase_tot; i++) {
			map[i] = -1;
		}

		for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
			if (map[i] == -1) { /* may be calculated previously */

				/* in case no valid value is found, use this */
				if (use_default)
					map[i] = i;

				BKE_deform_flip_side_name(name_flip, dg->name, false);

				if (!STREQ(name_flip, dg->name)) {
					flip_num = defgroup_name_index(ob, name_flip);
					if (flip_num >= 0) {
						map[i] = flip_num;
						map[flip_num] = i; /* save an extra lookup */
					}
				}
			}
		}
		return map;
	}
}
Пример #28
0
/* Generic "generateStrokes" callback */
static void generateStrokes(GpencilModifierData *md,
                            Depsgraph *UNUSED(depsgraph),
                            Object *ob,
                            bGPDlayer *gpl,
                            bGPDframe *gpf)
{
  MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
  bGPDstroke *gps, *gps_new = NULL;
  int tot_strokes;
  int i;

  /* check each axis for mirroring */
  for (int xi = 0; xi < 3; ++xi) {
    if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) {

      /* count strokes to avoid infinite loop after adding new strokes to tail of listbase */
      tot_strokes = BLI_listbase_count(&gpf->strokes);

      for (i = 0, gps = gpf->strokes.first; i < tot_strokes; i++, gps = gps->next) {
        if (is_stroke_affected_by_modifier(ob,
                                           mmd->layername,
                                           mmd->pass_index,
                                           mmd->layer_pass,
                                           1,
                                           gpl,
                                           gps,
                                           mmd->flag & GP_MIRROR_INVERT_LAYER,
                                           mmd->flag & GP_MIRROR_INVERT_PASS,
                                           mmd->flag & GP_MIRROR_INVERT_LAYERPASS)) {
          gps_new = BKE_gpencil_stroke_duplicate(gps);
          update_position(ob, mmd, gps_new, xi);
          BLI_addtail(&gpf->strokes, gps_new);
        }
      }
    }
  }
}
Пример #29
0
static KS_Path *rna_KeyingSet_paths_add(KeyingSet *keyingset, ReportList *reports,
                                        ID *id, const char rna_path[], int index, int group_method, const char group_name[])
{
    KS_Path *ksp = NULL;
    short flag = 0;

    /* special case when index = -1, we key the whole array (as with other places where index is used) */
    if (index == -1) {
        flag |= KSP_FLAG_WHOLE_ARRAY;
        index = 0;
    }

    /* if data is valid, call the API function for this */
    if (keyingset) {
        ksp = BKE_keyingset_add_path(keyingset, id, group_name, rna_path, index, flag, group_method);
        keyingset->active_path = BLI_listbase_count(&keyingset->paths);
    }
    else {
        BKE_report(reports, RPT_ERROR, "Keying set path could not be added");
    }

    /* return added path */
    return ksp;
}
Пример #30
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, NULL);
		}
	}
	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;
}