[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17550] branches/animsys2/source/blender: AnimSys2: Joining Meshes with Shapekeys

Joshua Leung aligorith at gmail.com
Mon Nov 24 11:21:18 CET 2008


Revision: 17550
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17550
Author:   aligorith
Date:     2008-11-24 11:21:18 +0100 (Mon, 24 Nov 2008)

Log Message:
-----------
AnimSys2: Joining Meshes with Shapekeys

It is now possible to join several meshes that have shapekeys (using Ctrl-J). This is still a 'first draft' version, as there are still a few cases things that need ironing out still (*see notes). 
Be aware that this may very well crash or screw things up in weird and wonderful ways.

Where possible, I've attempted to add some comments and general cleanups to this code to make it easier to follow. 

Notes (i.e. things that will be fixed in upcoming commits):
- Joining of shapekeys will only happen if the destination mesh has some shapekeys. If one of the meshes being merged into it has shapekeys but it doesn't, these are ignored/lost.
- IPO's are currently not transferred across yet...

Modified Paths:
--------------
    branches/animsys2/source/blender/blenkernel/BKE_key.h
    branches/animsys2/source/blender/blenkernel/intern/key.c
    branches/animsys2/source/blender/src/meshtools.c

Modified: branches/animsys2/source/blender/blenkernel/BKE_key.h
===================================================================
--- branches/animsys2/source/blender/blenkernel/BKE_key.h	2008-11-24 07:08:51 UTC (rev 17549)
+++ branches/animsys2/source/blender/blenkernel/BKE_key.h	2008-11-24 10:21:18 UTC (rev 17550)
@@ -62,6 +62,7 @@
 struct Key *ob_get_key(struct Object *ob);
 struct KeyBlock *ob_get_keyblock(struct Object *ob);
 struct KeyBlock *key_get_keyblock(struct Key *key, int index);
+struct KeyBlock *key_get_named_keyblock(struct Key *key, const char name[]);
 // needed for the GE
 void do_rel_key(int start, int end, int tot, char *basispoin, struct Key *key, int mode);
 

Modified: branches/animsys2/source/blender/blenkernel/intern/key.c
===================================================================
--- branches/animsys2/source/blender/blenkernel/intern/key.c	2008-11-24 07:08:51 UTC (rev 17549)
+++ branches/animsys2/source/blender/blenkernel/intern/key.c	2008-11-24 10:21:18 UTC (rev 17550)
@@ -1407,3 +1407,18 @@
 	
 	return NULL;
 }
+
+/* get the appropriate KeyBlock given a name to search for */
+KeyBlock *key_get_named_keyblock(Key *key, const char name[])
+{
+	KeyBlock *kb;
+	
+	if (key) {
+		for (kb= key->block.first; kb; kb= kb->next) {
+			if (strcmp(name, kb->name)==0)
+				return kb;
+		}
+	}
+	
+	return NULL;
+}

Modified: branches/animsys2/source/blender/src/meshtools.c
===================================================================
--- branches/animsys2/source/blender/src/meshtools.c	2008-11-24 07:08:51 UTC (rev 17549)
+++ branches/animsys2/source/blender/src/meshtools.c	2008-11-24 10:21:18 UTC (rev 17550)
@@ -51,6 +51,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_image_types.h"
+#include "DNA_key_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
@@ -68,6 +69,8 @@
 #include "BKE_customdata.h"
 #include "BKE_global.h"
 #include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_mesh.h"
@@ -123,10 +126,12 @@
 	Object *ob;
 	Material **matar, *ma;
 	Mesh *me;
-	MVert *mvert, *mvertmain;
+	MVert *mvert, *mv, *mvertmain;
 	MEdge *medge = NULL, *medgemain;
 	MFace *mface = NULL, *mfacemain;
-	float imat[4][4], cmat[4][4];
+	Key *key, *nkey=NULL;
+	KeyBlock *kb, *okb, *kbn;
+	float imat[4][4], cmat[4][4], *fp1, *fp2;
 	int a, b, totcol, totedge=0, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT];
 	int	i, j, index, haskey=0, hasmulti=0, edgeofs, faceofs;
 	bDeformGroup *dg, *odg;
@@ -135,8 +140,9 @@
 
 	if(G.obedit) return 0;
 	
+	/* ob is the object we are adding geometry to */
 	ob= OBACT;
