* New tool - Join as Shapes
Available in object mode (Object -> Join as Shapes), only works for meshes at the present. Will merge all selected objects as shape keys on the active object, if the vertex count is the same. This does not keep references to the external objects like in some applications, rather it's a quick way to update the shapes on the active object (perhaps after importing new versions from external applications).
This commit is contained in:
@@ -603,6 +603,7 @@ class VIEW3D_MT_object(bpy.types.Menu):
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("object.join_shapes")
|
||||
layout.operator("object.join")
|
||||
|
||||
layout.separator()
|
||||
|
||||
@@ -83,6 +83,7 @@ int mesh_get_x_mirror_vert(struct Object *ob, int index);
|
||||
int *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em);
|
||||
|
||||
int join_mesh_exec(struct bContext *C, struct wmOperator *op);
|
||||
int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
|
||||
|
||||
/* mesh_ops.c */
|
||||
void ED_operatortypes_mesh(void);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
meshtools.c: no editmode (violated already :), tools operating on meshes
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
@@ -62,6 +63,7 @@
|
||||
#include "BKE_blender.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_image.h"
|
||||
@@ -543,6 +545,82 @@ int join_mesh_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/*********************** JOIN AS SHAPES ***************************/
|
||||
|
||||
/* Append selected meshes vertex locations as shapes of the active mesh,
|
||||
return 0 if no join is made (error) and 1 of the join is done */
|
||||
|
||||
int join_mesh_shapes_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *ob= CTX_data_active_object(C);
|
||||
Mesh *me= (Mesh *)ob->data;
|
||||
Mesh *selme=NULL;
|
||||
DerivedMesh *dm=NULL;
|
||||
Key *key=me->key;
|
||||
KeyBlock *kb;
|
||||
int ok=0, nonequal_verts=0;
|
||||
|
||||
CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
|
||||
if (base->object == ob) continue;
|
||||
|
||||
if (base->object->type==OB_MESH) {
|
||||
selme = (Mesh *)base->object->data;
|
||||
|
||||
if (selme->totvert==me->totvert)
|
||||
ok++;
|
||||
else
|
||||
nonequal_verts=1;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
if (!ok) {
|
||||
if (nonequal_verts)
|
||||
BKE_report(op->reports, RPT_ERROR, "Selected meshes must have equal numbers of vertices.");
|
||||
else
|
||||
BKE_report(op->reports, RPT_ERROR, "No additional selected meshes with equal vertex count to join.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if(key == NULL) {
|
||||
key= me->key= add_key((ID *)me);
|
||||
key->type= KEY_RELATIVE;
|
||||
|
||||
/* first key added, so it was the basis. initialise it with the existing mesh */
|
||||
kb= add_keyblock(scene, key);
|
||||
mesh_to_key(me, kb);
|
||||
}
|
||||
|
||||
/* now ready to add new keys from selected meshes */
|
||||
CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
|
||||
if (base->object == ob) continue;
|
||||
|
||||
if(base->object->type==OB_MESH) {
|
||||
selme = (Mesh *)base->object->data;
|
||||
|
||||
if (selme->totvert==me->totvert) {
|
||||
dm = mesh_get_derived_deform(scene, base->object, CD_MASK_BAREMESH);
|
||||
|
||||
if (!dm) continue;
|
||||
|
||||
kb= add_keyblock(scene, key);
|
||||
strcpy(kb->name, base->object->id.name+2);
|
||||
BLI_uniquename(&key->block, kb, "Key", '.', offsetof(KeyBlock, name), 32);
|
||||
|
||||
DM_to_meshkey(dm, me, kb);
|
||||
|
||||
dm->release(dm);
|
||||
}
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* ********************** SORT FACES ******************* */
|
||||
|
||||
static void permutate(void *list, int num, int size, int *index)
|
||||
|
||||
@@ -1506,6 +1506,18 @@ void OBJECT_OT_duplicate(wmOperatorType *ot)
|
||||
}
|
||||
|
||||
/**************************** Join *************************/
|
||||
static int join_poll(bContext *C)
|
||||
{
|
||||
Object *ob= CTX_data_active_object(C);
|
||||
|
||||
if (!ob) return 0;
|
||||
|
||||
if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
|
||||
return ED_operator_screenactive(C);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int join_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
@@ -1516,10 +1528,6 @@ static int join_exec(bContext *C, wmOperator *op)
|
||||
BKE_report(op->reports, RPT_ERROR, "This data does not support joining in editmode.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
else if(!ob) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't join unless there is an active object.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
else if(object_data_is_libdata(ob)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata.");
|
||||
return OPERATOR_CANCELLED;
|
||||
@@ -1532,8 +1540,6 @@ static int join_exec(bContext *C, wmOperator *op)
|
||||
else if(ob->type == OB_ARMATURE)
|
||||
return join_armature_exec(C, op);
|
||||
|
||||
BKE_report(op->reports, RPT_ERROR, "This object type doesn't support joining.");
|
||||
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
@@ -1546,9 +1552,57 @@ void OBJECT_OT_join(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= join_exec;
|
||||
ot->poll= ED_operator_scene_editable;
|
||||
ot->poll= join_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/**************************** Join as Shape Key*************************/
|
||||
static int join_shapes_poll(bContext *C)
|
||||
{
|
||||
Object *ob= CTX_data_active_object(C);
|
||||
|
||||
if (!ob) return 0;
|
||||
|
||||
/* only meshes supported at the moment */
|
||||
if (ob->type == OB_MESH)
|
||||
return ED_operator_screenactive(C);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int join_shapes_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *ob= CTX_data_active_object(C);
|
||||
|
||||
if(scene->obedit) {
|
||||
BKE_report(op->reports, RPT_ERROR, "This data does not support joining in editmode.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
else if(object_data_is_libdata(ob)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't edit external libdata.");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if(ob->type == OB_MESH)
|
||||
return join_mesh_shapes_exec(C, op);
|
||||
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void OBJECT_OT_join_shapes(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Join as Shapes";
|
||||
ot->description = "Merge selected objects to shapes of active object.";
|
||||
ot->idname= "OBJECT_OT_join_shapes";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= join_shapes_exec;
|
||||
ot->poll= join_shapes_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_duplicate(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_delete(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_join(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_join_shapes(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_convert(struct wmOperatorType *ot);
|
||||
|
||||
/* object_hook.c */
|
||||
|
||||
@@ -331,82 +331,72 @@ int ED_object_modifier_convert(ReportList *reports, Scene *scene, Object *ob, Mo
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode)
|
||||
static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
|
||||
{
|
||||
DerivedMesh *dm;
|
||||
Mesh *me = ob->data;
|
||||
int converted = 0;
|
||||
if (ob->type==OB_MESH) {
|
||||
DerivedMesh *dm;
|
||||
Mesh *me= ob->data;
|
||||
Key *key=me->key;
|
||||
KeyBlock *kb;
|
||||
|
||||
if (scene->obedit) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in editmode");
|
||||
return 0;
|
||||
} else if (((ID*) ob->data)->us>1) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
|
||||
if(!modifier_sameTopology(md)) {
|
||||
BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to Shapes");
|
||||
return 0;
|
||||
}
|
||||
mesh_pmv_off(ob, me);
|
||||
|
||||
dm = mesh_create_derived_for_modifier(scene, ob, md);
|
||||
if (!dm) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(key == NULL) {
|
||||
key= me->key= add_key((ID *)me);
|
||||
key->type= KEY_RELATIVE;
|
||||
/* if that was the first key block added, then it was the basis.
|
||||
* Initialise it with the mesh, and add another for the modifier */
|
||||
kb= add_keyblock(scene, key);
|
||||
mesh_to_key(me, kb);
|
||||
}
|
||||
|
||||
kb= add_keyblock(scene, key);
|
||||
DM_to_meshkey(dm, me, kb);
|
||||
|
||||
dm->release(dm);
|
||||
}
|
||||
else {
|
||||
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (md!=ob->modifiers.first)
|
||||
BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected.");
|
||||
|
||||
static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, ModifierData *md)
|
||||
{
|
||||
if (ob->type==OB_MESH) {
|
||||
if (mode == MODIFIER_APPLY_SHAPE) {
|
||||
Key *key=me->key;
|
||||
KeyBlock *kb;
|
||||
int newkey=0;
|
||||
|
||||
if(!modifier_sameTopology(md)) {
|
||||
BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to Shapes");
|
||||
return 0;
|
||||
}
|
||||
mesh_pmv_off(ob, me);
|
||||
|
||||
dm = mesh_create_derived_for_modifier(scene, ob, md);
|
||||
if (!dm) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(key == NULL) {
|
||||
key= me->key= add_key((ID *)me);
|
||||
key->type= KEY_RELATIVE;
|
||||
newkey= 1;
|
||||
}
|
||||
kb= add_keyblock(scene, key);
|
||||
|
||||
if (newkey) {
|
||||
/* if that was the first key block added, then it was the basis.
|
||||
* Initialise it with the mesh, and add another for the modifier */
|
||||
mesh_to_key(me, kb);
|
||||
kb= add_keyblock(scene, key);
|
||||
}
|
||||
DM_to_meshkey(dm, me, kb);
|
||||
converted = 1;
|
||||
|
||||
dm->release(dm);
|
||||
DerivedMesh *dm;
|
||||
Mesh *me = ob->data;
|
||||
if( me->key) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to Mesh with Shape Keys");
|
||||
return 0;
|
||||
}
|
||||
else { /* MODIFIER_APPLY_DATA */
|
||||
if( me->key) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifier cannot be applied to Mesh with Shape Keys");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mesh_pmv_off(ob, me);
|
||||
mesh_pmv_off(ob, me);
|
||||
|
||||
/* Multires: ensure that recent sculpting is applied */
|
||||
if(md->type == eModifierType_Multires)
|
||||
multires_force_update(ob);
|
||||
/* Multires: ensure that recent sculpting is applied */
|
||||
if(md->type == eModifierType_Multires)
|
||||
multires_force_update(ob);
|
||||
|
||||
dm = mesh_create_derived_for_modifier(scene, ob, md);
|
||||
if (!dm) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DM_to_mesh(dm, me);
|
||||
converted = 1;
|
||||
|
||||
dm->release(dm);
|
||||
dm = mesh_create_derived_for_modifier(scene, ob, md);
|
||||
if (!dm) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DM_to_mesh(dm, me);
|
||||
|
||||
dm->release(dm);
|
||||
}
|
||||
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
|
||||
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
|
||||
@@ -414,6 +404,7 @@ int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, Modi
|
||||
int numVerts;
|
||||
float (*vertexCos)[3];
|
||||
|
||||
|
||||
BKE_report(reports, RPT_INFO, "Applied modifier only changed CV points, not tesselated/bevel vertices");
|
||||
|
||||
if (!(md->mode&eModifierMode_Realtime) || (mti->isDisabled && mti->isDisabled(md))) {
|
||||
@@ -425,8 +416,6 @@ int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, Modi
|
||||
mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0, 0);
|
||||
curve_applyVertexCos(cu, &cu->nurb, vertexCos);
|
||||
|
||||
converted = 1;
|
||||
|
||||
MEM_freeN(vertexCos);
|
||||
|
||||
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
|
||||
@@ -435,15 +424,34 @@ int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, Modi
|
||||
BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (converted) {
|
||||
BLI_remlink(&ob->modifiers, md);
|
||||
modifier_free(md);
|
||||
|
||||
return 1;
|
||||
int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, ModifierData *md, int mode)
|
||||
{
|
||||
if (scene->obedit) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in editmode");
|
||||
return 0;
|
||||
} else if (((ID*) ob->data)->us>1) {
|
||||
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (md!=ob->modifiers.first)
|
||||
BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected.");
|
||||
|
||||
if (mode == MODIFIER_APPLY_SHAPE) {
|
||||
if (!modifier_apply_shape(reports, scene, ob, md))
|
||||
return 0;
|
||||
} else {
|
||||
if (!modifier_apply_obdata(reports, scene, ob, md))
|
||||
return 0;
|
||||
}
|
||||
|
||||
BLI_remlink(&ob->modifiers, md);
|
||||
modifier_free(md);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ED_object_modifier_copy(ReportList *reports, Object *ob, ModifierData *md)
|
||||
|
||||
@@ -124,6 +124,7 @@ void ED_operatortypes_object(void)
|
||||
WM_operatortype_append(OBJECT_OT_duplicates_make_real);
|
||||
WM_operatortype_append(OBJECT_OT_duplicate);
|
||||
WM_operatortype_append(OBJECT_OT_join);
|
||||
WM_operatortype_append(OBJECT_OT_join_shapes);
|
||||
WM_operatortype_append(OBJECT_OT_convert);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_modifier_add);
|
||||
|
||||
Reference in New Issue
Block a user