* 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:
2009-11-28 04:04:01 +00:00
parent 54c5859578
commit aa3ed47848
7 changed files with 248 additions and 104 deletions

View File

@@ -603,6 +603,7 @@ class VIEW3D_MT_object(bpy.types.Menu):
layout.separator()
layout.operator("object.join_shapes")
layout.operator("object.join")
layout.separator()

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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)

View File

@@ -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);