-	if(!ob || ob->type!=OB_MESH) return 0;
+	if((!ob) || (ob->type!=OB_MESH)) return 0;
 	
 	if (object_data_is_libdata(ob)) {
 		error_libdata();
@@ -165,51 +171,38 @@
 #endif
 
 	/* count & check */
-	base= FIRSTBASE;
-	while(base) {
+	for (base= FIRSTBASE; base; base= base->next) {
 		if TESTBASELIB_BGMODE(base) { /* BGMODE since python can access */
-			if(base->object->type==OB_MESH) {
+			if (base->object->type==OB_MESH) {
 				me= base->object->data;
+				
 				totvert+= me->totvert;
+				totedge+= me->totedge;
 				totface+= me->totface;
-
-				if(base->object == ob) ok= 1;
-
-				if(me->key) {
-					haskey= 1;
-					break;
-				}
-				if(me->mr) {
+				
+				if (base->object == ob) ok= 1;
+				
+				/* check for multires */
+				if (me->mr) {
 					hasmulti= 1;
 					break;
 				}
 			}
 		}
-		base= base->next;
 	}
 	
-	if(haskey) {
-		error("Can't join meshes with vertex keys");
-		return 0;
-	}
-	if(hasmulti) {
+	if (hasmulti) {
 		error("Can't join meshes with Multires");
 		return 0;
 	}
 	/* that way the active object is always selected */ 
-	if(ok==0) return 0;
+	if (ok==0) return 0;
 	
-	if(totvert==0 || totvert>MESH_MAX_VERTS) return 0;
-
-	/* if needed add edges to other meshes */
-	for(base= FIRSTBASE; base; base= base->next) {
-		if TESTBASELIB_BGMODE(base) {
-			if(base->object->type==OB_MESH) {
-				me= base->object->data;
-				totedge += me->totedge;
-			}
-		}
-	}
+	/* only join meshes if there are verts to join, there aren't too many, and we only had one mesh selected */
+	me= (Mesh *)ob->data;
+	key= me->key;
+	if ((totvert==0) || (totvert>MESH_MAX_VERTS) || (totvert==me->totvert)) 
+		return 0;
 	
 	/* new material indices and material array */
 	matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh");
@@ -222,54 +215,99 @@
 		/* increase id->us : will be lowered later */
 	}
 	
-	base= FIRSTBASE;
-	while(base) {
+	/* if destination mesh had shapekeys, move them somewhere safe, and set up placeholders
+	 * with arrays that are large enough to hold shapekey data for all meshes
+	 */
+	if (key) {
+		/* make a duplicate copy that will only be used here... (must remember to free it!) */
+		nkey= copy_key(key);
+		
+		/* for all keys in old block, clear data-arrays */
+		for (kb= key->block.first; kb; kb= kb->next) {
+			if (kb->data) MEM_freeN(kb->data);
+			kb->data= MEM_callocN(sizeof(float)*3*totvert, "join_shapekey");
+			kb->totelem= totvert;
+		}
+	}
+	
+	/* first pass over objects - copying materials and vertexgroups across */
+	for (base= FIRSTBASE; base; base= base->next) {
 		if TESTBASELIB_BGMODE(base) {
-			if(ob!=base->object && base->object->type==OB_MESH) {
+			/* only act if a mesh, and not the one we're joining to */
+			if ((ob!=base->object) && (base->object->type==OB_MESH)) {
 				me= base->object->data;
-
-				// Join this object's vertex groups to the base one's
-				for (dg=base->object->defbase.first; dg; dg=dg->next){
-					/* See if this group exists in the object */
-					for (odg=ob->defbase.first; odg; odg=odg->next){
-						if (!strcmp(odg->name, dg->name)){
+				
+				/* Join this object's vertex groups to the base one's */
+				for (dg=base->object->defbase.first; dg; dg=dg->next) {
+					/* See if this group exists in the object (if it doesn't, add it to the end) */
+					for (odg=ob->defbase.first; odg; odg=odg->next) {
+						if (!strcmp(odg->name, dg->name)) {
 							break;
 						}
 					}
-					if (!odg){
-						odg = MEM_callocN (sizeof(bDeformGroup), "join deformGroup");
-						memcpy (odg, dg, sizeof(bDeformGroup));
+					if (!odg) {
+						odg = MEM_callocN(sizeof(bDeformGroup), "join deformGroup");
+						memcpy(odg, dg, sizeof(bDeformGroup));
 						BLI_addtail(&ob->defbase, odg);
 					}
-
 				}
 				if (ob->defbase.first && ob->actdef==0)
 					ob->actdef=1;
-
-				if(me->totvert) {
-					for(a=1; a<=base->object->totcol; a++) {
-						ma= give_current_material(base->object, a);
-						if(ma) {
-							for(b=0; b<totcol; b++) {
-								if(ma == matar[b]) break;
+				
+				
+				if (me->totvert) {
+					/* Add this object's materials to the base one's if they don't exist already (but only if limits not exceeded yet) */
+					if (totcol < MAXMAT-1) {
+						for (a=1; a<=base->object->totcol; a++) {
+							ma= give_current_material(base->object, a);
+							if (ma) {
+								for (b=0; b<totcol; b++) {
+									if (ma == matar[b]) break;
+								}
+								if (b==totcol) {
+									matar[b]= ma;
+									ma->id.us++;
+									totcol++;
+								}
+								if (totcol>=MAXMAT-1) 
+									break;
 							}
-							if(b==totcol) {
-								matar[b]= ma;
-								ma->id.us++;
-								totcol++;
+						}
+					}
+					
+					/* if this mesh has shapekeys, check if destination mesh already has matching entries too */
+					// FIXME: currently, we will only add shapekeys if the base mesh had them :/
+					if (me->key && key) {
+						for (kb= me->key->block.first; kb; kb= kb->next) {
+							/* if key doesn't exist in destination mesh, add it */
+							if (key_get_named_keyblock(key, kb->name) == NULL) {
+								/* copy this existing one over to the new shapekey block */
+								kbn= MEM_dupallocN(kb);
+								kbn->prev= kbn->next= NULL;
+								
+								/* adjust adrcode and other settings to fit (allocate a new data-array) */
+								kbn->data= MEM_callocN(sizeof(float)*3*totvert, "joined_shapekey");
+								kbn->totelem= totvert;
+								kbn->weights= NULL; // FIXME... not sure what these are for, but adding shapekeys doesn't set this!
+								
+								BLI_addtail(&key->block, kbn);
+								kbn->adrcode= key->totkey;
+								key->totkey++;
+								
+								/* also, copy corresponding ipo-curve to ipo-block if applicable */
+								if (me->key->ipo && key->ipo) {
+									// FIXME... this is a luxury item!
+								}
 							}
-							if(totcol>=MAXMAT-1) break;
 						}
 					}
 				}
 			}
-			if(totcol>=MAXMAT-1) break;
+			
 		}
-		base= base->next;
 	}
-
-	me= ob->data;
-
+	
+	/* setup new data for destination mesh */
 	memset(&vdata, 0, sizeof(vdata));
 	memset(&edata, 0, sizeof(edata));
 	memset(&fdata, 0, sizeof(fdata));
@@ -277,41 +315,44 @@
 	mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
 	medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
 	mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
-
+	
 	mvertmain= mvert;
 	medgemain= medge;
 	mfacemain= mface;
-
-	/* inverse transorm all selected meshes in this object */
-	Mat4Invert(imat, ob->obmat);
-
+	
 	vertofs= 0;
 	edgeofs= 0;
 	faceofs= 0;
-	base= FIRSTBASE;
-	while(base) {
+	
+	/* inverse transform for all selected meshes in this object */
+	Mat4Invert(imat, ob->obmat);
+	
+	for (base= FIRSTBASE; base; base= nextb) {
 		nextb= base->next;
+		
 		if TESTBASELIB_BGMODE(base) {
-			if(base->object->type==OB_MESH) {
-				
+			/* only join if this is a mesh */
+			if (base->object->type==OB_MESH) {
 				me= base->object->data;
 				
-				if(me->totvert) {
+				if (me->totvert) {
+					/* standard data */
 					CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
 					CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
 					
+					/* vertex groups */
 					dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
-
-					/* NEW VERSION */
-					if (dvert){
-						for (i=0; i<me->totvert; i++){
-							for (j=0; j<dvert[i].totweight; j++){
-								//	Find the old vertex group
-								odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr);
+					
+					/* NB: vertex groups here are new version */
+					if (dvert) {
+						for (i=0; i<me->totvert; i++) {
+							for (j=0; j<dvert[i].totweight; j++) {
+								/*	Find the old vertex group */
+								odg = BLI_findlink(&base->object->defbase, dvert[i].dw[j].def_nr);
 								if(odg) {

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list