New feature: Face Duplicators. Like vertex-duplicator, but now on a face

center, rotated according to face edges, and optionally with scale of the
face.

http://www.blender3d.org/cms/Face_Duplicator.828.0.html

Also: bugfix in undo/redo for relinking data to the UI. It was not checking
for Library data, accidentally linking non-library data with same names.
This commit is contained in:
Ton Roosendaal
2006-11-29 08:57:32 +00:00
parent a1481bc7e5
commit eb03a578a3
7 changed files with 201 additions and 70 deletions

View File

@@ -872,7 +872,7 @@ void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
/* store vertexes indices in tmp union */
for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
ev->tmp.l = (long) i++;
ev->tmp.l = (long) i;
for( ; ef; ef = ef->next, ++face_r) {
face_r->mat_nr = ef->mat_nr;

View File

@@ -457,6 +457,107 @@ static void vertex_duplilist(ListBase *lb, Scene *sce, Object *par)
dm->release(dm);
}
static void face_duplilist(ListBase *lb, Scene *sce, Object *par)
{
Object *ob;
Base *base;
DerivedMesh *dm;
MFace *mface;
MVert *mvert;
float pmat[4][4];
int lay, totface, a;
Mat4CpyMat4(pmat, par->obmat);
lay= G.scene->lay;
if(par==G.obedit) {
int totvert;
dm= editmesh_get_derived_cage();
totface= dm->getNumFaces(dm);
mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp");
dm->copyFaceArray(dm, mface);
totvert= dm->getNumVerts(dm);
mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp");
dm->copyVertArray(dm, mvert);
}
else {
dm = mesh_get_derived_deform(par);
totface= dm->getNumFaces(dm);
mface= dm->getFaceArray(dm);
mvert= dm->getVertArray(dm);
}
for(base= sce->base.first; base; base= base->next) {
if(base->object->type>0 && (lay & base->lay) && G.obedit!=base->object) {
ob= base->object->parent;
while(ob) {
if(ob==par) {
ob= base->object;
/* mballs have a different dupli handling */
if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */
for(a=0; a<totface; a++) {
float *v1= mvert[ mface[a].v1 ].co;
float *v2= mvert[ mface[a].v2 ].co;
float *v3= mvert[ mface[a].v3 ].co;
float *v4= mface[a].v4?mvert[ mface[a].v4 ].co:NULL;
float cent[3], quat[4], mat[3][3], tmat[4][4], obmat[4][4];
/* translation */
if(v4)
CalcCent4f(cent, v1, v2, v3, v4);
else
CalcCent3f(cent, v1, v2, v3);
Mat4MulVecfl(pmat, cent);
VecSubf(cent, cent, pmat[3]);
VecAddf(cent, cent, ob->obmat[3]);
Mat4CpyMat4(obmat, ob->obmat);
VECCOPY(obmat[3], cent);
/* rotation */
triatoquat(v1, v2, v3, quat);
QuatToMat3(quat, mat);
/* scale */
if(par->transflag & OB_DUPLIFACES_SCALE) {
float size= v4?AreaQ3Dfl(v1, v2, v3, v4):AreaT3Dfl(v1, v2, v3);
size= sqrt(size);
Mat3MulFloat(mat[0], size);
}
Mat4CpyMat4(tmat, obmat);
Mat4MulMat43(obmat, tmat, mat);
new_dupli_object(lb, ob, obmat, lay, a);
}
break;
}
ob= ob->parent;
}
}
}
if(par==G.obedit) {
MEM_freeN(mface);
MEM_freeN(mvert);
}
dm->release(dm);
}
static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *paf)
{
Object *ob, copyob;
@@ -670,16 +771,20 @@ ListBase *object_duplilist(Scene *sce, Object *ob)
if(ob->transflag & OB_DUPLI) {
if(ob->transflag & OB_DUPLIVERTS) {
if(ob->type==OB_MESH) {
if(ob->transflag & OB_DUPLIVERTS) {
PartEff *paf;
if( (paf=give_parteff(ob)) ) particle_duplilist(&duplilist, sce, ob, paf);
else vertex_duplilist(&duplilist, sce, ob);
}
PartEff *paf;
if( (paf=give_parteff(ob)) )
particle_duplilist(&duplilist, sce, ob, paf);
else
vertex_duplilist(&duplilist, sce, ob);
}
else if(ob->type==OB_FONT) {
font_duplilist(&duplilist, ob);
}
}
else if(ob->transflag & OB_DUPLIFACES) {
if(ob->type==OB_MESH)
face_duplilist(&duplilist, sce, ob);
}
else if(ob->transflag & OB_DUPLIFRAMES)
frames_duplilist(&duplilist, ob);
else if(ob->transflag & OB_DUPLIGROUP) {

View File

@@ -538,7 +538,8 @@ ID *find_id(char *type, char *name) /* type: "OB" or "MA" etc */
id= lb->first;
while(id) {
if( strcmp(id->name+2, name)==0 ) return id;
if(id->name[2]==name[0] && strcmp(id->name+2, name)==0 )
return id;
id= id->next;
}
return 0;

View File

@@ -3419,26 +3419,30 @@ static void lib_link_screen(FileData *fd, Main *main)
}
}
/* Only for undo files, or to restore a screen after reading without UI... */
static void *restore_pointer_by_name(Main *mainp, ID *id, int user)
{
ListBase *lb;
ID *idn=NULL;
if(id) {
lb= wich_libbase(mainp, GS(id->name));
ListBase *lb= wich_libbase(mainp, GS(id->name));
if(lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
idn= lb->first;
ID *idn= lb->first;
char *name= id->name+2;
while(idn) {
if( strcmp(idn->name, id->name)==0) {
if(user && idn->us==0) idn->us++;
break;
if(idn->name[2]==name[0] && strcmp(idn->name+2, name)==0) {
if(idn->lib==id->lib) {
if(user && idn->us==0) idn->us++;
break;
}
}
idn= idn->next;
}
return idn;
}
}
return idn;
return NULL;
}
/* called from kernel/blender.c */

View File

@@ -253,6 +253,11 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
#define B_RECALCPATH 1401
#define B_TRACKBUTS 1402
#define B_DUPLI_FRAME 1403
#define B_DUPLI_VERTS 1404
#define B_DUPLI_FACES 1405
#define B_DUPLI_GROUP 1406
#define B_PRINTSPEED 1413
#define B_PRINTLEN 1414

View File

@@ -266,16 +266,18 @@ extern Object workob;
#define PARSLOW 16
/* (short) transflag */
#define OB_OFFS_LOCAL 1
#define OB_QUAT 2
#define OB_NEG_SCALE 4
#define OB_DUPLI (8+16+256)
#define OB_DUPLIFRAMES 8
#define OB_DUPLIVERTS 16
#define OB_DUPLIROT 32
#define OB_DUPLINOSPEED 64
#define OB_POWERTRACK 128
#define OB_DUPLIGROUP 256
#define OB_OFFS_LOCAL 1
#define OB_QUAT 2
#define OB_NEG_SCALE 4
#define OB_DUPLI (8+16+256+512)
#define OB_DUPLIFRAMES 8
#define OB_DUPLIVERTS 16
#define OB_DUPLIROT 32
#define OB_DUPLINOSPEED 64
#define OB_POWERTRACK 128
#define OB_DUPLIGROUP 256
#define OB_DUPLIFACES 512
#define OB_DUPLIFACES_SCALE 1024
/* (short) ipoflag */
#define OB_DRAWKEY 1

View File

@@ -1530,10 +1530,11 @@ void do_object_panels(unsigned short event)
Effect *eff;
ob= OBACT;
if(ob==NULL)
return;
switch(event) {
case B_TRACKBUTS:
ob= OBACT;
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
allqueue(REDRAWVIEW3D, 0);
break;
@@ -1541,9 +1542,29 @@ void do_object_panels(unsigned short event)
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
allqueue(REDRAWVIEW3D, 0);
break;
case B_DUPLI_FRAME:
ob->transflag &= ~(OB_DUPLIVERTS|OB_DUPLIFACES|OB_DUPLIGROUP);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSOBJECT, 0);
break;
case B_DUPLI_VERTS:
ob->transflag &= ~(OB_DUPLIFRAMES|OB_DUPLIFACES|OB_DUPLIGROUP);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSOBJECT, 0);
break;
case B_DUPLI_FACES:
ob->transflag &= ~(OB_DUPLIVERTS|OB_DUPLIFRAMES|OB_DUPLIGROUP);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSOBJECT, 0);
break;
case B_DUPLI_GROUP:
ob->transflag &= ~(OB_DUPLIVERTS|OB_DUPLIFRAMES|OB_DUPLIFACES);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSOBJECT, 0);
break;
case B_PRINTSPEED:
ob= OBACT;
if(ob) {
{
float vec[3];
CFRA++;
do_ob_ipo(ob);
@@ -1558,8 +1579,7 @@ void do_object_panels(unsigned short event)
}
break;
case B_PRINTLEN:
ob= OBACT;
if(ob && ob->type==OB_CURVE) {
if(ob->type==OB_CURVE) {
Curve *cu=ob->data;
if(cu->path) prlen= cu->path->totdist; else prlen= -1.0;
@@ -1571,24 +1591,20 @@ void do_object_panels(unsigned short event)
allqueue(REDRAWBUTSOBJECT, 0);
allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWIPO, 0);
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
break;
case B_CURVECHECK:
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
allqueue(REDRAWVIEW3D, 0);
break;
case B_SOFTBODY_CHANGE:
ob= OBACT;
if(ob) {
ob->softflag |= OB_SB_REDO;
allqueue(REDRAWBUTSOBJECT, 0);
allqueue(REDRAWVIEW3D, 0);
}
ob->softflag |= OB_SB_REDO;
allqueue(REDRAWBUTSOBJECT, 0);
allqueue(REDRAWVIEW3D, 0);
break;
case B_SOFTBODY_DEL_VG:
ob= OBACT;
if(ob && ob->soft) {
if(ob->soft) {
ob->soft->vertgroup= 0;
ob->softflag |= OB_SB_REDO;
allqueue(REDRAWBUTSOBJECT, 0);
@@ -1596,23 +1612,19 @@ void do_object_panels(unsigned short event)
}
break;
case B_SOFTBODY_BAKE:
ob= OBACT;
if(ob && ob->soft) softbody_bake(ob);
if(ob->soft) softbody_bake(ob);
break;
case B_SOFTBODY_BAKE_FREE:
ob= OBACT;
if(ob && ob->soft) sbObjectToSoftbody(ob);
if(ob->soft) sbObjectToSoftbody(ob);
allqueue(REDRAWBUTSOBJECT, 0);
allqueue(REDRAWVIEW3D, 0);
break;
case B_FLUIDSIM_BAKE:
ob= OBACT;
/* write config files (currently no simulation) */
fluidsimBake(ob);
break;
case B_FLUIDSIM_MAKEPART:
ob= OBACT;
if(1) {
{
PartEff *paf= NULL;
/* prepare fluidsim particle display */
// simplified delete effect, create new - recalc some particles...
@@ -1634,9 +1646,9 @@ void do_object_panels(unsigned short event)
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSOBJECT, 0);
break;
case B_FLUIDSIM_SELDIR: {
case B_FLUIDSIM_SELDIR:
{
ScrArea *sa = closest_bigger_area();
ob= OBACT;
/* choose dir for surface files */
areawinset(sa->win);
activate_fileselect(FILE_SPECIAL, "Select Directory", ob->fluidsimSettings->surfdataPath, fluidsimFilesel);
@@ -1649,26 +1661,23 @@ void do_object_panels(unsigned short event)
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
break;
case B_GROUP_RELINK:
group_relink_nla_objects(OBACT);
group_relink_nla_objects(ob);
allqueue(REDRAWVIEW3D, 0);
break;
default:
if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
ob= OBACT;
if(ob) {
int a=B_SELEFFECT;
int a=B_SELEFFECT;
eff= ob->effect.first;
while(eff) {
if(event==a) eff->flag |= SELECT;
else eff->flag &= ~SELECT;
eff= ob->effect.first;
while(eff) {
if(event==a) eff->flag |= SELECT;
else eff->flag &= ~SELECT;
a++;
eff= eff->next;
}
allqueue(REDRAWBUTSOBJECT, 0);
a++;
eff= eff->next;
}
allqueue(REDRAWBUTSOBJECT, 0);
}
}
@@ -1839,13 +1848,18 @@ static void object_panel_anim(Object *ob)
uiDefButBitS(block, TOG, PARSLOW, 0, "SlowPar", 260,155,56,19, &ob->partype, 0, 0, 0, 0, "Create a delay in the parent relationship");
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG, OB_DUPLIFRAMES, REDRAWVIEW3D, "DupliFrames", 24,130,89,20, &ob->transflag, 0, 0, 0, 0, "Make copy of object for every frame");
uiDefButBitS(block, TOG, OB_DUPLIVERTS, REDRAWVIEW3D, "DupliVerts", 114,130,82,20, &ob->transflag, 0, 0, 0, 0, "Duplicate child objects on all vertices");
uiDefButBitS(block, TOG, OB_DUPLIROT, REDRAWVIEW3D, "Rot", 200,130,31,20, &ob->transflag, 0, 0, 0, 0, "Rotate dupli according to vertnormal");
uiDefButBitS(block, TOG, OB_DUPLINOSPEED, REDRAWVIEW3D, "No Speed", 234,130,82,20, &ob->transflag, 0, 0, 0, 0, "Set dupliframes to still, regardless of frame");
uiDefButBitS(block, TOG, OB_DUPLIGROUP, REDRAWVIEW3D, "DupliGroup", 24,110,150,20, &ob->transflag, 0, 0, 0, 0, "Enable group instancing");
uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_GROUP_RELINK, "GR:", 174,110,142,20, &ob->dup_group, "Instance an existing group");
uiDefButBitS(block, TOG, OB_DUPLIFRAMES, B_DUPLI_FRAME, "DupliFrames", 24,130,95,20, &ob->transflag, 0, 0, 0, 0, "Make copy of object for every frame");
uiDefButBitS(block, TOG, OB_DUPLIVERTS, B_DUPLI_VERTS, "DupliVerts", 119,130,95,20, &ob->transflag, 0, 0, 0, 0, "Duplicate child objects on all vertices");
uiDefButBitS(block, TOG, OB_DUPLIFACES, B_DUPLI_FACES, "DupliFaces", 214,130,102,20, &ob->transflag, 0, 0, 0, 0, "Duplicate child objects on all faces");
uiDefButBitS(block, TOG, OB_DUPLIGROUP, B_DUPLI_GROUP, "DupliGroup", 24,110,150,20, &ob->transflag, 0, 0, 0, 0, "Enable group instancing");
if(ob->transflag & OB_DUPLIFRAMES)
uiDefButBitS(block, TOG, OB_DUPLINOSPEED, REDRAWVIEW3D, "No Speed", 174,110,142,20, &ob->transflag, 0, 0, 0, 0, "Set dupliframes to still, regardless of frame");
else if(ob->transflag & OB_DUPLIVERTS)
uiDefButBitS(block, TOG, OB_DUPLIROT, REDRAWVIEW3D, "Rot", 174,110,142,20, &ob->transflag, 0, 0, 0, 0, "Rotate dupli according to vertex normal");
else if(ob->transflag & OB_DUPLIFACES)
uiDefButBitS(block, TOG, OB_DUPLIFACES_SCALE, REDRAWVIEW3D, "Scale", 174,110,142,20, &ob->transflag, 0, 0, 0, 0, "Scale dupli based on face size");
else
uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_GROUP_RELINK, "GR:", 174,110,142,20, &ob->dup_group, "Instance an existing group");
uiBlockBeginAlign(block);
/* DupSta and DupEnd are both shorts, so the maxframe is greater then their range