diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
70 files changed, 10343 insertions, 7293 deletions
diff --git a/source/blender/blenkernel/intern/BME_conversions.c b/source/blender/blenkernel/intern/BME_conversions.c new file mode 100644 index 00000000000..369c19b16c8 --- /dev/null +++ b/source/blender/blenkernel/intern/BME_conversions.c @@ -0,0 +1,392 @@ +/** + * BME_mesh.c jan 2007 + * + * BMesh mesh level functions. + * + * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle, Levi Schooley. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_utildefines.h" +#include "BKE_mesh.h" +#include "BKE_bmesh.h" +#include "BKE_global.h" +#include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" + +#include "BLI_blenlib.h" +#include "BLI_editVert.h" +#include "BLI_edgehash.h" +#include "BIF_editmesh.h" +#include "editmesh.h" +#include "bmesh_private.h" + +#include "BSE_edit.h" + +BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em, BME_Mesh *bm) { + BME_Vert *v1, *v2; + BME_Edge *e, *edar[4]; + BME_Poly *f; + + EditVert *eve; + EditEdge *eed; + EditFace *efa; + + int len; + + BME_model_begin(bm); + + /*add verts*/ + eve= em->verts.first; + while(eve) { + v1 = BME_MV(bm,eve->co); + VECCOPY(v1->no,eve->no); + v1->flag = eve->f; + v1->h = eve->h; + v1->bweight = eve->bweight; + + /* link the verts for edge and face construction; + * kind of a dangerous thing - remember to cast back to BME_Vert before using! */ + eve->tmp.v = (EditVert*)v1; + eve = eve->next; + } + + /*add edges*/ + eed= em->edges.first; + while(eed) { + v1 = (BME_Vert*)eed->v1->tmp.v; + v2 = (BME_Vert*)eed->v2->tmp.v; + e = BME_ME(bm, v1, v2); + e->crease = eed->crease; + e->bweight = eed->bweight; + e->flag = eed->f & SELECT; + if(eed->sharp) e->flag |= ME_SHARP; + if(eed->seam) e->flag |= ME_SEAM; + if(eed->h & EM_FGON) e->flag |= ME_FGON; + if(eed->h & 1) e->flag |= ME_HIDE; + + /* link the edges for face construction; + * kind of a dangerous thing - remember to cast back to BME_Edge before using! */ + eed->tmp.e = (EditEdge*)e; + eed = eed->next; + } + + /*add faces.*/ + efa= em->faces.first; + while(efa) { + if(efa->v4) len = 4; + else len = 3; + + edar[0] = (BME_Edge*)efa->e1->tmp.e; + edar[1] = (BME_Edge*)efa->e2->tmp.e; + edar[2] = (BME_Edge*)efa->e3->tmp.e; + if(len == 4){ + edar[3] = (BME_Edge*)efa->e4->tmp.e; + } + + /*find v1 and v2*/ + v1 = (BME_Vert*)efa->v1->tmp.v; + v2 = (BME_Vert*)efa->v2->tmp.v; + + f = BME_MF(bm,v1,v2,edar,len); + f->mat_nr = efa->mat_nr; + f->flag = efa->flag; + if(efa->h) { + f->flag |= ME_HIDE; + f->flag &= ~ME_FACE_SEL; + } + else { + if(efa->f & 1) f->flag |= ME_FACE_SEL; + else f->flag &= ~ME_FACE_SEL; + } + efa = efa->next; + } + BME_model_end(bm); + return bm; +} + +/* adds the geometry in the bmesh to G.editMesh (does not free G.editMesh) + * if td != NULL, the transdata will be mapped to the EditVert's co */ +EditMesh *BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td) { + BME_Vert *v1; + BME_Edge *e; + BME_Poly *f; + + BME_TransData *vtd; + + EditMesh *em; + EditVert *eve1, *eve2, *eve3, *eve4, **evlist; + EditEdge *eed; + EditFace *efa; + + int totvert, len, i; + + em = G.editMesh; + + if (em == NULL) return NULL; + + /* convert to EditMesh */ + /* make editverts */ + totvert = BLI_countlist(&(bm->verts)); + evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist"); + for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) { + v1->tflag1 = i; + eve1 = addvertlist(v1->co,NULL); + if (td && (vtd = BME_get_transdata(td,v1))) { + vtd->loc = eve1->co; + } + eve1->keyindex = i; + evlist[i]= eve1; + eve1->f = (unsigned char)v1->flag; + eve1->h = (unsigned char)v1->h; + eve1->bweight = v1->bweight; + } + + /* make edges */ + for (e=bm->edges.first;e;e=e->next) { + if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){ + eed= addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL); + eed->crease = e->crease; + eed->bweight = e->bweight; + if(e->flag & ME_SEAM) eed->seam = 1; + if(e->flag & ME_SHARP) eed->sharp = 1; + if(e->flag & SELECT) eed->f |= SELECT; + if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! + if(e->flag & ME_HIDE) eed->h |= 1; + if(G.scene->selectmode==SCE_SELECT_EDGE) + EM_select_edge(eed, eed->f & SELECT); + } + } + + /* make faces */ + for (f=bm->polys.first;f;f=f->next) { + len = BME_cycle_length(f->loopbase); + if (len==3 || len==4) { + eve1= evlist[f->loopbase->v->tflag1]; + eve2= evlist[f->loopbase->next->v->tflag1]; + eve3= evlist[f->loopbase->next->next->v->tflag1]; + if (len == 4) { + eve4= evlist[f->loopbase->prev->v->tflag1]; + } + else { + eve4= NULL; + } + + efa = addfacelist(eve1, eve2, eve3, eve4, NULL, NULL); + efa->mat_nr = (unsigned char)f->mat_nr; + efa->flag= f->flag & ~ME_HIDE; + if(f->flag & ME_FACE_SEL) { + efa->f |= SELECT; + } + if(f->flag & ME_HIDE) efa->h= 1; + if((G.f & G_FACESELECT) && (efa->f & SELECT)) + EM_select_face(efa, 1); /* flush down */ + } + } + + MEM_freeN(evlist); + + countall(); + + return em; +} + +/* Adds the geometry found in dm to bm + * NOTE: it does not allocate a new BME_Mesh! + */ +BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm, BME_Mesh *bm) +{ + MVert *mvert, *mv; + MEdge *medge, *me; + MFace *mface, *mf; + int totface,totedge,totvert,i,len; + + BME_Vert *v1=NULL,*v2=NULL, **vert_array; + BME_Edge *e=NULL; + BME_Poly *f=NULL; + + EdgeHash *edge_hash = BLI_edgehash_new(); + + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + totface = dm->getNumFaces(dm); + mvert = dm->getVertArray(dm); + medge = dm->getEdgeArray(dm); + mface = dm->getFaceArray(dm); + + vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array"); + + BME_model_begin(bm); + /*add verts*/ + for(i=0,mv = mvert; i < totvert;i++,mv++){ + v1 = BME_MV(bm,mv->co); + vert_array[i] = v1; + v1->flag = mv->flag; + v1->bweight = mv->bweight/255.0f; + } + /*add edges*/ + for(i=0,me = medge; i < totedge;i++,me++){ + v1 = vert_array[me->v1]; + v2 = vert_array[me->v2]; + e = BME_ME(bm, v1, v2); + e->crease = me->crease/255.0f; + e->bweight = me->bweight/255.0f; + e->flag = (unsigned char)me->flag; + BLI_edgehash_insert(edge_hash,me->v1,me->v2,e); + } + /*add faces.*/ + for(i=0,mf = mface; i < totface;i++,mf++){ + BME_Edge *edar[4]; + if(mf->v4) len = 4; + else len = 3; + + edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2); + edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3); + if(len == 4){ + edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4); + edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1); + } + else + edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1); + + /*find v1 and v2*/ + v1 = vert_array[mf->v1]; + v2 = vert_array[mf->v2]; + + f = BME_MF(bm,v1,v2,edar,len); + f->mat_nr = mf->mat_nr; + f->flag = mf->flag; + } + + BME_model_end(bm); + BLI_edgehash_free(edge_hash, NULL); + MEM_freeN(vert_array); + return bm; +} + +DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm) +{ + MFace *mface, *mf; + MEdge *medge, *me; + MVert *mvert, *mv; + int totface,totedge,totvert,i,bmeshok,len; + + BME_Vert *v1=NULL; + BME_Edge *e=NULL, *oe=NULL; + BME_Poly *f=NULL; + + DerivedMesh *result; + EdgeHash *edge_hash = BLI_edgehash_new(); + + totvert = BLI_countlist(&(bm->verts)); + totedge = 0; + + /*we cannot have double edges in a derived mesh!*/ + for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i; + for(e=bm->edges.first; e; e=e->next){ + oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1); + if(!oe){ + totedge++; + BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e); + e->tflag2 = 1; + } + else{ + e->tflag2 = 0; + } + } + + /*count quads and tris*/ + totface = 0; + bmeshok = 1; + for(f=bm->polys.first;f;f=f->next){ + len = BME_cycle_length(f->loopbase); + if(len == 3 || len == 4) totface++; + } + + /*convert back to mesh*/ + result = CDDM_from_template(dm,totvert,totedge,totface); + /*Make Verts*/ + mvert = CDDM_get_verts(result); + for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){ + VECCOPY(mv->co,v1->co); + mv->flag = (unsigned char)v1->flag; + mv->bweight = (char)(255.0*v1->bweight); + } + medge = CDDM_get_edges(result); + i=0; + for(e=bm->edges.first,me=medge;e;e=e->next){ + if(e->tflag2){ + if(e->v1->tflag1 < e->v2->tflag1){ + me->v1 = e->v1->tflag1; + me->v2 = e->v2->tflag1; + } + else{ + me->v1 = e->v2->tflag1; + me->v2 = e->v1->tflag1; + } + + me->crease = (char)(255.0*e->crease); + me->bweight = (char)(255.0*e->bweight); + me->flag = e->flag; + me++; + i++; + } + } + if(totface){ + mface = CDDM_get_faces(result); + /*make faces*/ + for(i=0,f=bm->polys.first;f;f=f->next){ + mf = &mface[i]; + len = BME_cycle_length(f->loopbase); + if(len==3 || len==4){ + mf->v1 = f->loopbase->v->tflag1; + mf->v2 = f->loopbase->next->v->tflag1; + mf->v3 = f->loopbase->next->next->v->tflag1; + if(len == 4){ + mf->v4 = f->loopbase->prev->v->tflag1; + } + /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */ + if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){ + test_index_face(mf, NULL, i, len); + } + i++; + mf->mat_nr = (unsigned char)f->mat_nr; + mf->flag = (unsigned char)f->flag; + } + } + } + BLI_edgehash_free(edge_hash, NULL); + return result; +} diff --git a/source/blender/blenkernel/intern/BME_eulers.c b/source/blender/blenkernel/intern/BME_eulers.c new file mode 100644 index 00000000000..3403f5829fe --- /dev/null +++ b/source/blender/blenkernel/intern/BME_eulers.c @@ -0,0 +1,973 @@ +/** + * BME_eulers.c jan 2007 + * + * BMesh Euler construction API. + * + * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" + +#include "BLI_blenlib.h" +#include "bmesh_private.h" +#include "BLI_ghash.h" + +/********************************************************* + * "Euler API" * + * * + * * + * Primitive construction operators for mesh tools. * + * * + **********************************************************/ + + +/* + The functions in this file represent the 'primitive' or 'atomic' operators that + mesh tools use to manipulate the topology of the structure.* The purpose of these + functions is to provide a trusted set of operators to manipulate the mesh topology + and which can also be combined together like building blocks to create more + sophisticated tools. It needs to be stressed that NO manipulation of an existing + mesh structure should be done outside of these functions. + + In the BMesh system, each euler is named by an ancronym which describes what it actually does. + Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that + through a Euler's logical inverse you can 'undo' an operation. (Special note should + be taken of BME_loop_reverse, which is its own inverse). + + BME_MF/KF: Make Face and Kill Face + BME_ME/KE: Make Edge and Kill Edge + BME_MV/KV: Make Vert and Kill Vert + BME_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert + BME_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge + BME_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one) + + Using a combination of these eleven eulers any non-manifold modelling operation can be achieved. + Each Euler operator has a detailed explanation of what is does in the comments preceding its + code. + + *The term "Euler Operator" is actually a misnomer when referring to a non-manifold + data structure. Its use is in keeping with the convention established by others. + + TODO: + -Finish inserting 'strict' validation in all Eulers +*/ + +void *BME_exit(char *s) { + if (s) printf("%s\n",s); + return NULL; +} + +#define RETCLEAR(bm) {bm->rval->v = bm->rval->e = bm->rval->f = bm->rva->l = NULL;} +/*MAKE Eulers*/ + +/** + * BME_MV + * + * MAKE VERT EULER: + * + * Makes a single loose vertex. + * + * Returns - + * A BME_Vert pointer. + */ + +BME_Vert *BME_MV(BME_Mesh *bm, float *vec){ + BME_Vert *v = BME_addvertlist(bm, NULL); + VECCOPY(v->co,vec); + return v; +} + +/** + * BME_ME + * + * MAKE EDGE EULER: + * + * Makes a single wire edge between two vertices. + * If the caller does not want there to be duplicate + * edges between the vertices, it is up to them to check + * for this condition beforehand. + * + * Returns - + * A BME_Edge pointer. + */ + +BME_Edge *BME_ME(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2){ + BME_Edge *e=NULL; + BME_CycleNode *d1=NULL, *d2=NULL; + int valance1=0, valance2=0, edok; + + /*edge must be between two distinct vertices...*/ + if(v1 == v2) return NULL; + + #ifndef BME_FASTEULER + /*count valance of v1*/ + if(v1->edge){ + d1 = BME_disk_getpointer(v1->edge,v1); + if(d1) valance1 = BME_cycle_length(d1); + else BME_error(); + } + if(v2->edge){ + d2 = BME_disk_getpointer(v2->edge,v2); + if(d2) valance2 = BME_cycle_length(d2); + else BME_error(); + } + #endif + + /*go ahead and add*/ + e = BME_addedgelist(bm, v1, v2, NULL); + BME_disk_append_edge(e, e->v1); + BME_disk_append_edge(e, e->v2); + + #ifndef BME_FASTEULER + /*verify disk cycle lengths*/ + d1 = BME_disk_getpointer(e, e->v1); + edok = BME_cycle_validate(valance1+1, d1); + if(!edok) BME_error(); + d2 = BME_disk_getpointer(e, e->v2); + edok = BME_cycle_validate(valance2+1, d2); + if(!edok) BME_error(); + + /*verify that edge actually made it into the cycle*/ + edok = BME_disk_hasedge(v1, e); + if(!edok) BME_error(); + edok = BME_disk_hasedge(v2, e); + if(!edok) BME_error(); + #endif + return e; +} + + + +/** + * BME_MF + * + * MAKE FACE EULER: + * Takes a list of edge pointers which form a closed loop and makes a face + * from them. The first edge in elist is considered to be the start of the + * polygon, and v1 and v2 are its vertices and determine the winding of the face + * Other than the first edge, no other assumptions are made about the order of edges + * in the elist array. To verify that it is a single closed loop and derive the correct + * order a simple series of verifications is done and all elements are visited. + * + * Returns - + * A BME_Poly pointer + */ + +#define MF_CANDIDATE 1 +#define MF_VISITED 2 +#define MF_TAKEN 4 + +BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int len) +{ + BME_Poly *f = NULL; + BME_Edge *curedge; + BME_Vert *curvert, *tv, **vlist; + int i, j, done, cont, edok; + + if(len < 2) return NULL; + + /*make sure that v1 and v2 are in elist[0]*/ + if(BME_verts_in_edge(v1,v2,elist[0]) == 0) return NULL; + + /*clear euler flags*/ + for(i=0;i<len;i++) elist[i]->eflag1=elist[i]->eflag2 = 0; + for(i=0;i<len;i++){ + elist[i]->eflag1 |= MF_CANDIDATE; + + /*if elist[i] has a loop, count its radial length*/ + if(elist[i]->loop) elist[i]->eflag2 = BME_cycle_length(&(elist[i]->loop->radial)); + else elist[i]->eflag2 = 0; + } + + /* For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it + Note that this does not gauruntee that face is a single closed loop. At best it gauruntees + that elist contains a finite number of seperate closed loops. + */ + for(i=0; i<len; i++){ + edok = BME_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0); + if(edok != 2) return NULL; + edok = BME_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0); + if(edok != 2) return NULL; + } + + /*set start edge, start vert and target vert for our loop traversal*/ + curedge = elist[0]; + tv = v1; + curvert = v2; + + if(bm->vtarlen < len){ + MEM_freeN(bm->vtar); + bm->vtar = MEM_callocN(sizeof(BME_Vert *)* len, "BMesh Vert pointer array"); + bm->vtarlen = len; + } + /*insert tv into vlist since its the first vertex in face*/ + i=0; + vlist=bm->vtar; + vlist[i] = tv; + + /* Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't + been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE + edge, loop until we find TV. We know TV is reachable because of test we did earlier. + */ + done=0; + while(!done){ + /*add curvert to vlist*/ + /*insert some error cheking here for overflows*/ + i++; + vlist[i] = curvert; + + /*mark curedge as visited*/ + curedge->eflag1 |= MF_VISITED; + + /*find next edge and vert*/ + curedge = BME_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0); + curvert = BME_edge_getothervert(curedge, curvert); + if(curvert == tv){ + curedge->eflag1 |= MF_VISITED; + done=1; + } + } + + /* Verify that all edges have been visited It's possible that we did reach tv + from sv, but that several unconnected loops were passed in via elist. + */ + cont=1; + for(i=0; i<len; i++){ + if((elist[i]->eflag1 & MF_VISITED) == 0) cont = 0; + } + + /*if we get this far, its ok to allocate the face and add the loops*/ + if(cont){ + BME_Loop *l; + BME_Edge *e; + f = BME_addpolylist(bm, NULL); + f->len = len; + for(i=0;i<len;i++){ + curvert = vlist[i]; + l = BME_create_loop(bm,curvert,NULL,f,NULL); + if(!(f->loopbase)) f->loopbase = l; + BME_cycle_append(f->loopbase, l); + } + + /*take care of edge pointers and radial cycle*/ + for(i=0, l = f->loopbase; i<len; i++, l=l->next){ + e = NULL; + if(l == f->loopbase) e = elist[0]; /*first edge*/ + + else{/*search elist for others*/ + for(j=1; j<len; j++){ + edok = BME_verts_in_edge(l->v, l->next->v, elist[j]); + if(edok){ + e = elist[j]; + break; + } + } + } + l->e = e; /*set pointer*/ + BME_radial_append(e, l); /*append into radial*/ + } + + f->len = len; + + /*Validation Loop cycle*/ + edok = BME_cycle_validate(len, f->loopbase); + if(!edok) BME_error(); + for(i=0, l = f->loopbase; i<len; i++, l=l->next){ + /*validate loop vert pointers*/ + edok = BME_verts_in_edge(l->v, l->next->v, l->e); + if(!edok) BME_error(); + /*validate the radial cycle of each edge*/ + edok = BME_cycle_length(&(l->radial)); + if(edok != (l->e->eflag2 + 1)) BME_error(); + } + } + return f; +} + +/* KILL Eulers */ + +/** + * BME_KV + * + * KILL VERT EULER: + * + * Kills a single loose vertex. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int BME_KV(BME_Mesh *bm, BME_Vert *v){ + if(v->edge == NULL){ + BLI_remlink(&(bm->verts), v); + BME_free_vert(bm,v); + return 1; + } + return 0; +} + +/** + * BME_KE + * + * KILL EDGE EULER: + * + * Kills a wire edge. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int BME_KE(BME_Mesh *bm, BME_Edge *e){ + int edok; + + /*Make sure that no faces!*/ + if(e->loop == NULL){ + BME_disk_remove_edge(e, e->v1); + BME_disk_remove_edge(e, e->v2); + + /*verify that edge out of disk*/ + edok = BME_disk_hasedge(e->v1, e); + if(edok) BME_error(); + edok = BME_disk_hasedge(e->v2, e); + if(edok) BME_error(); + + /*remove and deallocate*/ + BLI_remlink(&(bm->edges), e); + BME_free_edge(bm, e); + return 1; + } + return 0; +} + +/** + * BME_KF + * + * KILL FACE EULER: + * + * The logical inverse of BME_MF. + * Kills a face and removes each of its loops from the radial that it belongs to. + * + * Returns - + * 1 for success, 0 for failure. +*/ + +int BME_KF(BME_Mesh *bm, BME_Poly *bply){ + BME_Loop *newbase,*oldbase, *curloop; + int i,len=0; + + /*add validation to make sure that radial cycle is cleaned up ok*/ + /*deal with radial cycle first*/ + len = BME_cycle_length(bply->loopbase); + for(i=0, curloop=bply->loopbase; i < len; i++, curloop = curloop->next) + BME_radial_remove_loop(curloop, curloop->e); + + /*now deallocate the editloops*/ + for(i=0; i < len; i++){ + newbase = bply->loopbase->next; + oldbase = bply->loopbase; + BME_cycle_remove(oldbase, oldbase); + BME_free_loop(bm, oldbase); + bply->loopbase = newbase; + } + + BLI_remlink(&(bm->polys), bply); + BME_free_poly(bm, bply); + return 1; +} + +/*SPLIT Eulers*/ + +/** + * BME_SEMV + * + * SPLIT EDGE MAKE VERT: + * Takes a given edge and splits it into two, creating a new vert. + * + * + * Before: OV---------TV + * After: OV----NV---TV + * + * Returns - + * BME_Vert pointer. + * +*/ + +BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){ + BME_Vert *nv, *ov; + BME_CycleNode *diskbase; + BME_Edge *ne; + int i, edok, valance1=0, valance2=0; + + if(BME_vert_in_edge(e,tv) == 0) return NULL; + ov = BME_edge_getothervert(e,tv); + //v2 = tv; + + /*count valance of v1*/ + diskbase = BME_disk_getpointer(e, ov); + valance1 = BME_cycle_length(diskbase); + /*count valance of v2*/ + diskbase = BME_disk_getpointer(e, tv); + valance2 = BME_cycle_length(diskbase); + + nv = BME_addvertlist(bm, tv); + ne = BME_addedgelist(bm, nv, tv, e); + + //e->v2 = nv; + /*remove e from v2's disk cycle*/ + BME_disk_remove_edge(e, tv); + /*swap out tv for nv in e*/ + BME_edge_swapverts(e, tv, nv); + /*add e to nv's disk cycle*/ + BME_disk_append_edge(e, nv); + /*add ne to nv's disk cycle*/ + BME_disk_append_edge(ne, nv); + /*add ne to tv's disk cycle*/ + BME_disk_append_edge(ne, tv); + /*verify disk cycles*/ + diskbase = BME_disk_getpointer(ov->edge,ov); + edok = BME_cycle_validate(valance1, diskbase); + if(!edok) BME_error(); + diskbase = BME_disk_getpointer(tv->edge,tv); + edok = BME_cycle_validate(valance2, diskbase); + if(!edok) BME_error(); + diskbase = BME_disk_getpointer(nv->edge,nv); + edok = BME_cycle_validate(2, diskbase); + if(!edok) BME_error(); + + /*Split the radial cycle if present*/ + if(e->loop){ + BME_Loop *nl,*l; + BME_CycleNode *radEBase=NULL, *radNEBase=NULL; + int radlen = BME_cycle_length(&(e->loop->radial)); + /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/ + while(e->loop){ + l=e->loop; + l->f->len++; + BME_radial_remove_loop(l,e); + + nl = BME_create_loop(bm,NULL,NULL,l->f,l); + nl->prev = l; + nl->next = l->next; + nl->prev->next = nl; + nl->next->prev = nl; + nl->v = nv; + + /*assign the correct edge to the correct loop*/ + if(BME_verts_in_edge(nl->v, nl->next->v, e)){ + nl->e = e; + l->e = ne; + + /*append l into ne's rad cycle*/ + if(!radNEBase){ + radNEBase = &(l->radial); + radNEBase->next = NULL; + radNEBase->prev = NULL; + } + + if(!radEBase){ + radEBase = &(nl->radial); + radEBase->next = NULL; + radEBase->prev = NULL; + } + + BME_cycle_append(radEBase,&(nl->radial)); + BME_cycle_append(radNEBase,&(l->radial)); + + } + else if(BME_verts_in_edge(nl->v,nl->next->v,ne)){ + nl->e = ne; + l->e = e; + + if(!radNEBase){ + radNEBase = &(nl->radial); + radNEBase->next = NULL; + radNEBase->prev = NULL; + } + if(!radEBase){ + radEBase = &(l->radial); + radEBase->next = NULL; + radEBase->prev = NULL; + } + BME_cycle_append(radEBase,&(l->radial)); + BME_cycle_append(radNEBase,&(nl->radial)); + } + + } + + e->loop = radEBase->data; + ne->loop = radNEBase->data; + + /*verify length of radial cycle*/ + edok = BME_cycle_validate(radlen,&(e->loop->radial)); + if(!edok) BME_error(); + edok = BME_cycle_validate(radlen,&(ne->loop->radial)); + if(!edok) BME_error(); + + /*verify loop->v and loop->next->v pointers for e*/ + for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){ + if(!(l->e == e)) BME_error(); + if(!(l->radial.data == l)) BME_error(); + if(l->prev->e != ne && l->next->e != ne) BME_error(); + edok = BME_verts_in_edge(l->v, l->next->v, e); + if(!edok) BME_error(); + if(l->v == l->next->v) BME_error(); + if(l->e == l->next->e) BME_error(); + /*verify loop cycle for kloop->f*/ + edok = BME_cycle_validate(l->f->len, l->f->loopbase); + if(!edok) BME_error(); + } + /*verify loop->v and loop->next->v pointers for ne*/ + for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){ + if(!(l->e == ne)) BME_error(); + if(!(l->radial.data == l)) BME_error(); + if(l->prev->e != e && l->next->e != e) BME_error(); + edok = BME_verts_in_edge(l->v, l->next->v, ne); + if(!edok) BME_error(); + if(l->v == l->next->v) BME_error(); + if(l->e == l->next->e) BME_error(); + /*verify loop cycle for kloop->f. Redundant*/ + edok = BME_cycle_validate(l->f->len, l->f->loopbase); + if(!edok) BME_error(); + } + } + + if(re) *re = ne; + return nv; +} + +/** + * BME_SFME + * + * SPLIT FACE MAKE EDGE: + * + * Takes as input two vertices in a single face. An edge is created which divides the original face + * into two distinct regions. One of the regions is assigned to the original face and it is closed off. + * The second region has a new face assigned to it. + * + * Examples: + * + * Before: After: + * ---------- ---------- + * | | | | + * | | | f1 | + * v1 f1 v2 v1======v2 + * | | | f2 | + * | | | | + * ---------- ---------- + * + * Note that the input vertices can be part of the same edge. This will result in a two edged face. + * This is desirable for advanced construction tools and particularly essential for edge bevel. Because + * of this it is up to the caller to decide what to do with the extra edge. + * + * Returns - + * A BME_Poly pointer + */ +BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **rl){ + + BME_Poly *f2; + BME_Loop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL; + BME_Edge *e; + int i, len, f1len, f2len; + + + /*verify that v1 and v2 are in face.*/ + len = BME_cycle_length(f->loopbase); + for(i = 0, curloop = f->loopbase; i < len; i++, curloop = curloop->next){ + if(curloop->v == v1) v1loop = curloop; + else if(curloop->v == v2) v2loop = curloop; + } + + if(!v1loop || !v2loop) return NULL; + + /*allocate new edge between v1 and v2*/ + e = BME_addedgelist(bm, v1, v2,NULL); + BME_disk_append_edge(e, v1); + BME_disk_append_edge(e, v2); + + f2 = BME_addpolylist(bm,f); + f1loop = BME_create_loop(bm,v2,e,f,NULL); + f2loop = BME_create_loop(bm,v1,e,f2,NULL); + + f1loop->prev = v2loop->prev; + f2loop->prev = v1loop->prev; + v2loop->prev->next = f1loop; + v1loop->prev->next = f2loop; + + f1loop->next = v1loop; + f2loop->next = v2loop; + v1loop->prev = f1loop; + v2loop->prev = f2loop; + + f2->loopbase = f2loop; + f->loopbase = f1loop; + + /*validate both loops*/ + /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/ + + /*go through all of f2's loops and make sure they point to it properly.*/ + f2len = BME_cycle_length(f2->loopbase); + for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next) curloop->f = f2; + + /*link up the new loops into the new edges radial*/ + BME_radial_append(e, f1loop); + BME_radial_append(e, f2loop); + + + f2->len = f2len; + + f1len = BME_cycle_length(f->loopbase); + f->len = f1len; + + if(rl) *rl = f2loop; + return f2; +} + + +/** + * BME_JEKV + * + * JOIN EDGE KILL VERT: + * Takes a an edge and pointer to one of its vertices and collapses + * the edge on that vertex. + * + * Before: OE KE + * ------- ------- + * | || | + * OV KV TV + * + * + * After: OE + * --------------- + * | | + * OV TV + * + * + * Restrictions: + * KV is a vertex that must have a valance of exactly two. Furthermore + * both edges in KV's disk cycle (OE and KE) must be unique (no double + * edges). + * + * It should also be noted that this euler has the possibility of creating + * faces with just 2 edges. It is up to the caller to decide what to do with + * these faces. + * + * Returns - + * 1 for success, 0 for failure. + */ +int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv) +{ + BME_Edge *oe; + BME_Vert *ov, *tv; + BME_CycleNode *diskbase; + BME_Loop *killoop,*nextl; + int len,radlen=0, halt = 0, i, valance1, valance2,edok; + + if(BME_vert_in_edge(ke,kv) == 0) return 0; + diskbase = BME_disk_getpointer(kv->edge, kv); + len = BME_cycle_length(diskbase); + + if(len == 2){ + oe = BME_disk_nextedge(ke, kv); + tv = BME_edge_getothervert(ke, kv); + ov = BME_edge_getothervert(oe, kv); + halt = BME_verts_in_edge(kv, tv, oe); //check for double edges + + if(halt) return 0; + else{ + + /*For verification later, count valance of ov and tv*/ + diskbase = BME_disk_getpointer(ov->edge, ov); + valance1 = BME_cycle_length(diskbase); + diskbase = BME_disk_getpointer(tv->edge, tv); + valance2 = BME_cycle_length(diskbase); + + /*remove oe from kv's disk cycle*/ + BME_disk_remove_edge(oe,kv); + /*relink oe->kv to be oe->tv*/ + BME_edge_swapverts(oe, kv, tv); + /*append oe to tv's disk cycle*/ + BME_disk_append_edge(oe, tv); + /*remove ke from tv's disk cycle*/ + BME_disk_remove_edge(ke, tv); + + /*deal with radial cycle of ke*/ + if(ke->loop){ + /*first step, fix the neighboring loops of all loops in ke's radial cycle*/ + radlen = BME_cycle_length(&(ke->loop->radial)); + for(i=0,killoop = ke->loop; i<radlen; i++, killoop = BME_radial_nextloop(killoop)){ + /*relink loops and fix vertex pointer*/ + killoop->next->prev = killoop->prev; + killoop->prev->next = killoop->next; + if(killoop->next->v == kv) killoop->next->v = tv; + + /*fix len attribute of face*/ + killoop->f->len--; + if(killoop->f->loopbase == killoop) killoop->f->loopbase = killoop->next; + } + /*second step, remove all the hanging loops attached to ke*/ + killoop = ke->loop; + radlen = BME_cycle_length(&(ke->loop->radial)); + /*make sure we have enough room in bm->lpar*/ + if(bm->lparlen < radlen){ + MEM_freeN(bm->lpar); + bm->lpar = MEM_callocN(sizeof(BME_Loop *)* radlen, "BMesh Loop pointer array"); + bm->lparlen = bm->lparlen * radlen; + } + /*this should be wrapped into a bme_free_radial function to be used by BME_KF as well...*/ + i=0; + while(i<radlen){ + bm->lpar[i] = killoop; + killoop = killoop->radial.next->data; + i++; + } + i=0; + while(i<radlen){ + BME_free_loop(bm,bm->lpar[i]); + i++; + } + /*Validate radial cycle of oe*/ + edok = BME_cycle_validate(radlen,&(oe->loop->radial)); + + } + + /*Validate disk cycles*/ + diskbase = BME_disk_getpointer(ov->edge,ov); + edok = BME_cycle_validate(valance1, diskbase); + if(!edok) BME_error(); + diskbase = BME_disk_getpointer(tv->edge,tv); + edok = BME_cycle_validate(valance2, diskbase); + if(!edok) BME_error(); + + /*Validate loop cycle of all faces attached to oe*/ + for(i=0,nextl = oe->loop; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){ + edok = BME_cycle_validate(nextl->f->len,nextl->f->loopbase); + if(!edok) BME_error(); + } + /*deallocate edge*/ + BLI_remlink(&(bm->edges), ke); + BME_free_edge(bm, ke); + /*deallocate vertex*/ + BLI_remlink(&(bm->verts), kv); + BME_free_vert(bm, kv); + return 1; + } + } + return 0; +} + + +/** + * BME_loop_reverse + * + * FLIP FACE EULER + * + * Changes the winding order of a face from CW to CCW or vice versa. + * This euler is a bit peculiar in compairson to others as it is its + * own inverse. + * + * TODO: reinsert validation code. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int BME_loop_reverse(BME_Mesh *bm, BME_Poly *f){ + BME_Loop *l = f->loopbase, *curloop, *oldprev, *oldnext; + int i, j, edok, len = 0; + + len = BME_cycle_length(l); + if(bm->edarlen < len){ + MEM_freeN(bm->edar); + bm->edar = MEM_callocN(sizeof(BME_Edge *)* len, "BMesh Edge pointer array"); + bm->edarlen = len; + } + + for(i=0, curloop = l; i< len; i++, curloop=curloop->next){ + curloop->e->eflag1 = 0; + curloop->e->eflag2 = BME_cycle_length(&curloop->radial); + BME_radial_remove_loop(curloop, curloop->e); + /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/ + curloop->radial.next = curloop->radial.prev = NULL; + bm->edar[i] = curloop->e; + } + + /*actually reverse the loop. This belongs in BME_cycle_reverse!*/ + for(i=0, curloop = l; i < len; i++){ + oldnext = curloop->next; + oldprev = curloop->prev; + curloop->next = oldprev; + curloop->prev = oldnext; + curloop = oldnext; + } + + if(len == 2){ //two edged face + //do some verification here! + l->e = bm->edar[1]; + l->next->e = bm->edar[0]; + } + else{ + for(i=0, curloop = l; i < len; i++, curloop = curloop->next){ + edok = 0; + for(j=0; j < len; j++){ + edok = BME_verts_in_edge(curloop->v, curloop->next->v, bm->edar[j]); + if(edok){ + curloop->e = bm->edar[j]; + break; + } + } + } + } + /*rebuild radial*/ + for(i=0, curloop = l; i < len; i++, curloop = curloop->next) BME_radial_append(curloop->e, curloop); + + /*validate radial*/ + for(i=0, curloop = l; i < len; i++, curloop = curloop->next){ + edok = BME_cycle_validate(curloop->e->eflag2, &(curloop->radial)); + if(!edok){ + BME_error(); + } + } + return 1; +} + +/** + * BME_JFKE + * + * JOIN FACE KILL EDGE: + * + * Takes two faces joined by a single 2-manifold edge and fuses them togather. + * The edge shared by the faces must not be connected to any other edges which have + * Both faces in its radial cycle + * + * Examples: + * + * A B + * ---------- ---------- + * | | | | + * | f1 | | f1 | + * v1========v2 = Ok! v1==V2==v3 == Wrong! + * | f2 | | f2 | + * | | | | + * ---------- ---------- + * + * In the example A, faces f1 and f2 are joined by a single edge, and the euler can safely be used. + * In example B however, f1 and f2 are joined by multiple edges and will produce an error. The caller + * in this case should call BME_JEKV on the extra edges before attempting to fuse f1 and f2. + * + * Also note that the order of arguments decides whether or not certain per-face attributes are present + * in the resultant face. For instance vertex winding, material index, smooth flags, ect are inherited + * from f1, not f2. + * + * Returns - + * A BME_Poly pointer +*/ + +BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e) +{ + + BME_Loop *curloop, *f1loop=NULL, *f2loop=NULL; + int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok; + + if(f1 == f2) return NULL; //can't join a face to itself + /*verify that e is in both f1 and f2*/ + f1len = BME_cycle_length(f1->loopbase); + f2len = BME_cycle_length(f2->loopbase); + for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = curloop->next){ + if(curloop->e == e){ + f1loop = curloop; + break; + } + } + for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next){ + if(curloop->e==e){ + f2loop = curloop; + break; + } + } + if(!(f1loop && f2loop)) return NULL; + + /*validate that edge is 2-manifold edge*/ + radlen = BME_cycle_length(&(f1loop->radial)); + if(radlen != 2) return NULL; + + /*validate direction of f2's loop cycle is compatible.*/ + if(f1loop->v == f2loop->v) return NULL; + + /* + Finally validate that for each face, each vertex has another edge in its disk cycle that is + not e, and not shared. + */ + if(BME_radial_find_face(f1loop->next->e,f2)) return NULL; + if(BME_radial_find_face(f1loop->prev->e,f2)) return NULL; + if(BME_radial_find_face(f2loop->next->e,f1)) return NULL; + if(BME_radial_find_face(f2loop->prev->e,f1)) return NULL; + + /*join the two loops*/ + f1loop->prev->next = f2loop->next; + f2loop->next->prev = f1loop->prev; + + f1loop->next->prev = f2loop->prev; + f2loop->prev->next = f1loop->next; + + /*if f1loop was baseloop, give f1loop->next the base.*/ + if(f1->loopbase == f1loop) f1->loopbase = f1loop->next; + + /*validate the new loop*/ + loopok = BME_cycle_validate((f1len+f2len)-2, f1->loopbase); + if(!loopok) BME_error(); + + /*make sure each loop points to the proper face*/ + newlen = BME_cycle_length(f1->loopbase); + for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = curloop->next) curloop->f = f1; + + f1->len = newlen; + + edok = BME_cycle_validate(f1->len, f1->loopbase); + if(!edok) BME_error(); + + /*remove edge from the disk cycle of its two vertices.*/ + BME_disk_remove_edge(f1loop->e, f1loop->e->v1); + BME_disk_remove_edge(f1loop->e, f1loop->e->v2); + + /*deallocate edge and its two loops as well as f2*/ + BLI_remlink(&(bm->edges), f1loop->e); + BLI_remlink(&(bm->polys), f2); + BME_free_edge(bm, f1loop->e); + BME_free_loop(bm, f1loop); + BME_free_loop(bm, f2loop); + BME_free_poly(bm, f2); + return f1; +} diff --git a/source/blender/blenkernel/intern/BME_mesh.c b/source/blender/blenkernel/intern/BME_mesh.c new file mode 100644 index 00000000000..d9d2354ef36 --- /dev/null +++ b/source/blender/blenkernel/intern/BME_mesh.c @@ -0,0 +1,302 @@ +/** + * BME_mesh.c jan 2007 + * + * BMesh mesh level functions. + * + * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + + +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" +#include "BKE_global.h" +#include "BKE_depsgraph.h" +#include "BLI_blenlib.h" +#include "BLI_editVert.h" +#include "BIF_editmesh.h" +#include "BIF_space.h" +#include "editmesh.h" +#include "bmesh_private.h" +#include "mydevice.h" + +#include "BSE_edit.h" + + +/* + * BME MAKE MESH + * + * Allocates a new BME_Mesh structure +*/ + +BME_Mesh *BME_make_mesh(void){ + BME_Mesh *bm = MEM_callocN(sizeof(BME_Mesh),"BMesh"); + return bm; +} + +/* + * BME FREE MESH + * + * Frees a BME_Mesh structure. +*/ + +void BME_free_mesh(BME_Mesh *bm) +{ + BME_Poly *bf, *nextf; + BME_Edge *be, *nexte; + BME_Vert *bv, *nextv; + BME_CycleNode *loopref; + + /*destroy polygon data*/ + bf = bm->polys.first; + while(bf){ + nextf = bf->next; + BLI_remlink(&(bm->polys), bf); + BME_free_poly(bm, bf); + + bf = nextf; + } + /*destroy edge data*/ + be = bm->edges.first; + while(be){ + nexte = be->next; + BLI_remlink(&(bm->edges), be); + BME_free_edge(bm, be); + be = nexte; + } + /*destroy vert data*/ + bv = bm->verts.first; + while(bv){ + nextv = bv->next; + BLI_remlink(&(bm->verts), bv); + BME_free_vert(bm, bv); + bv = nextv; + } + + for(loopref=bm->loops.first;loopref;loopref=loopref->next) BME_delete_loop(bm,loopref->data); + BLI_freelistN(&(bm->loops)); + + //CustomData_free(&bm->vdata, 0); + //CustomData_free(&bm->edata, 0); + //CustomData_free(&bm->ldata, 0); + //CustomData_free(&bm->pdata, 0); + + MEM_freeN(bm); +} + +/* + * BME MODEL BEGIN AND END + * + * These two functions represent the 'point of entry' for tools. Every BMesh tool + * must begin with a call to BME_model_end() and finish with a call to BME_model_end(). + * No modification of mesh data is allowed except in between these two calls. + * + * TODO + * FOR BME_MODEL_BEGIN: + * -integrate euler undo system. + * -make full copy of structure to safely recover from errors. + * -accept a toolname string. + * -accept param to turn off full copy if just selection tool. (perhaps check for this in eulers...) + * + * BME_MODEL_END: + * -full mesh validation if debugging turned on + * -free structure copy or use it to restore. + * -do euler undo push. + * +*/ + +int BME_model_begin(BME_Mesh *bm){ + /*Initialize some scratch pointer arrays used by eulers*/ + bm->vtar = MEM_callocN(sizeof(BME_Vert *) * 1024, "BMesh scratch vert array"); + bm->edar = MEM_callocN(sizeof(BME_Edge *) * 1024, "BMesh scratch edge array"); + bm->lpar = MEM_callocN(sizeof(BME_Loop *) * 1024, "BMesh scratch loop array"); + bm->plar = MEM_callocN(sizeof(BME_Poly *) * 1024, "BMesh scratch poly array"); + + bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024; + + return 1; +} + +void BME_model_end(BME_Mesh *bm){ + int meshok, totvert, totedge, totpoly, totloop; + + totvert = BLI_countlist(&(bm->verts)); + totedge = BLI_countlist(&(bm->edges)); + totpoly = BLI_countlist(&(bm->polys)); + totloop = BLI_countlist(&(bm->loops)); + + if(bm->vtar) MEM_freeN(bm->vtar); + if(bm->edar) MEM_freeN(bm->edar); + if(bm->lpar) MEM_freeN(bm->lpar); + if(bm->plar) MEM_freeN(bm->plar); + + bm->vtar = NULL; + bm->edar = NULL; + bm->lpar = NULL; + bm->plar = NULL; + bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024; + + + if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totpoly!=totpoly || bm->totloop!=totloop) + BME_error(); + + meshok = BME_validate_mesh(bm, 1); + if(!meshok){ + BME_error(); + } +} + +/* + * BME VALIDATE MESH + * + * There are several levels of validation for meshes. At the + * Euler level, some basic validation is done to local topology. + * To catch more subtle problems however, BME_validate_mesh() is + * called by BME_model_end() whenever a tool is done executing. + * The purpose of this function is to insure that during the course + * of tool execution that nothing has been done to invalidate the + * structure, and if it has, provide a way of reporting that so that + * we can restore the proper structure from a backup. Since a full mesh + * validation would be too expensive, this is presented as a compromise. + * + * TODO + * + * -Write a full mesh validation function for debugging purposes. + */ + +#define VHALT(halt) {BME_error(); if(halt) return 0;} + +int BME_validate_mesh(struct BME_Mesh *bm, int halt) +{ + BME_Vert *v; + BME_Edge *e; + BME_Poly *f; + BME_Loop *l; + BME_CycleNode *diskbase; + int i, ok; + + /*Simple edge verification*/ + for(e=bm->edges.first; e; e=e->next){ + if(e->v1 == e->v2) VHALT(halt); + /*validate e->d1.data and e->d2.data*/ + if(e->d1.data != e || e->d2.data != e) VHALT(halt); + /*validate e->loop->e*/ + if(e->loop){ + if(e->loop->e != e) VHALT(halt); + } + } + + /*calculate disk cycle lengths*/ + for(v=bm->verts.first; v; v=v->next) v->tflag1 = v->tflag2 = 0; + for(e=bm->edges.first; e; e=e->next){ + e->v1->tflag1++; + e->v2->tflag1++; + } + /*Validate vertices and disk cycle*/ + for(v=bm->verts.first; v; v=v->next){ + /*validate v->edge pointer*/ + if(v->tflag1){ + if(v->edge){ + ok = BME_vert_in_edge(v->edge,v); + if(!ok) VHALT(halt); + /*validate length of disk cycle*/ + diskbase = BME_disk_getpointer(v->edge, v); + ok = BME_cycle_validate(v->tflag1, diskbase); + if(!ok) VHALT(halt); + /*validate that each edge in disk cycle contains V*/ + for(i=0, e=v->edge; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){ + ok = BME_vert_in_edge(e, v); + if(!ok) VHALT(halt); + } + } + else VHALT(halt); + } + } + /*validate edges*/ + for(e=bm->edges.first; e; e=e->next){ + /*seperate these into BME_disk_hasedge (takes pointer to edge)*/ + /*search v1 disk cycle for edge*/ + ok = BME_disk_hasedge(e->v1,e); + if(!ok) VHALT(halt); + /*search v2 disk cycle for edge*/ + ok = BME_disk_hasedge(e->v2,e); + if(!ok) VHALT(halt); + } + + for(e=bm->edges.first; e; e=e->next) e->tflag2 = 0; //store incident faces + /*Validate the loop cycle integrity.*/ + for(f=bm->polys.first; f; f=f->next){ + ok = BME_cycle_length(f->loopbase); + if(ok > 1){ + f->tflag1 = ok; + } + else VHALT(halt); + for(i=0, l=f->loopbase; i < f->tflag1; i++, l=l->next){ + /*verify loop->v pointers*/ + ok = BME_verts_in_edge(l->v, l->next->v, l->e); + if(!ok) VHALT(halt); + /*verify radial node data pointer*/ + if(l->radial.data != l) VHALT(halt); + /*validate l->e->loop poitner*/ + if(l->e->loop == NULL) VHALT(halt); + /*validate l->f pointer*/ + if(l->f != f) VHALT(halt); + /*see if l->e->loop is actually in radial cycle*/ + + l->e->tflag2++; + } + } + + /*validate length of radial cycle*/ + for(e=bm->edges.first; e; e=e->next){ + if(e->loop){ + ok = BME_cycle_validate(e->tflag2,&(e->loop->radial)); + if(!ok) VHALT(halt); + } + } + + /*validate that EIDs are within range... if not indicates corrupted mem*/ + + /*if we get this far, pretty safe to return 1*/ + return 1; +} + +/* Currently just a convient place for a breakpoint. + Probably should take an error string +*/ +void BME_error(void){ + printf("BME modelling error!"); +} diff --git a/source/blender/blenkernel/intern/BME_structure.c b/source/blender/blenkernel/intern/BME_structure.c new file mode 100644 index 00000000000..d283e1df5ca --- /dev/null +++ b/source/blender/blenkernel/intern/BME_structure.c @@ -0,0 +1,616 @@ +/** + * BME_structure.c jan 2007 + * + * Low level routines for manipulating the BMesh structure. + * + * $Id: BME_structure.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <limits.h> +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" +#include "BLI_blenlib.h" +#include "BLI_linklist.h" +#include "BLI_ghash.h" + +#include "BKE_customdata.h" +/** + * MISC utility functions. + * + */ + +int BME_vert_in_edge(BME_Edge *e, BME_Vert *v){ + if(e->v1 == v || e->v2 == v) return 1; + return 0; +} +int BME_verts_in_edge(BME_Vert *v1, BME_Vert *v2, BME_Edge *e){ + if(e->v1 == v1 && e->v2 == v2) return 1; + else if(e->v1 == v2 && e->v2 == v1) return 1; + return 0; +} + +BME_Vert *BME_edge_getothervert(BME_Edge *e, BME_Vert *v){ + if(e->v1 == v) return e->v2; + else if(e->v2 == v) return e->v1; + return NULL; +} + +int BME_edge_swapverts(BME_Edge *e, BME_Vert *orig, BME_Vert *new){ + if(e->v1 == orig){ + e->v1 = new; + e->d1.next = NULL; + e->d1.prev = NULL; + return 1; + } + else if(e->v2 == orig){ + e->v2 = new; + e->d2.next = NULL; + e->d2.prev = NULL; + return 1; + } + return 0; +} + +/** + * ALLOCATION/DEALLOCATION FUNCTIONS + */ + +BME_Vert *BME_addvertlist(BME_Mesh *bm, BME_Vert *example){ + BME_Vert *v=NULL; + v = MEM_callocN(sizeof(BME_Vert), "BME Vertex"); + BLI_addtail(&(bm->verts), v); + v->EID = bm->nextv; + bm->nextv++; + bm->totvert++; + + if(example) + VECCOPY(v->co,example->co); + //if(example) + // CustomData_em_copy_data(&bm->vdata, &bm->vdata, example->data, &v->data); + //else + // CustomData_em_set_default(&bm->vdata, &v->data); + + return v; +} +BME_Edge *BME_addedgelist(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge *example){ + BME_Edge *e=NULL; + e = MEM_callocN(sizeof(BME_Edge), "BME_Edge"); + e->v1 = v1; + e->v2 = v2; + e->d1.data = e; + e->d2.data = e; + e->EID = bm->nexte; + bm->nexte++; + bm->totedge++; + BLI_addtail(&(bm->edges), e); + + //if(example) + // CustomData_em_copy_data(&bm->edata, &bm->edata, example->data, &e->data); + //else + // CustomData_em_set_default(&bm->edata, &e->data); + + + return e; +} +BME_Loop *BME_create_loop(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Poly *f, BME_Loop *example){ + /*allocate a BME_Loop and add it to the loophash*/ + BME_Loop *l=NULL; + BME_CycleNode *loopnode = MEM_callocN(sizeof(BME_CycleNode),"BME Loop Reference"); + l = MEM_callocN(sizeof(BME_Loop), "BME_Loop"); + l->radial.data = l; + l->v = v; + l->e = e; + l->f = f; + l->EID = bm->nextl; + l->gref = loopnode; + loopnode->data = l; + BLI_addtail(&(bm->loops),loopnode); + bm->nextl++; + bm->totloop++; + + +/* if(example) + BME_CustomData_copy_data(&bm->ldata, &bm->ldata, example->data, &l->data); + else + BME_CustomData_set_default(&bm->ldata, &l->data); +*/ + return l; +} + +BME_Poly *BME_addpolylist(BME_Mesh *bm, BME_Poly *example){ + BME_Poly *f = NULL; + f= MEM_callocN(sizeof(BME_Poly),"BME_Poly"); + BLI_addtail(&(bm->polys),f); + f->EID = bm->nextp; + bm->nextp++; + bm->totpoly++; + + //if(example) + // CustomData_em_copy_data(&bm->pdata, &bm->pdata, example->data, &f->data); + //else + // CustomData_em_set_default(&bm->pdata, &f->data); + + + return f; +} + +/* free functions dont do much *yet*. When per-vertex, per-edge and per-face/faceloop + data is added though these will be needed. +*/ +void BME_free_vert(BME_Mesh *bm, BME_Vert *v){ + bm->totvert--; + //CustomData_em_free_block(&bm->vdata, &v->data); + MEM_freeN(v); +} +void BME_free_edge(BME_Mesh *bm, BME_Edge *e){ + bm->totedge--; + //CustomData_em_free_block(&bm->edata, &e->data); + MEM_freeN(e); +} +void BME_free_poly(BME_Mesh *bm, BME_Poly *f){ + bm->totpoly--; + //CustomData_em_free_block(&bm->pdata, &f->data); + MEM_freeN(f); +} +void BME_delete_loop(BME_Mesh *bm, BME_Loop *l){ + bm->totloop--; + //CustomData_em_free_block(&bm->ldata, &l->data); + MEM_freeN(l); +} +void BME_free_loop(BME_Mesh *bm, BME_Loop *l){ + BME_CycleNode *loopref = l->gref; + BLI_freelinkN(&(bm->loops),loopref); + BME_delete_loop(bm,l); +} + + +/** + * BMESH CYCLES + * + * Cycles are circular doubly linked lists that form the basis of adjacency + * information in the BME modeller. Full adjacency relations can be derived + * from examining these cycles very quickly. Although each cycle is a double + * circular linked list, each one is considered to have a 'base' or 'head', + * and care must be taken by Euler code when modifying the contents of a cycle. + * + * The contents of this file are split into two parts. First there are the + * BME_cycle family of functions which are generic circular double linked list + * procedures. The second part contains higher level procedures for supporting + * modification of specific cycle types. + * + * The three cycles explicitly stored in the BMesh data structure are as follows: + * + * 1: The Disk Cycle - A circle of edges around a vertex + * Base: vertex->edge pointer. + * + * This cycle is the most complicated in terms of its structure. Each BME_Edge contains + * two BME_CycleNode structures to keep track of that edge's membership in the disk cycle + * of each of its vertices. However for any given vertex it may be the first in some edges + * in its disk cycle and the second for others. The BME_disk_XXX family of functions contain + * some nice utilities for navigating disk cycles in a way that hides this detail from the + * tool writer. + * + * Note that the disk cycle is completley independant from face data. One advantage of this + * is that wire edges are fully integrated into the topology database. Another is that the + * the disk cycle has no problems dealing with non-manifold conditions involving faces. + * + * Functions relating to this cycle: + * + * BME_disk_append_edge + * BME_disk_remove_edge + * BME_disk_nextedge + * BME_disk_getpointer + * + * 2: The Radial Cycle - A circle of face edges (BME_Loop) around an edge + * Base: edge->loop->radial structure. + * + * The radial cycle is similar to the radial cycle in the radial edge data structure.* + * Unlike the radial edge however, the radial cycle does not require a large amount of memory + * to store non-manifold conditions since BMesh does not keep track of region/shell + * information. + * + * Functions relating to this cycle: + * + * BME_radial_append + * BME_radial_remove_loop + * BME_radial_nextloop + * BME_radial_find_face + * + * + * 3: The Loop Cycle - A circle of face edges around a polygon. + * Base: polygon->loopbase. + * + * The loop cycle keeps track of a faces vertices and edges. It should be noted that the + * direction of a loop cycle is either CW or CCW depending on the face normal, and is + * not oriented to the faces editedges. + * + * Functions relating to this cycle: + * + * BME_cycle_XXX family of functions. + * + * + * Note that the order of elements in all cycles except the loop cycle is undefined. This + * leads to slightly increased seek time for deriving some adjacency relations, however the + * advantage is that no intrinsic properties of the data structures are dependant upon the + * cycle order and all non-manifold conditions are represented trivially. + * +*/ + + +void BME_cycle_append(void *h, void *nt) +{ + BME_CycleNode *oldtail, *head, *newtail; + + head = (BME_CycleNode*)h; + newtail = (BME_CycleNode*)nt; + + if(head->next == NULL){ + head->next = newtail; + head->prev = newtail; + newtail->next = head; + newtail->prev = head; + } + else{ + oldtail = head->prev; + oldtail->next = newtail; + newtail->next = head; + newtail->prev = oldtail; + head->prev = newtail; + + } +} + +/** + * BME_cycle_length + * + * Count the nodes in a cycle. + * + * Returns - + * Integer + */ + +int BME_cycle_length(void *h){ + + int len = 0; + BME_CycleNode *head, *curnode; + head = (BME_CycleNode*)h; + + if(head){ + len = 1; + for(curnode = head->next; curnode != head; curnode=curnode->next){ + if(len == INT_MAX){ //check for infinite loop/corrupted cycle + return -1; + } + len++; + } + } + return len; +} + + +/** + * BME_cycle_remove + * + * Removes a node from a cycle. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int BME_cycle_remove(void *h, void *remn) +{ + int i, len; + BME_CycleNode *head, *remnode, *curnode; + + head = (BME_CycleNode*)h; + remnode = (BME_CycleNode*)remn; + len = BME_cycle_length(h); + + if(len == 1 && head == remnode){ + head->next = NULL; + head->prev = NULL; + return 1; + } + else{ + for(i=0, curnode = head; i < len; curnode = curnode->next){ + if(curnode == remnode){ + remnode->prev->next = remnode->next; + remnode->next->prev = remnode->prev; + /*zero out remnode pointers, important!*/ + //remnode->next = NULL; + //remnode->prev = NULL; + return 1; + + } + } + } + return 0; +} + +/** + * BME_cycle_validate + * + * Validates a cycle. Takes as an argument the expected length of the cycle and + * a pointer to the cycle head or base. + * + * + * Returns - + * 1 for success, 0 for failure. + */ + +int BME_cycle_validate(int len, void *h){ + int i; + BME_CycleNode *curnode, *head; + head = (BME_CycleNode*)h; + + /*forward validation*/ + for(i = 0, curnode = head; i < len; i++, curnode = curnode->next); + if(curnode != head) return 0; + + /*reverse validation*/ + for(i = 0, curnode = head; i < len; i++, curnode = curnode->prev); + if(curnode != head) return 0; + + return 1; +} + +/*Begin Disk Cycle routines*/ + +/** + * BME_disk_nextedge + * + * Find the next edge in a disk cycle + * + * Returns - + * Pointer to the next edge in the disk cycle for the vertex v. + */ + +BME_Edge *BME_disk_nextedge(BME_Edge *e, BME_Vert *v) +{ + if(BME_vert_in_edge(e, v)){ + if(e->v1 == v) return e->d1.next->data; + else if(e->v2 == v) return e->d2.next->data; + } + return NULL; +} + +/** + * BME_disk_getpointer + * + * Given an edge and one of its vertices, find the apporpriate CycleNode + * + * Returns - + * Pointer to BME_CycleNode. + */ +BME_CycleNode *BME_disk_getpointer(BME_Edge *e, BME_Vert *v){ + /*returns pointer to the cycle node for the appropriate vertex in this disk*/ + if(e->v1 == v) return &(e->d1); + else if (e->v2 == v) return &(e->d2); + return NULL; +} + +/** + * BME_disk_append_edge + * + * Appends edge to the end of a vertex disk cycle. + * + * Returns - + * 1 for success, 0 for failure + */ + +int BME_disk_append_edge(BME_Edge *e, BME_Vert *v) +{ + + BME_CycleNode *base, *tail; + + if(BME_vert_in_edge(e, v) == 0) return 0; /*check to make sure v is in e*/ + + /*check for loose vert first*/ + if(v->edge == NULL){ + v->edge = e; + base = tail = BME_disk_getpointer(e, v); + BME_cycle_append(base, tail); /*circular reference is ok!*/ + return 1; + } + + /*insert e at the end of disk cycle and make it the new v->edge*/ + base = BME_disk_getpointer(v->edge, v); + tail = BME_disk_getpointer(e, v); + BME_cycle_append(base, tail); + return 1; +} + +/** + * BME_disk_remove_edge + * + * Removes an edge from a disk cycle. If the edge to be removed is + * at the base of the cycle, the next edge becomes the new base. + * + * + * Returns - + * Nothing + */ + +void BME_disk_remove_edge(BME_Edge *e, BME_Vert *v) +{ + BME_CycleNode *base, *remnode; + BME_Edge *newbase; + int len; + + base = BME_disk_getpointer(v->edge, v); + remnode = BME_disk_getpointer(e, v); + + /*first deal with v->edge pointer...*/ + len = BME_cycle_length(base); + if(len == 1) newbase = NULL; + else if(v->edge == e) newbase = base->next-> data; + else newbase = v->edge; + + /*remove and rebase*/ + BME_cycle_remove(base, remnode); + v->edge = newbase; +} + +/** + * BME_disk_next_edgeflag + * + * Searches the disk cycle of v, starting with e, for the + * next edge that has either eflag or tflag. + * + * BME_Edge pointer. + */ + +BME_Edge *BME_disk_next_edgeflag(BME_Edge *e, BME_Vert *v, int eflag, int tflag){ + + BME_CycleNode *diskbase; + BME_Edge *curedge; + int len, ok; + + if(eflag && tflag) return NULL; + + ok = BME_vert_in_edge(e,v); + if(ok){ + diskbase = BME_disk_getpointer(e, v); + len = BME_cycle_length(diskbase); + curedge = BME_disk_nextedge(e,v); + while(curedge != e){ + if(tflag){ + if(curedge->tflag1 == tflag) return curedge; + } + else if(eflag){ + if(curedge->eflag1 == eflag) return curedge; + } + curedge = BME_disk_nextedge(curedge, v); + } + } + return NULL; +} + +/** + * BME_disk_count_edgeflag + * + * Counts number of edges in this verts disk cycle which have + * either eflag or tflag (but not both!) + * + * Returns - + * Integer. + */ + +int BME_disk_count_edgeflag(BME_Vert *v, int eflag, int tflag){ + BME_CycleNode *diskbase; + BME_Edge *curedge; + int i, len=0, count=0; + + if(v->edge){ + if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/ + diskbase = BME_disk_getpointer(v->edge, v); + len = BME_cycle_length(diskbase); + + for(i = 0, curedge=v->edge; i<len; i++){ + if(tflag){ + if(curedge->tflag1 == tflag) count++; + } + else if(eflag){ + if(curedge->eflag1 == eflag) count++; + } + curedge = BME_disk_nextedge(curedge, v); + } + } + return count; +} + +int BME_disk_hasedge(BME_Vert *v, BME_Edge *e){ + BME_CycleNode *diskbase; + BME_Edge *curedge; + int i, len=0; + + if(v->edge){ + diskbase = BME_disk_getpointer(v->edge,v); + len = BME_cycle_length(diskbase); + + for(i = 0, curedge=v->edge; i<len; i++){ + if(curedge == e) return 1; + else curedge=BME_disk_nextedge(curedge, v); + } + } + return 0; +} +/*end disk cycle routines*/ + +BME_Loop *BME_radial_nextloop(BME_Loop *l){ + return (BME_Loop*)(l->radial.next->data); +} + +void BME_radial_append(BME_Edge *e, BME_Loop *l){ + if(e->loop == NULL) e->loop = l; + BME_cycle_append(&(e->loop->radial), &(l->radial)); +} + +void BME_radial_remove_loop(BME_Loop *l, BME_Edge *e) +{ + BME_Loop *newbase; + int len; + + /*deal with edge->loop pointer*/ + len = BME_cycle_length(&(e->loop->radial)); + if(len == 1) newbase = NULL; + else if(e->loop == l) newbase = e->loop->radial.next->data; + else newbase = e->loop; + + /*remove and rebase*/ + BME_cycle_remove(&(e->loop->radial), &(l->radial)); + e->loop = newbase; +} + +int BME_radial_find_face(BME_Edge *e,BME_Poly *f) +{ + + BME_Loop *curloop; + int i, len; + + len = BME_cycle_length(&(e->loop->radial)); + for(i = 0, curloop = e->loop; i < len; i++, curloop = curloop->radial.next->data){ + if(curloop->f == f) return 1; + } + return 0; +} + +struct BME_Loop *BME_loop_find_loop(struct BME_Poly *f, struct BME_Vert *v) { + BME_Loop *l; + int i, len; + + len = BME_cycle_length(f->loopbase); + for (i = 0, l=f->loopbase; i < len; i++, l=l->next) { + if (l->v == v) return l; + } + return NULL; +} diff --git a/source/blender/blenkernel/intern/BME_tools.c b/source/blender/blenkernel/intern/BME_tools.c new file mode 100644 index 00000000000..90fa9793644 --- /dev/null +++ b/source/blender/blenkernel/intern/BME_tools.c @@ -0,0 +1,1209 @@ +/** + * BME_tools.c jan 2007 + * + * Functions for changing the topology of a mesh. + * + * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle and Levi Schooley. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "blendef.h" + +/*split this all into a seperate bevel.c file in src*/ + +/* ------- Bevel code starts here -------- */ + +BME_TransData_Head *BME_init_transdata(int bufsize) { + BME_TransData_Head *td; + + td = MEM_callocN(sizeof(BME_TransData_Head), "BMesh transdata header"); + td->gh = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp); + td->ma = BLI_memarena_new(bufsize); + BLI_memarena_use_calloc(td->ma); + + return td; +} + +void BME_free_transdata(BME_TransData_Head *td) { + BLI_ghash_free(td->gh,NULL,NULL); + BLI_memarena_free(td->ma); + MEM_freeN(td); +} + +BME_TransData *BME_assign_transdata(BME_TransData_Head *td, BME_Mesh *bm, BME_Vert *v, + float *co, float *org, float *vec, float *loc, + float factor, float weight, float maxfactor, float *max) { + BME_TransData *vtd; + int is_new = 0; + + if (v == NULL) return NULL; + + if ((vtd = BLI_ghash_lookup(td->gh, v)) == NULL && bm != NULL) { + vtd = BLI_memarena_alloc(td->ma, sizeof(*vtd)); + BLI_ghash_insert(td->gh, v, vtd); + td->len++; + is_new = 1; + } + + vtd->bm = bm; + vtd->v = v; + if (co != NULL) VECCOPY(vtd->co,co); + if (org == NULL && is_new) { VECCOPY(vtd->org,v->co); } /* default */ + else if (org != NULL) VECCOPY(vtd->org,org); + if (vec != NULL) { + VECCOPY(vtd->vec,vec); + Normalize(vtd->vec); + } + vtd->loc = loc; + + vtd->factor = factor; + vtd->weight = weight; + vtd->maxfactor = maxfactor; + vtd->max = max; + + return vtd; +} + +BME_TransData *BME_get_transdata(BME_TransData_Head *td, BME_Vert *v) { + BME_TransData *vtd; + vtd = BLI_ghash_lookup(td->gh, v); + return vtd; +} + +/* a hack (?) to use the transdata memarena to allocate floats for use with the max limits */ +float *BME_new_transdata_float(BME_TransData_Head *td) { + return BLI_memarena_alloc(td->ma, sizeof(float)); +} + +static int BME_is_nonmanifold_vert(BME_Mesh *bm, BME_Vert *v) { + BME_Edge *e, *oe; + BME_Loop *l; + int len, count, flag; + + if (v->edge == NULL) { + /* loose vert */ + return 1; + } + + /* count edges while looking for non-manifold edges */ + oe = v->edge; + for (len=0,e=v->edge; e != oe || (e == oe && len == 0); len++,e=BME_disk_nextedge(e,v)) { + if (e->loop == NULL) { + /* loose edge */ + return 1; + } + + if (BME_cycle_length(&(e->loop->radial)) > 2) { + /* edge shared by more than two faces */ + return 1; + } + } + + count = 1; + flag = 1; + e = NULL; + oe = v->edge; + l = oe->loop; + while(e != oe) { + if (l->v == v) l = l->prev; + else l = l->next; + e = l->e; + count++; /* count the edges */ + + if (flag && l->radial.next->data == l) { + /* we've hit the edge of an open mesh, reset once */ + flag = 0; + count = 1; + oe = e; + e = NULL; + l = oe->loop; + } + else if (l->radial.next->data == l) { + /* break the loop */ + e = oe; + } + else { + l = l->radial.next->data; + } + } + + if (count < len) { + /* vert shared by multiple regions */ + return 1; + } + + return 0; +} + +/* a wrapper for BME_JFKE that [for now just] checks to + * make sure loop directions are compatible */ +static BME_Poly *BME_JFKE_safe(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e) { + BME_Loop *l1, *l2; + + l1 = e->loop; + l2 = l1->radial.next->data; + if (l1->v == l2->v) { + BME_loop_reverse(bm, f2); + } + + return BME_JFKE(bm, f1, f2, e); +} + +/* a wrapper for BME_SFME that transfers element flags */ +static BME_Poly *BME_split_face(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **nl, BME_Edge *example) { + BME_Poly *nf; + nf = BME_SFME(bm,f,v1,v2,nl); + nf->flag = f->flag; + /* if the edge was selected, select this face, too */ + if (example->flag & SELECT) f->flag |= ME_FACE_SEL; + nf->h = f->h; + nf->mat_nr = f->mat_nr; + if (nl && example) { + (*nl)->e->flag = example->flag; + (*nl)->e->h = example->h; + (*nl)->e->crease = example->crease; + (*nl)->e->bweight = example->bweight; + } + + return nf; +} + +/* a wrapper for BME_SEMV that transfers element flags */ +static BME_Vert *BME_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Edge **ne, float percent) { + BME_Vert *nv, *v2; + float len; + + v2 = BME_edge_getothervert(e,v); + nv = BME_SEMV(bm,v,e,ne); + if (nv == NULL) return NULL; + VECSUB(nv->co,v2->co,v->co); + len = VecLength(nv->co); + VECADDFAC(nv->co,v->co,nv->co,len*percent); + nv->flag = v->flag; + nv->bweight = v->bweight; + if (ne) { + (*ne)->flag = e->flag; + (*ne)->h = e->h; + (*ne)->crease = e->crease; + (*ne)->bweight = e->bweight; + } + + return nv; +} + +static int BME_bevel_is_split_vert(BME_Loop *l) { + /* look for verts that have already been added to the edge when + * beveling other polys; this can be determined by testing the + * vert and the edges around it for originality + */ + if ((l->v->tflag1 & BME_BEVEL_ORIG)==0 + && (l->e->tflag1 & BME_BEVEL_ORIG) + && (l->prev->e->tflag1 & BME_BEVEL_ORIG)) + { + return 1; + } + return 0; +} + +/* get a vector, vec, that points from v1->co to wherever makes sense to + * the bevel operation as a whole based on the relationship between v1 and v2 + * (won't necessarily be a vec from v1->co to v2->co, though it probably will be); + * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */ +static int BME_bevel_get_vec(float *vec, BME_Vert *v1, BME_Vert *v2, BME_TransData_Head *td) { + BME_TransData *vtd1, *vtd2; + + vtd1 = BME_get_transdata(td,v1); + vtd2 = BME_get_transdata(td,v2); + if (!vtd1 || !vtd2) { + //printf("BME_bevel_get_vec() got called without proper BME_TransData\n"); + return -1; + } + + /* compare the transform origins to see if we can use the vert co's; + * if they belong to different origins, then we will use the origins to determine + * the vector */ + if (VecCompare(vtd1->org,vtd2->org,0.000001f)) { + VECSUB(vec,v2->co,v1->co); + if (VecLength(vec) < 0.000001f) { + VecMulf(vec,0); + } + return 0; + } + else { + VECSUB(vec,vtd2->org,vtd1->org); + if (VecLength(vec) < 0.000001f) { + VecMulf(vec,0); + } + return 1; + } +} + +/* "Projects" a vector perpendicular to vec2 against vec1, such that + * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2. + * note: the direction, is_forward, is used in conjunction with up_vec to determine + * whether this is a convex or concave corner. If it is a concave corner, it will + * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards). + * vec1 is the vector to project onto (expected to be normalized) + * vec2 is the direction of projection (pointing away from vec1) + * up_vec is used for orientation (expected to be normalized) + * returns the length of the projected vector that lies along vec1 */ +static float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *td) { + float factor, vec3[3], tmp[3],c1,c2; + + Crossf(tmp,vec1,vec2); + Normalize(tmp); + factor = Inpf(up_vec,tmp); + if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) { + Crossf(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */ + } + else { + Crossf(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */ + } + Normalize(vec3); + c1 = Inpf(vec3,vec1); + c2 = Inpf(vec1,vec1); + if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) { + factor = 0.0f; + } + else { + factor = c2/c1; + } + + return factor; +} + +/* BME_bevel_split_edge() is the main math work-house; its responsibilities are: + * using the vert and the loop passed, get or make the split vert, set its coordinates + * and transform properties, and set the max limits. + * Finally, return the split vert. */ +static BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, BME_Loop *l, float *up_vec, float value, BME_TransData_Head *td) { + BME_TransData *vtd, *vtd1, *vtd2; + BME_Vert *sv, *v2, *v3; + BME_Loop *lv1, *lv2; + BME_Edge *ne, *e1, *e2; + float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3]; + int is_edge, forward, is_split_vert; + + if (l == NULL) { + /* what you call operator overloading in C :) + * I wanted to use the same function for both wire edges and poly loops + * so... here we walk around edges to find the needed verts */ + forward = 1; + is_split_vert = 0; + if (v->edge == NULL) { + //printf("We can't split a loose vert's edge!\n"); + return NULL; + } + e1 = v->edge; /* we just use the first two edges */ + e2 = BME_disk_nextedge(v->edge, v); + if (e1 == e2) { + //printf("You need at least two edges to use BME_bevel_split_edge()\n"); + return NULL; + } + v2 = BME_edge_getothervert(e1, v); + v3 = BME_edge_getothervert(e2, v); + if (v1 != v2 && v1 != v3) { + //printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n"); + return NULL; + } + if (v1 == v2) { + v2 = v3; + } + else { + e1 = e2; + } + sv = BME_split_edge(bm,v,e1,&ne,0); + BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ + sv->tflag1 |= BME_BEVEL_BEVEL; + ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ + BME_bevel_get_vec(vec1,v1,v,td); + BME_bevel_get_vec(vec2,v2,v,td); + Crossf(t_up_vec,vec1,vec2); + Normalize(t_up_vec); + up_vec = t_up_vec; + } + else { + /* establish loop direction */ + if (l->v == v) { + forward = 1; + lv1 = l->next; + lv2 = l->prev; + v1 = l->next->v; + v2 = l->prev->v; + } + else if (l->next->v == v) { + forward = 0; + lv1 = l; + lv2 = l->next->next; + v1 = l->v; + v2 = l->next->next->v; + } + else { + //printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n"); + return NULL; + } + + if (BME_bevel_is_split_vert(lv1)) { + is_split_vert = 1; + sv = v1; + if (forward) v1 = l->next->next->v; + else v1 = l->prev->v; + } + else { + is_split_vert = 0; + sv = BME_split_edge(bm,v,l->e,&ne,0); + BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ + sv->tflag1 |= BME_BEVEL_BEVEL; + ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ + } + + if (BME_bevel_is_split_vert(lv2)) { + if (forward) v2 = lv2->prev->v; + else v2 = lv2->next->v; + } + } + + is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */ + BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */ + len = VecLength(vec1); + Normalize(vec1); + + vtd = BME_get_transdata(td, sv); + vtd1 = BME_get_transdata(td, v); + vtd2 = BME_get_transdata(td,v1); + + if (vtd1->loc == NULL) { + /* this is a vert with data only for calculating initial weights */ + if (vtd1->weight < 0) { + vtd1->weight = 0; + } + scale = vtd1->weight/vtd1->factor; + if (!vtd1->max) { + vtd1->max = BME_new_transdata_float(td); + *vtd1->max = -1; + } + } + else { + scale = vtd1->weight; + } + vtd->max = vtd1->max; + + if (is_edge && vtd1->loc != NULL) { + maxfactor = vtd1->maxfactor; + } + else { + maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td); + if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) { + maxfactor = vtd->maxfactor; + } + } + + dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2; + if (is_edge || dis > maxfactor*value) { + dis = maxfactor*value; + } + VECADDFAC(sv->co,v->co,vec1,dis); + VECSUB(vec1,sv->co,vtd1->org); + dis = VecLength(vec1); + Normalize(vec1); + BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max); + + return sv; +} + +static float BME_bevel_set_max(BME_Vert *v1, BME_Vert *v2, float value, BME_TransData_Head *td) { + BME_TransData *vtd1, *vtd2; + float max, fac1, fac2, vec1[3], vec2[3], vec3[3]; + + BME_bevel_get_vec(vec1,v1,v2,td); + vtd1 = BME_get_transdata(td,v1); + vtd2 = BME_get_transdata(td,v2); + + if (vtd1->loc == NULL) { + fac1 = 0; + } + else { + VECCOPY(vec2,vtd1->vec); + VecMulf(vec2,vtd1->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec2,vec1); + fac1 = VecLength(vec2)/value; + } + else { + fac1 = 0; + } + } + + if (vtd2->loc == NULL) { + fac2 = 0; + } + else { + VECCOPY(vec3,vtd2->vec); + VecMulf(vec3,vtd2->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec3,vec1); + fac2 = VecLength(vec2)/value; + } + else { + fac2 = 0; + } + } + + if (fac1 || fac2) { + max = VecLength(vec1)/(fac1 + fac2); + if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) { + *vtd1->max = max; + } + if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) { + *vtd2->max = max; + } + } + else { + max = -1; + } + + return max; +} + +static BME_Vert *BME_bevel_wire(BME_Mesh *bm, BME_Vert *v, float value, int res, int options, BME_TransData_Head *td) { + BME_Vert *ov1, *ov2, *v1, *v2; + + ov1 = BME_edge_getothervert(v->edge, v); + ov2 = BME_edge_getothervert(BME_disk_nextedge(v->edge, v), v); + + /* split the edges */ + v1 = BME_bevel_split_edge(bm,v,ov1,NULL,NULL,value,td); + v1->tflag1 |= BME_BEVEL_NONMAN; + v2 = BME_bevel_split_edge(bm,v,ov2,NULL,NULL,value,td); + v2->tflag1 |= BME_BEVEL_NONMAN; + + if (value > 0.5) { + BME_bevel_set_max(v1,ov1,value,td); + BME_bevel_set_max(v2,ov2,value,td); + } + + /* remove the original vert */ + if (res) { + BME_JEKV(bm,v->edge,v); + } + + return v1; +} + +static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int options, float *up_vec, BME_TransData_Head *td) { + BME_Vert *v1, *v2, *kv; + BME_Loop *kl=NULL, *nl; + BME_Edge *e; + BME_Poly *f; + + f = l->f; + e = l->e; + + if ((l->e->tflag1 & BME_BEVEL_BEVEL) == 0 + && ((l->v->tflag1 & BME_BEVEL_BEVEL) || (l->next->v->tflag1 & BME_BEVEL_BEVEL))) + { /* sanity check */ + return l; + } + + /* checks and operations for prev edge */ + /* first, check to see if this edge was inset previously */ + if ((l->prev->e->tflag1 & BME_BEVEL_ORIG) == 0 + && (l->v->tflag1 & BME_BEVEL_NONMAN) == 0) { + kl = l->prev->radial.next->data; + if (kl->v == l->v) kl = kl->prev; + else kl = kl->next; + kv = l->v; + } + else { + kv = NULL; + } + /* get/make the first vert to be used in SFME */ + if (l->v->tflag1 & BME_BEVEL_NONMAN){ + v1 = l->v; + } + else { /* we'll need to split the previous edge */ + v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td); + } + /* if we need to clean up geometry... */ + if (kv) { + l = l->next; + if (kl->v == kv) { + BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e); + BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e); + BME_JEKV(bm,kl->e,kv); + } + else { + BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e); + BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e); + BME_JEKV(bm,kl->e,kv); + } + l = l->prev; + } + + /* checks and operations for the next edge */ + /* first, check to see if this edge was inset previously */ + if ((l->next->e->tflag1 & BME_BEVEL_ORIG) == 0 + && (l->next->v->tflag1 & BME_BEVEL_NONMAN) == 0) { + kl = l->next->radial.next->data; + if (kl->v == l->next->v) kl = kl->prev; + else kl = kl->next; + kv = l->next->v; + } + else { + kv = NULL; + } + /* get/make the second vert to be used in SFME */ + if (l->next->v->tflag1 & BME_BEVEL_NONMAN) { + v2 = l->next->v; + } + else { /* we'll need to split the next edge */ + v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td); + } + /* if we need to clean up geometry... */ + if (kv) { + if (kl->v == kv) { + BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e); + BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e); + BME_JEKV(bm,kl->e,kv); + } + else { + BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e); + BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e); + BME_JEKV(bm,kl->e,kv); + } + } + + if ((v1->tflag1 & BME_BEVEL_NONMAN)==0 || (v2->tflag1 & BME_BEVEL_NONMAN)==0) { + BME_split_face(bm,f,v2,v1,&l,e); + l->e->tflag1 = BME_BEVEL_BEVEL; + l = l->radial.next->data; + } + + if (l->f != f){ + //printf("Whoops! You got something out of order in BME_bevel_edge()!\n"); + } + + return l; +} + +static BME_Loop *BME_bevel_vert(BME_Mesh *bm, BME_Loop *l, float value, int options, float *up_vec, BME_TransData_Head *td) { + BME_Vert *v1, *v2; + BME_Poly *f; + + /* get/make the first vert to be used in SFME */ + /* may need to split the previous edge */ + v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td); + + /* get/make the second vert to be used in SFME */ + /* may need to split this edge (so move l) */ + l = l->prev; + v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td); + l = l->next->next; + + /* "cut off" this corner */ + f = BME_split_face(bm,l->f,v2,v1,NULL,l->e); + + return l; +} + +/** + * BME_bevel_poly + * + * Polygon inset tool: + * + * Insets a polygon/face based on the tflag1's of its vertices + * and edges. Used by the bevel tool only, for now. + * The parameter "value" is the distance to inset (should be negative). + * The parameter "options" is not currently used. + * + * Returns - + * A BME_Poly pointer to the resulting inner face. +*/ +static BME_Poly *BME_bevel_poly(BME_Mesh *bm, BME_Poly *f, float value, int options, BME_TransData_Head *td) { + BME_Loop *l, *ol; + BME_TransData *vtd1, *vtd2; + float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1; + int len, i; + + up_vec[0] = 0.0f; + up_vec[1] = 0.0f; + up_vec[2] = 0.0f; + /* find a good normal for this face (there's better ways, I'm sure) */ + ol = f->loopbase; + l = ol->next; + for (i=0,ol=f->loopbase,l=ol->next; l->next!=ol; l=l->next) { + BME_bevel_get_vec(vec1,l->next->v,ol->v,td); + BME_bevel_get_vec(vec2,l->v,ol->v,td); + Crossf(vec3,vec2,vec1); + VECADD(up_vec,up_vec,vec3); + i++; + } + VecMulf(up_vec,1.0f/i); + Normalize(up_vec); + + for (i=0,len=f->len; i<len; i++,l=l->next) { + if ((l->e->tflag1 & BME_BEVEL_BEVEL) && (l->e->tflag1 & BME_BEVEL_ORIG)) { + max = 1.0f; + l = BME_bevel_edge(bm, l, value, options, up_vec, td); + } + else if ((l->v->tflag1 & BME_BEVEL_BEVEL) && (l->v->tflag1 & BME_BEVEL_ORIG) && (l->prev->e->tflag1 & BME_BEVEL_BEVEL) == 0) { + max = 1.0f; + l = BME_bevel_vert(bm, l, value, options, up_vec, td); + } + } + + /* max pass */ + if (value > 0.5 && max > 0) { + max = -1; + for (i=0,len=f->len; i<len; i++,l=l->next) { + if ((l->e->tflag1 & BME_BEVEL_BEVEL) || (l->e->tflag1 & BME_BEVEL_ORIG)) { + BME_bevel_get_vec(vec1,l->v,l->next->v,td); + vtd1 = BME_get_transdata(td,l->v); + vtd2 = BME_get_transdata(td,l->next->v); + if (vtd1->loc == NULL) { + fac1 = 0; + } + else { + VECCOPY(vec2,vtd1->vec); + VecMulf(vec2,vtd1->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec2,vec1); + fac1 = VecLength(vec2)/value; + } + else { + fac1 = 0; + } + } + if (vtd2->loc == NULL) { + fac2 = 0; + } + else { + VECCOPY(vec3,vtd2->vec); + VecMulf(vec3,vtd2->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec3,vec1); + fac2 = VecLength(vec2)/value; + } + else { + fac2 = 0; + } + } + if (fac1 || fac2) { + max = VecLength(vec1)/(fac1 + fac2); + if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) { + *vtd1->max = max; + } + if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) { + *vtd2->max = max; + } + } + } + } + } + + return l->f; +} + +static void BME_bevel_add_vweight(BME_TransData_Head *td, BME_Mesh *bm, BME_Vert *v, float weight, float factor, int options) { + BME_TransData *vtd; + + if (v->tflag1 & BME_BEVEL_NONMAN) return; + v->tflag1 |= BME_BEVEL_BEVEL; + if ( (vtd = BME_get_transdata(td, v)) ) { + if (options & BME_BEVEL_EMIN) { + vtd->factor = 1.0; + if (vtd->weight < 0 || weight < vtd->weight) { + vtd->weight = weight; + } + } + else if (options & BME_BEVEL_EMAX) { + vtd->factor = 1.0; + if (weight > vtd->weight) { + vtd->weight = weight; + } + } + else if (vtd->weight < 0) { + vtd->factor = factor; + vtd->weight = weight; + } + else { + vtd->factor += factor; /* increment number of edges with weights (will be averaged) */ + vtd->weight += weight; /* accumulate all the weights */ + } + } + else { + /* we'll use vtd->loc == NULL to mark that this vert is not moving */ + vtd = BME_assign_transdata(td, bm, v, v->co, NULL, NULL, NULL, factor, weight, -1, NULL); + } +} + +static float BME_bevel_get_angle(BME_Mesh *bm, BME_Edge *e, BME_Vert *v) { + BME_Vert *v1, *v2; + BME_Loop *l1, *l2; + float vec1[3], vec2[3], vec3[3], vec4[3]; + + l1 = e->loop; + l2 = e->loop->radial.next->data; + if (l1->v == v) { + v1 = l1->prev->v; + v2 = l1->next->v; + } + else { + v1 = l1->next->next->v; + v2 = l1->v; + } + VECSUB(vec1,v1->co,v->co); + VECSUB(vec2,v2->co,v->co); + Crossf(vec3,vec1,vec2); + + l1 = l2; + if (l1->v == v) { + v1 = l1->prev->v; + v2 = l1->next->v; + } + else { + v1 = l1->next->next->v; + v2 = l1->v; + } + VECSUB(vec1,v1->co,v->co); + VECSUB(vec2,v2->co,v->co); + Crossf(vec4,vec2,vec1); + + Normalize(vec3); + Normalize(vec4); + + return Inpf(vec3,vec4); +} + +/** + * BME_bevel_initialize + * + * Prepare the mesh for beveling: + * + * Sets the tflag1's of the mesh elements based on the options passed. + * + * Returns - + * A BME_Mesh pointer to the BMesh passed as a parameter. +*/ +static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int defgrp_index, float angle, BME_TransData_Head *td) { + BME_Vert *v; + BME_Edge *e; + BME_Poly *f; + BME_TransData *vtd; + MDeformVert *dvert; + MDeformWeight *dw; + int len; + float weight, threshold; + + /* vert pass */ + for (v=bm->verts.first; v; v=v->next) { + dvert = NULL; + dw = NULL; + v->tflag1 = BME_BEVEL_ORIG; + /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if + * the vert is manifold (or is shared by only two edges - wire bevel) + * BME_BEVEL_SELECT is passed and the vert has v->flag&SELECT or + * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight + * BME_BEVEL_ANGLE is not passed + * BME_BEVEL_EWEIGHT is not passed + */ + /* originally coded, a vertex gets tagged with BME_BEVEL_NONMAN in this pass if + * the vert is loose, shared by multiple regions, or is shared by wire edges + * note: verts belonging to edges of open meshes are not tagged with BME_BEVEL_NONMAN + */ + /* originally coded, a vertex gets a transform weight set in this pass if + * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight + */ + + /* get disk cycle length */ + if (v->edge == NULL) { + len = 0; + } + else { + len = BME_cycle_length(BME_disk_getpointer(v->edge,v)); + /* we'll assign a default transform data to every vert (except the loose ones) */ + vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL); + } + + /* check for non-manifold vert */ + if (BME_is_nonmanifold_vert(bm,v)) { + v->tflag1 |= BME_BEVEL_NONMAN; + } + + /* BME_BEVEL_BEVEL tests */ + if ((v->tflag1 & BME_BEVEL_NONMAN) == 0 || len == 2) { /* either manifold vert, or wire vert */ + if (((options & BME_BEVEL_SELECT) && (v->flag & SELECT)) + || ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT)) /* use weights for verts */ + || ((options & BME_BEVEL_ANGLE) == 0 + && (options & BME_BEVEL_SELECT) == 0 + && (options & BME_BEVEL_WEIGHT) == 0)) + { + if (options & BME_BEVEL_WEIGHT) { + /* do vert weight stuff */ + //~ dvert = CustomData_em_get(&bm->vdata,v->data,CD_MDEFORMVERT); + //~ if (!dvert) continue; + //~ for (i = 0; i < dvert->totweight; ++i) { + //~ if(dvert->dw[i].def_nr == defgrp_index) { + //~ dw = &dvert->dw[i]; + //~ break; + //~ } + //~ } + //~ if (!dw || dw->weight == 0.0) continue; + if (v->bweight == 0.0) continue; + vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, v->bweight, -1, NULL); + v->tflag1 |= BME_BEVEL_BEVEL; + } + else { + vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, 1.0, -1, NULL); + v->tflag1 |= BME_BEVEL_BEVEL; + } + } + } + } + + /* edge pass */ + threshold = (float)cos((angle + 0.00001) * M_PI / 180.0); + for (e=bm->edges.first; e; e=e->next) { + e->tflag1 = BME_BEVEL_ORIG; + weight = 0.0; + /* originally coded, an edge gets tagged with BME_BEVEL_BEVEL in this pass if + * BME_BEVEL_VERT is not set + * the edge is manifold (shared by exactly two faces) + * BME_BEVEL_SELECT is passed and the edge has e->flag&SELECT or + * BME_BEVEL_EWEIGHT is passed, and the edge has the crease set or + * BME_BEVEL_ANGLE is passed, and the edge is sharp enough + * BME_BEVEL_VWEIGHT is passed, and both verts are set for bevel + */ + /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if + * the vert belongs to the edge + * the vert is not tagged with BME_BEVEL_NONMAN + * the edge is eligible for bevel (even if BME_BEVEL_VERT is set, or the edge is shared by less than 2 faces) + */ + /* originally coded, a vertex gets a transform weight set in this pass if + * the vert belongs to the edge + * the edge has a weight + */ + /* note: edge weights are cumulative at the verts, + * i.e. the vert's weight is the average of the weights of its weighted edges + */ + + if (e->loop == NULL) { + len = 0; + e->v1->tflag1 |= BME_BEVEL_NONMAN; + e->v2->tflag1 |= BME_BEVEL_NONMAN; + } + else { + len = BME_cycle_length(&(e->loop->radial)); + } + + if (len > 2) { + /* non-manifold edge of the worst kind */ + continue; + } + + if ((options & BME_BEVEL_SELECT) && (e->flag & SELECT)) { + weight = 1.0; + /* stupid editmode doesn't always flush selections, or something */ + e->v1->flag |= SELECT; + e->v2->flag |= SELECT; + } + else if ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT) == 0) { + weight = e->bweight; + } + else if (options & BME_BEVEL_ANGLE) { + if ((e->v1->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v1) < threshold) { + e->tflag1 |= BME_BEVEL_BEVEL; + e->v1->tflag1 |= BME_BEVEL_BEVEL; + BME_bevel_add_vweight(td, bm, e->v1, 1.0, 1.0, options); + } + else { + BME_bevel_add_vweight(td, bm, e->v1, 0.0, 1.0, options); + } + if ((e->v2->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v2) < threshold) { + e->tflag1 |= BME_BEVEL_BEVEL; + e->v2->tflag1 |= BME_BEVEL_BEVEL; + BME_bevel_add_vweight(td, bm, e->v2, 1.0, 1.0, options); + } + else { + BME_bevel_add_vweight(td, bm, e->v2, 0.0, 1.0, options); + } + } + //~ else if ((options & BME_BEVEL_VWEIGHT) && (options & BME_BEVEL_VERT) == 0) { + //~ if ((e->v1->tflag1 & BME_BEVEL_BEVEL) && (e->v2->tflag1 & BME_BEVEL_BEVEL)) { + //~ e->tflag1 |= BME_BEVEL_BEVEL; + //~ } + //~ } + else if ((options & BME_BEVEL_SELECT) == 0 + && (options & BME_BEVEL_VERT) == 0) + { + weight = 1.0; + } + + if (weight > 0.0) { + e->tflag1 |= BME_BEVEL_BEVEL; + BME_bevel_add_vweight(td, bm, e->v1, weight, 1.0, options); + BME_bevel_add_vweight(td, bm, e->v2, weight, 1.0, options); + } + + if (len != 2 || options & BME_BEVEL_VERT) { + e->tflag1 &= ~BME_BEVEL_BEVEL; + } + } + + /* face pass */ + for (f=bm->polys.first; f; f=f->next) f->tflag1 = BME_BEVEL_ORIG; + + return bm; +} + +/* tags all elements as originals */ +static BME_Mesh *BME_bevel_reinitialize(BME_Mesh *bm) { + BME_Vert *v; + BME_Edge *e; + BME_Poly *f; + + for (v = bm->verts.first; v; v=v->next) { + v->tflag1 |= BME_BEVEL_ORIG; + } + + for (e=bm->edges.first; e; e=e->next) { + e->tflag1 |= BME_BEVEL_ORIG; + } + + for (f=bm->polys.first; f; f=f->next) { + f->tflag1 |= BME_BEVEL_ORIG; + } + + return bm; +} + +/** + * BME_bevel_mesh + * + * Mesh beveling tool: + * + * Bevels an entire mesh. It currently uses the tflag1's of + * its vertices and edges to track topological changes. + * The parameter "value" is the distance to inset (should be negative). + * The parameter "options" is not currently used. + * + * Returns - + * A BME_Mesh pointer to the BMesh passed as a parameter. +*/ + +static void bmesh_dissolve_disk(BME_Mesh *bm, BME_Vert *v){ + BME_Poly *f; + BME_Edge *e; + int done, len; + + if(v->edge){ + done = 0; + while(!done){ + done = 1; + e = v->edge; /*loop the edge looking for a edge to dissolve*/ + do{ + f = NULL; + len = BME_cycle_length(&(e->loop->radial)); + if(len == 2){ + f = BME_JFKE_safe(bm,e->loop->f, ((BME_Loop*)(e->loop->radial.next->data))->f, e); + } + if(f){ + done = 0; + break; + } + e = BME_disk_nextedge(e,v); + }while(e != v->edge); + } + BME_JEKV(bm,v->edge,v); + } +} +static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options, int defgrp_index, BME_TransData_Head *td) { + BME_Vert *v, *nv; + BME_Edge *e, *oe; + BME_Loop *l, *l2; + BME_Poly *f; + unsigned int i, len; + + for (f=bm->polys.first; f; f=f->next) { + if(f->tflag1 & BME_BEVEL_ORIG) { + BME_bevel_poly(bm,f,value,options,td); + } + } + + /* here we will loop through all the verts to clean up the left over geometry */ + /* crazy idea. when res == 0, don't remove the original geometry */ + for (v = bm->verts.first; v; /* we may kill v, so increment in-loop */) { + nv = v->next; + if ((v->tflag1 & BME_BEVEL_NONMAN) && (v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG)) { + v = BME_bevel_wire(bm, v, value, res, options, td); + } + else if (res && ((v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG))) { + + /* first, make sure we're not sitting on an edge to be removed */ + oe = v->edge; + e = BME_disk_nextedge(oe,v); + while ((e->tflag1 & BME_BEVEL_BEVEL) && (e->tflag1 & BME_BEVEL_ORIG)) { + e = BME_disk_nextedge(e,v); + if (e == oe) { + //printf("Something's wrong! We can't remove every edge here!\n"); + break; + } + } + /* look for original edges, and remove them */ + oe = e; + while ( (e = BME_disk_next_edgeflag(oe, v, 0, BME_BEVEL_ORIG | BME_BEVEL_BEVEL)) ) { + /* join the faces (we'll split them later) */ + f = BME_JFKE_safe(bm,e->loop->f,((BME_Loop*)e->loop->radial.next->data)->f,e); + if (!f){ + //printf("Non-manifold geometry not getting tagged right?\n"); + } + } + + /* all original edges marked to be beveled have been removed; + * now we need to link up the edges for this "corner" */ + len = BME_cycle_length(BME_disk_getpointer(v->edge, v)); + for (i=0,e=v->edge; i < len; i++,e=BME_disk_nextedge(e,v)) { + l = e->loop; + l2 = l->radial.next->data; + if (l->v != v) l = l->next; + if (l2->v != v) l2 = l2->next; + /* look for faces that have had the original edges removed via JFKE */ + if (l->f->len > 3) { + BME_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */ + if (len > 2) { + l->e->tflag1 |= BME_BEVEL_BEVEL; + } + } + if (l2->f->len > 3) { + BME_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */ + if (len > 2) { + l->e->tflag1 |= BME_BEVEL_BEVEL; + } + } + } + bmesh_dissolve_disk(bm, v); + } + v = nv; + } + + return bm; +} + +static BME_Mesh *BME_tesselate(BME_Mesh *bm) { + BME_Loop *l, *nextloop; + BME_Poly *f; + + for (f=bm->polys.first; f; f=f->next) { + l = f->loopbase; + while (l->f->len > 4) { + nextloop = l->next->next->next; + /* make a quad */ + BME_split_face(bm,l->f,l->v,nextloop->v,NULL,l->e); + l = nextloop; + } + } + return bm; +} + + +/*Main bevel function: + Should be only one exported + +*/ + +/* options that can be passed: + * BME_BEVEL_VWEIGHT <---- v, Look at vertex weights; use defgrp_index if option is present + * BME_BEVEL_SELECT <---- v,e, check selection for verts and edges + * BME_BEVEL_ANGLE <---- v,e, don't bevel-tag verts - tag verts per edge + * BME_BEVEL_VERT <---- e, don't tag edges + * BME_BEVEL_EWEIGHT <---- e, use crease flag for now + * BME_BEVEL_PERCENT <---- Will need to think about this one; will probably need to incorporate into actual bevel routine + * BME_BEVEL_RADIUS <---- Will need to think about this one; will probably need to incorporate into actual bevel routine + * All weights/limits are stored per-vertex + */ +BME_Mesh *BME_bevel(BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) { + BME_Vert *v; + BME_TransData_Head *td; + BME_TransData *vtd; + int i; + float fac=1, d; + + td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE); + + BME_bevel_initialize(bm, options, defgrp_index, angle, td); + + /* recursion math courtesy of Martin Poirier (theeth) */ + for (i=0; i<res-1; i++) { + if (i==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * i * 2.0f); + } + d = 1.0f/fac; + /* crazy idea. if res == 0, don't remove original geometry */ + for (i=0; i<res || (res==0 && i==0); i++) { + if (i != 0) BME_bevel_reinitialize(bm); + BME_model_begin(bm); + BME_bevel_mesh(bm,d,res,options,defgrp_index,td); + BME_model_end(bm); + if (i==0) d /= 3; else d /= 2; + } + + BME_tesselate(bm); + + if (rtd) { + *rtd = td; + return bm; + } + + /* transform pass */ + for (v = bm->verts.first; v; v=v->next) { + if ( (vtd = BME_get_transdata(td, v)) ) { + if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) { + d = *vtd->max; + } + else { + d = value; + } + VECADDFAC(v->co,vtd->org,vtd->vec,vtd->factor*d); + } + v->tflag1 = 0; + } + + BME_free_transdata(td); + return bm; +} diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 4e00e29029c..9dcb6b6e7fa 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -1293,7 +1293,7 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) { VertDataMulN(nCo, 1.0f/numEdges); } - if ((sharpCount>1 && v->numFaces) || seam) { + if (sharpCount>1 || seam) { VertDataZero(q); if (seam) { diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 94a968970fa..654cf0991cc 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <string.h> @@ -423,7 +420,6 @@ static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3] dofluidsim = ((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN)&& (ob->fluidsimSettings->meshSurface) && - (1) && (!give_parteff(ob)) && // doesnt work together with particle systems! (me->totvert == ((Mesh *)(ob->fluidsimSettings->meshSurface))->totvert)); if (vertCos && !dofluidsim) @@ -636,7 +632,6 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use } static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) { - GLubyte act_face_stipple[32*32/8] = DM_FACE_STIPPLE; EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; EditFace *efa; int i, draw; @@ -653,7 +648,7 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us if(draw) { if (draw==2) { /* enabled with stipple */ glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple(act_face_stipple); + glPolygonStipple(stipple_quarttone); } glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); @@ -690,7 +685,7 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us if(draw) { if (draw==2) { /* enabled with stipple */ glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple(act_face_stipple); + glPolygonStipple(stipple_quarttone); } glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); @@ -734,6 +729,9 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, EditFace *efa; int i; + /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ + glShadeModel(GL_SMOOTH); + if (vertexCos) { EditVert *eve; @@ -755,11 +753,16 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, flag= 1; if(flag != 0) { /* flag 0 == the face is hidden or invisible */ - if (flag==1 && mcol) - cp= (unsigned char*)mcol; - - glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); - + + /* we always want smooth here since otherwise vertex colors dont interpolate */ + if (mcol) { + if (flag==1) { + cp= (unsigned char*)mcol; + } + } else { + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + } + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); if (!drawSmooth) { glNormal3fv(emdm->faceNos[i]); @@ -823,10 +826,14 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, flag= 1; if(flag != 0) { /* flag 0 == the face is hidden or invisible */ - if (flag==1 && mcol) - cp= (unsigned char*)mcol; - - glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + /* we always want smooth here since otherwise vertex colors dont interpolate */ + if (mcol) { + if (flag==1) { + cp= (unsigned char*)mcol; + } + } else { + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + } glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); if (!drawSmooth) { @@ -942,6 +949,7 @@ void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ vert_r->mat_nr = 0; + vert_r->bweight = (unsigned char) (ev->bweight*255.0f); } void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) @@ -954,6 +962,7 @@ void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) for(i = 0; i < index; ++i) ee = ee->next; edge_r->crease = (unsigned char) (ee->crease*255.0f); + edge_r->bweight = (unsigned char) (ee->bweight*255.0f); /* TODO what to do with edge_r->flag? */ edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; if (ee->seam) edge_r->flag |= ME_SEAM; @@ -1034,6 +1043,7 @@ void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ vert_r->mat_nr = 0; vert_r->flag = 0; + vert_r->bweight = (unsigned char) (ev->bweight*255.0f); } } @@ -1050,6 +1060,7 @@ void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) for( ; ee; ee = ee->next, ++edge_r) { edge_r->crease = (unsigned char) (ee->crease*255.0f); + edge_r->bweight = (unsigned char) (ee->bweight*255.0f); /* TODO what to do with edge_r->flag? */ edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; if (ee->seam) edge_r->flag |= ME_SEAM; @@ -1318,6 +1329,7 @@ void vDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) /* not supported yet */ edge_r->flag = 0; edge_r->crease = 0; + edge_r->bweight = 0; break; } } @@ -1424,6 +1436,7 @@ void vDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) /* not supported yet */ edge_r->flag = 0; edge_r->crease = 0; + edge_r->bweight = 0; } } } @@ -1902,8 +1915,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], * domain objects */ if((G.obedit!=ob) && !needMapping) { - if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && - (1) && (!give_parteff(ob)) ) { // doesnt work together with particle systems! + if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE)) { if(ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN) { loadFluidsimMesh(ob,useRenderParams); fluidsimMeshUsed = 1; @@ -1995,8 +2007,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], if((md->mode & required_mode) != required_mode) continue; if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue; if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { - modifier_setError(md, "Internal error, modifier requires " - "original data (bad stack position)."); + modifier_setError(md, "Modifier requires original data, bad stack position."); continue; } if(mti->isDisabled && mti->isDisabled(md)) continue; @@ -2177,8 +2188,7 @@ static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) if((md->mode & required_mode) != required_mode) return 0; if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { - modifier_setError(md, "Internal error, modifier requires" - "original data (bad stack position)."); + modifier_setError(md, "Modifier requires original data, bad stack position."); return 0; } if(mti->isDisabled && mti->isDisabled(md)) return 0; @@ -2538,14 +2548,7 @@ void makeDerivedMesh(Object *ob, CustomDataMask dataMask) if (ob==G.obedit) { editmesh_build_data(dataMask); } else { - PartEff *paf= give_parteff(ob); - mesh_build_data(ob, dataMask); - - if(paf) { - if((paf->flag & PAF_STATIC) || (ob->recalc & OB_RECALC_TIME)==0) - build_particle_system(ob); - } } } @@ -2578,7 +2581,7 @@ float *multires_render_pin(Object *ob, Mesh *me, int *orig_lvl) { float *vert_copy= NULL; - if(me->mr) { + if(me->mr && !(me->mr->flag & MULTIRES_NO_RENDER)) { MultiresLevel *lvl= NULL; int i; @@ -2604,16 +2607,22 @@ float *multires_render_pin(Object *ob, Mesh *me, int *orig_lvl) void multires_render_final(Object *ob, Mesh *me, DerivedMesh **dm, float *vert_copy, const int orig_lvl, CustomDataMask dataMask) { - if(me->mr) { + if(me->mr && !(me->mr->flag & MULTIRES_NO_RENDER)) { if((*dm)->getNumVerts(*dm) == me->totvert && (*dm)->getNumFaces(*dm) == me->totface) { MultiresLevel *lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels)); DerivedMesh *old= NULL; + MVert *vertdup= NULL; int i; - (*dm)->copyVertArray(*dm, me->mvert); + /* Copy the verts into the mesh */ + vertdup= (*dm)->dupVertArray(*dm); (*dm)->release(*dm); - + for(i=0; i<me->totvert; ++i) + me->mvert[i]= vertdup[i]; + /* Free vertdup after use*/ + MEM_freeN(vertdup); + /* Go to the render level */ me->mr->newlvl= me->mr->renderlvl; multires_set_level(ob, me, 1); (*dm)= getMeshDerivedMesh(me, ob, NULL); @@ -3291,11 +3300,13 @@ void loadFluidsimMesh(Object *srcob, int useRenderParams) srcob->data = srcob->fluidsimSettings->orgMesh; return; } else if(displaymode==2) { - strcat(targetDir,"fluidsurface_preview_#"); + strcat(targetDir,"fluidsurface_preview_####"); } else { // 3 - strcat(targetDir,"fluidsurface_final_#"); + strcat(targetDir,"fluidsurface_final_####"); } - BLI_convertstringcode(targetDir, G.sce, curFrame); // fixed #frame-no + BLI_convertstringcode(targetDir, G.sce); + BLI_convertstringframe(targetDir, curFrame); // fixed #frame-no + strcpy(targetFile,targetDir); strcat(targetFile, ".bobj.gz"); diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile index 488d8801e41..74c6c551a83 100644 --- a/source/blender/blenkernel/intern/Makefile +++ b/source/blender/blenkernel/intern/Makefile @@ -1,15 +1,12 @@ # # $Id$ # -# ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +# ***** BEGIN GPL LICENSE BLOCK ***** # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. The Blender -# Foundation also sells licenses for use in proprietary software under -# the Blender License. See http://www.blender.org/BL/ for information -# about this. +# of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ # # Contributor(s): none yet. # -# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# ***** END GPL LICENSE BLOCK ***** # # diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index b8c05f3bb7b..5fb3d6f869a 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,7 +22,7 @@ * * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef HAVE_CONFIG_H @@ -295,7 +292,7 @@ void copy_pose(bPose **dst, bPose *src, int copycon) outPose= MEM_callocN(sizeof(bPose), "pose"); - duplicatelist (&outPose->chanbase, &src->chanbase); + duplicatelist(&outPose->chanbase, &src->chanbase); if (copycon) { for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) { @@ -314,11 +311,11 @@ void free_pose_channels(bPose *pose) if (pose->chanbase.first) { for (pchan = pose->chanbase.first; pchan; pchan=pchan->next){ - if(pchan->path) + if (pchan->path) MEM_freeN(pchan->path); free_constraints(&pchan->constraints); } - BLI_freelistN (&pose->chanbase); + BLI_freelistN(&pose->chanbase); } } @@ -353,7 +350,9 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan } } -/* checks for IK constraint, can do more constraints flags later */ +/* checks for IK constraint, and also for Follow-Path constraint. + * can do more constraints flags later + */ /* pose should be entirely OK */ void update_pose_constraint_flags(bPose *pose) { @@ -361,13 +360,15 @@ void update_pose_constraint_flags(bPose *pose) bConstraint *con; /* clear */ - for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { + for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { pchan->constflag= 0; } + pose->flag &= ~POSE_CONSTRAINTS_TIMEDEPEND; + /* detect */ - for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) { - for(con= pchan->constraints.first; con; con= con->next) { - if(con->type==CONSTRAINT_TYPE_KINEMATIC) { + for (pchan= pose->chanbase.first; pchan; pchan=pchan->next) { + for (con= pchan->constraints.first; con; con= con->next) { + if (con->type==CONSTRAINT_TYPE_KINEMATIC) { bKinematicConstraint *data = (bKinematicConstraint*)con->data; pchan->constflag |= PCHAN_HAS_IK; @@ -390,7 +391,20 @@ void update_pose_constraint_flags(bPose *pose) } } } - else pchan->constflag |= PCHAN_HAS_CONST; + else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) { + bFollowPathConstraint *data= (bFollowPathConstraint *)con->data; + + /* for drawing constraint colors when color set allows this */ + pchan->constflag |= PCHAN_HAS_CONST; + + /* if we have a valid target, make sure that this will get updated on frame-change + * (needed for when there is no anim-data for this pose) + */ + if ((data->tar) && (data->tar->type==OB_CURVE)) + pose->flag |= POSE_CONSTRAINTS_TIMEDEPEND; + } + else + pchan->constflag |= PCHAN_HAS_CONST; } } } @@ -475,10 +489,11 @@ static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert { float length, actlength, repeat, scale; + if (strip->repeat == 0.0f) strip->repeat = 1.0f; repeat = (strip->flag & ACTSTRIP_USESTRIDE) ? (1.0f) : (strip->repeat); - if(strip->scale == 0.0f) strip->scale= 1.0f; - scale = abs(strip->scale); /* scale must be positive (for now) */ + if (strip->scale == 0.0f) strip->scale= 1.0f; + scale = fabs(strip->scale); /* scale must be positive (for now) */ actlength = strip->actend-strip->actstart; if (actlength == 0.0f) actlength = 1.0f; @@ -946,11 +961,7 @@ static float nla_time(float cfra, float unit) /* global time */ cfra*= G.scene->r.framelen; - - - /* decide later... */ -// if(no_speed_curve==0) if(ob && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra); - + return cfra; } @@ -1128,12 +1139,13 @@ void what_does_obaction (Object *ob, bAction *act, float cframe) workob.constraints.first = ob->constraints.first; workob.constraints.last = ob->constraints.last; - strcpy(workob.parsubstr, ob->parsubstr); + strcpy(workob.parsubstr, ob->parsubstr); + strcpy(workob.id.name, ob->id.name); /* extract_ipochannels_from_action needs id's! */ workob.action= act; - extract_ipochannels_from_action(&tchanbase, &ob->id, act, "Object", bsystem_time(&workob, cframe, 0.0)); + extract_ipochannels_from_action(&tchanbase, &workob.id, act, "Object", bsystem_time(&workob, cframe, 0.0)); if (tchanbase.first) { execute_ipochannels(&tchanbase); diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 58d0e84acd8..8533175ad37 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> @@ -387,7 +384,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *n { DupliObject *dob; struct vertexDupliData *vdd= userData; - float vec[3], *q2, mat[3][3], tmat[4][4], obmat[4][4]; + float vec[3], q2[4], mat[3][3], tmat[4][4], obmat[4][4]; VECCOPY(vec, co); Mat4MulVecfl(vdd->pmat, vec); @@ -405,7 +402,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *n vec[0]= -no_s[0]; vec[1]= -no_s[1]; vec[2]= -no_s[2]; } - q2= vectoquat(vec, vdd->ob->trackflag, vdd->ob->upflag); + vectoquat(vec, vdd->ob->trackflag, vdd->ob->upflag, q2); QuatToMat3(q2, mat); Mat4CpyMat4(tmat, obmat); @@ -736,8 +733,8 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ ParticleSystemModifierData *psmd; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], obrotmat[4][4], pamat[4][4], size=0.0; - float obmat[4][4], (*obmatlist)[4][4]=0; - float xvec[3] = {-1.0, 0.0, 0.0}, *q; + float (*obmat)[4]; + float xvec[3] = {-1.0, 0.0, 0.0}, q[4]; int lay, a, b, k, step_nbr = 0, counter, hair = 0; int totpart, totchild, totgroup=0, pa_num; @@ -749,7 +746,11 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ part=psys->part; psmd= psys_get_modifier(par, psys); - if(part==0) return; + if(part==0) + return; + + if(!psys_check_enabled(par, psys)) + return; ctime = bsystem_time(par, (float)G.scene->r.cfra, 0.0); @@ -767,8 +768,13 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ else step_nbr = 0; - if(psys->flag & PSYS_HAIR_DONE) - hair= (totchild == 0 || psys->childcache) && psys->pathcache; + /* if we have a hair particle system, use the path cache */ + if(part->type == PART_HAIR) { + if(psys->flag & PSYS_HAIR_DONE) + hair= (totchild == 0 || psys->childcache) && psys->pathcache; + if(!hair) + return; + } psys->lattice = psys_get_lattice(par, psys); @@ -782,17 +788,12 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ } oblist= MEM_callocN(totgroup*sizeof(Object *), "dupgroup object list"); - obmatlist= MEM_callocN(totgroup*sizeof(float)*4*4, "dupgroup obmat list"); go= part->dup_group->gobject.first; - for(a=0; a<totgroup; a++, go=go->next) { + for(a=0; a<totgroup; a++, go=go->next) oblist[a]=go->ob; - Mat4CpyMat4(obmatlist[a], go->ob->obmat); - } } - else { + else ob = part->dup_ob; - Mat4CpyMat4(obmat, ob->obmat); - } if(totchild==0 || part->draw & PART_DRAW_PARENT) a=0; @@ -828,18 +829,20 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ b= a % totgroup; ob = oblist[b]; - Mat4CpyMat4(obmat, obmatlist[b]); + obmat= oblist[b]->obmat; } + else + obmat= ob->obmat; for(k=0; k<=step_nbr; k++, counter++) { if(hair) { if(a < totpart) { cache = psys->pathcache[a]; - psys_get_dupli_path_transform(par, part, psmd, pa, 0, cache, pamat, &scale); + psys_get_dupli_path_transform(par, psys, psmd, pa, 0, cache, pamat, &scale); } else { cache = psys->childcache[a-totpart]; - psys_get_dupli_path_transform(par, part, psmd, 0, cpa, cache, pamat, &scale); + psys_get_dupli_path_transform(par, psys, psmd, 0, cpa, cache, pamat, &scale); } VECCOPY(pamat[3], cache->co); @@ -865,7 +868,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ if(part->draw_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for(go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) { - Mat4MulMat4(tmat, obmatlist[b], pamat); + Mat4MulMat4(tmat, obmat, pamat); Mat4MulFloat3((float *)tmat, size*scale); if(par_space_mat) Mat4MulMat4(mat, tmat, par_space_mat); @@ -882,10 +885,9 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ where_is_object_time(ob, ctime-pa_time); if(!hair) { - q = vectoquat(xvec, ob->trackflag, ob->upflag); + vectoquat(xvec, ob->trackflag, ob->upflag, q); QuatToMat4(q, obrotmat); obrotmat[3][3]= 1.0f; - Mat4MulMat4(mat, obrotmat, pamat); } else @@ -907,8 +909,6 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ } if(oblist) MEM_freeN(oblist); - if(obmatlist) - MEM_freeN(obmatlist); if(psys->lattice) { end_latt_deform(); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 28a5430a5b3..eca10e5b079 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1,7 +1,7 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,7 +22,7 @@ * * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <ctype.h> @@ -366,7 +366,7 @@ void bone_autoside_name (char *name, int strip_number, short axis, float head, f { int len; char basename[32]={""}; - char extension[3]={""}; + char extension[5]={""}; len= strlen(name); if (len == 0) return; @@ -384,59 +384,88 @@ void bone_autoside_name (char *name, int strip_number, short axis, float head, f /* z-axis - vertical (top/bottom) */ if (IS_EQ(head, 0)) { if (tail < 0) - strcpy(extension, ".Bot"); + strcpy(extension, "Bot"); else if (tail > 0) - strcpy(extension, ".Top"); + strcpy(extension, "Top"); } else { if (head < 0) - strcpy(extension, ".Bot"); + strcpy(extension, "Bot"); else - strcpy(extension, ".Top"); + strcpy(extension, "Top"); } } else if (axis == 1) { /* y-axis - depth (front/back) */ if (IS_EQ(head, 0)) { if (tail < 0) - strcpy(extension, ".Fr"); + strcpy(extension, "Fr"); else if (tail > 0) - strcpy(extension, ".Bk"); + strcpy(extension, "Bk"); } else { if (head < 0) - strcpy(extension, ".Fr"); + strcpy(extension, "Fr"); else - strcpy(extension, ".Bk"); + strcpy(extension, "Bk"); } } else { /* x-axis - horizontal (left/right) */ if (IS_EQ(head, 0)) { if (tail < 0) - strcpy(extension, ".R"); + strcpy(extension, "R"); else if (tail > 0) - strcpy(extension, ".L"); + strcpy(extension, "L"); } else { if (head < 0) - strcpy(extension, ".R"); + strcpy(extension, "R"); else if (head > 0) - strcpy(extension, ".L"); + strcpy(extension, "L"); } } /* Simple name truncation * - truncate if there is an extension and it wouldn't be able to fit - * - otherwise, just append to end (TODO: this should really check if there was already a tag there, and remove it) + * - otherwise, just append to end */ if (extension[0]) { - if ((32 - len) < strlen(extension)) { + int change = 1; + + while (change) { /* remove extensions */ + change = 0; + if (len > 2 && basename[len-2]=='.') { + if (basename[len-1]=='L' || basename[len-1] == 'R' ) { /* L R */ + basename[len-2] = '\0'; + len-=2; + change= 1; + } + } else if (len > 3 && basename[len-3]=='.') { + if ( (basename[len-2]=='F' && basename[len-1] == 'r') || /* Fr */ + (basename[len-2]=='B' && basename[len-1] == 'k') /* Bk */ + ) { + basename[len-3] = '\0'; + len-=3; + change= 1; + } + } else if (len > 4 && basename[len-4]=='.') { + if ( (basename[len-3]=='T' && basename[len-2]=='o' && basename[len-1] == 'p') || /* Top */ + (basename[len-3]=='B' && basename[len-2]=='o' && basename[len-1] == 't') /* Bot */ + ) { + basename[len-4] = '\0'; + len-=4; + change= 1; + } + } + } + + if ((32 - len) < strlen(extension) + 1) { /* add 1 for the '.' */ strncpy(name, basename, len-strlen(extension)); } } - sprintf(name, "%s%s", basename, extension); + sprintf(name, "%s.%s", basename, extension); } /* ************* B-Bone support ******************* */ @@ -1389,18 +1418,26 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected bPoseChannel *pchan, *pchanp, pchanw; bConstraint *con; - if(frompose==NULL) return; + if (frompose==NULL) return; /* exception, armature local layer should be proxied too */ - if(pose->proxy_layer) + if (pose->proxy_layer) ((bArmature *)ob->data)->layer= pose->proxy_layer; /* clear all transformation values from library */ rest_pose(frompose); - pchan= pose->chanbase.first; - for(; pchan; pchan= pchan->next) { - if(pchan->bone->layer & layer_protected) { + /* copy over all of the proxy's bone groups */ + /* TODO for later - implement 'local' bone groups as for constraints + * Note: this isn't trivial, as bones reference groups by index not by pointer, + * so syncing things correctly needs careful attention + */ + BLI_freelistN(&pose->agroups); + duplicatelist(&pose->agroups, &frompose->agroups); + pose->active_group= frompose->active_group; + + for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { + if (pchan->bone->layer & layer_protected) { ListBase proxylocal_constraints = {NULL, NULL}; pchanp= get_pose_channel(frompose, pchan->name); @@ -1755,7 +1792,7 @@ static void execute_posetree(Object *ob, PoseTree *tree) if(tree->stretch && (pchan->ikstretch > 0.0)) { float ikstretch = pchan->ikstretch*pchan->ikstretch; - IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.999)); + IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99)); IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10); } } @@ -2164,8 +2201,10 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime) } else { Mat4MulMat4(pchan->pose_mat, pchan->chan_mat, bone->arm_mat); - /* only rootbones get the cyclic offset */ - VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset); + + /* only rootbones get the cyclic offset (unless user doesn't want that) */ + if ((bone->flag & BONE_NO_CYCLICOFFSET) == 0) + VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset); } /* do NLA strip modifiers - i.e. curve follow */ diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index b15a5bb42ed..81f496e97d6 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -4,15 +4,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifndef WIN32 @@ -63,6 +60,7 @@ #include "DNA_mesh_types.h" #include "DNA_screen_types.h" +#include "BKE_action.h" #include "BKE_blender.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" @@ -85,7 +83,6 @@ #include "BKE_bad_level_calls.h" // for freeAllRad editNurb free_editMesh free_editText free_editArmature #include "BKE_utildefines.h" // O_BINARY FALSE #include "BIF_mainqueue.h" // mainqenter for onload script -#include "BIF_toolbox.h" #include "mydevice.h" #include "nla.h" #include "blendef.h" @@ -333,6 +330,7 @@ static void setup_app_data(BlendFileData *bfd, char *filename) extern void lib_link_screen_restore(Main *, Scene *); SWAP(ListBase, G.main->screen, bfd->main->screen); + SWAP(ListBase, G.main->script, bfd->main->script); /* we re-use current screen */ curscreen= G.curscreen; @@ -385,7 +383,8 @@ static void setup_app_data(BlendFileData *bfd, char *filename) /* special cases, override loaded flags: */ if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG; else bfd->globalf &= ~G_DEBUG; - if (!(G.f & G_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS; + + if ((U.flag & USER_DONT_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS; G.f= bfd->globalf; @@ -396,6 +395,9 @@ static void setup_app_data(BlendFileData *bfd, char *filename) /* baseflags, groups, make depsgraph, etc */ set_scene_bg(G.scene); + /* clear BONE_UNKEYED flags, these are not valid anymore for proxies */ + framechange_poses_clear_unkeyed(); + /* last stage of do_versions actually, that sets recalc flags for recalc poses */ for(ob= G.main->object.first; ob; ob= ob->id.next) { if(ob->type==OB_ARMATURE) @@ -412,7 +414,7 @@ static void setup_app_data(BlendFileData *bfd, char *filename) if (G.sce != filename) /* these are the same at times, should never copy to the same location */ strcpy(G.sce, filename); - strcpy(G.main->name, filename); /* is guaranteed current file */ + BLI_strncpy(G.main->name, filename, FILE_MAX); /* is guaranteed current file */ MEM_freeN(bfd); } @@ -479,7 +481,7 @@ int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r) if (type_r) *((BlenFileType*)type_r)= bfd->type; - setup_app_data(bfd, "<memory>"); + setup_app_data(bfd, "<memory2>"); } else { error("Loading failed: %s", BLO_bre_as_string(bre)); } @@ -501,7 +503,7 @@ int BKE_read_file_from_memfile(MemFile *memfile) bfd= BLO_read_from_memfile(G.sce, memfile, &bre); if (bfd) { - setup_app_data(bfd, "<memory>"); + setup_app_data(bfd, "<memory1>"); } else { error("Loading failed: %s", BLO_bre_as_string(bre)); } @@ -602,7 +604,7 @@ void BKE_write_undo(char *name) counter= counter % U.undosteps; sprintf(numstr, "%d.blend", counter); - BLI_make_file_string("/", tstr, U.tempdir, numstr); + BLI_make_file_string("/", tstr, btempdir, numstr); success= BLO_write_file(tstr, G.fileflags, &err); @@ -617,10 +619,6 @@ void BKE_write_undo(char *name) success= BLO_write_file_mem(prevfile, &curundo->memfile, G.fileflags, &err); } - - /* signals "file needs save" on exit */ - if(curundo!=NULL && curundo->prev!=NULL) - U.uiflag |= USER_UNDOSAVE; } /* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */ @@ -698,7 +696,7 @@ char *BKE_undo_menu_string(void) return menu; } -/* saves quit.blend */ + /* saves quit.blend */ void BKE_undo_save_quit(void) { UndoElem *uel; @@ -717,11 +715,11 @@ void BKE_undo_save_quit(void) /* no undo state to save */ if(undobase.first==undobase.last) return; - BLI_make_file_string("/", str, U.tempdir, "quit.blend"); + BLI_make_file_string("/", str, btempdir, "quit.blend"); file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666); if(file == -1) { - printf("Unable to save %s\n", str); + error("Unable to save %s, check you have permissions", str); return; } @@ -733,7 +731,7 @@ void BKE_undo_save_quit(void) close(file); - if(chunk) printf("Unable to save %s\n", str); + if(chunk) error("Unable to save %s, internal error", str); else printf("Saved session recovery to %s\n", str); } diff --git a/source/blender/blenkernel/intern/bmesh_private.h b/source/blender/blenkernel/intern/bmesh_private.h new file mode 100644 index 00000000000..ad90398bf66 --- /dev/null +++ b/source/blender/blenkernel/intern/bmesh_private.h @@ -0,0 +1,71 @@ +/** + * BME_private.h jan 2007 + * + * low level, 'private' function prototypes for bmesh kernel. + * + * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BMESH_PRIVATE +#define BMESH_PRIVATE + +#include "BKE_bmesh.h" + +/*ALLOCATION/DEALLOCATION*/ +struct BME_Vert *BME_addvertlist(struct BME_Mesh *bm, struct BME_Vert *example); +struct BME_Edge *BME_addedgelist(struct BME_Mesh *bm, struct BME_Vert *v1, struct BME_Vert *v2, struct BME_Edge *example); +struct BME_Poly *BME_addpolylist(struct BME_Mesh *bm, struct BME_Poly *example); +struct BME_Loop *BME_create_loop(struct BME_Mesh *bm, struct BME_Vert *v, struct BME_Edge *e, struct BME_Poly *f, struct BME_Loop *example); + +void BME_free_vert(struct BME_Mesh *bm, struct BME_Vert *v); +void BME_free_edge(struct BME_Mesh *bm, struct BME_Edge *e); +void BME_free_poly(struct BME_Mesh *bm, struct BME_Poly *f); +void BME_free_loop(struct BME_Mesh *bm, struct BME_Loop *l); +void BME_delete_loop(struct BME_Mesh *bm, struct BME_Loop *l); + +/*DOUBLE CIRCULAR LINKED LIST FUNCTIONS*/ +void BME_cycle_append(void *h, void *nt); +int BME_cycle_remove(void *h, void *remn); +int BME_cycle_validate(int len, void *h); +/*DISK CYCLE MANAGMENT*/ +int BME_disk_append_edge(struct BME_Edge *e, struct BME_Vert *v); +void BME_disk_remove_edge(struct BME_Edge *e, struct BME_Vert *v); +/*RADIAL CYCLE MANAGMENT*/ +void BME_radial_append(struct BME_Edge *e, struct BME_Loop *l); +void BME_radial_remove_loop(struct BME_Loop *l, struct BME_Edge *e); + +/*MISC FUNCTIONS*/ +int BME_edge_swapverts(struct BME_Edge *e, struct BME_Vert *orig, struct BME_Vert *new); /*relink edge*/ +int BME_disk_hasedge(struct BME_Vert *v, struct BME_Edge *e); + +/*Error reporting. Shouldnt be called by tools ever.*/ +void BME_error(void); +#endif diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c index 6ea08b5cfbb..0af54b86ed6 100644 --- a/source/blender/blenkernel/intern/bmfont.c +++ b/source/blender/blenkernel/intern/bmfont.c @@ -5,15 +5,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,7 +28,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** * */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index ca2f7b114d5..6ea470a2263 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> @@ -73,7 +70,8 @@ Brush *add_brush(char *name) brush->clone.alpha= 0.5; /* enable fake user by default */ - brush_toggle_fake_user(brush); + brush->id.flag |= LIB_FAKEUSER; + brush_toggled_fake_user(brush); return brush; } @@ -95,8 +93,10 @@ Brush *copy_brush(Brush *brush) } /* enable fake user by default */ - if (!(brushn->id.flag & LIB_FAKEUSER)) - brush_toggle_fake_user(brushn); + if (!(brushn->id.flag & LIB_FAKEUSER)) { + brushn->id.flag |= LIB_FAKEUSER; + brush_toggled_fake_user(brushn); + } return brushn; } @@ -148,8 +148,10 @@ void make_local_brush(Brush *brush) new_id(0, (ID *)brush, 0); /* enable fake user by default */ - if (!(brush->id.flag & LIB_FAKEUSER)) - brush_toggle_fake_user(brush); + if (!(brush->id.flag & LIB_FAKEUSER)) { + brush->id.flag |= LIB_FAKEUSER; + brush_toggled_fake_user(brush); + } } else if(local && lib) { brushn= copy_brush(brush); @@ -203,16 +205,14 @@ int brush_delete(Brush **current_brush) return 0; } -void brush_toggle_fake_user(Brush *brush) +void brush_toggled_fake_user(Brush *brush) { ID *id= (ID*)brush; if(id) { if(id->flag & LIB_FAKEUSER) { - id->flag -= LIB_FAKEUSER; - id->us--; - } else { - id->flag |= LIB_FAKEUSER; id_us_plus(id); + } else { + id->us--; } } } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 6a856307916..c2946bb666f 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -52,6 +52,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_fluidsim.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -746,18 +747,24 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) { CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm"); DerivedMesh *dm = &cddm->dm; - int i, *index; + int i, *index, alloctype; - /* this does a referenced copy, the only new layers being ORIGINDEX */ + /* this does a referenced copy, the only new layers being ORIGINDEX, + * with an exception for fluidsim */ DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface); dm->deformedOnly = 1; - CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, CD_REFERENCE, + if(ob && ob->fluidsimSettings && ob->fluidsimSettings->meshSurface) + alloctype= CD_DUPLICATE; + else + alloctype= CD_REFERENCE; + + CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, alloctype, mesh->totvert); - CustomData_merge(&mesh->edata, &dm->edgeData, CD_MASK_MESH, CD_REFERENCE, + CustomData_merge(&mesh->edata, &dm->edgeData, CD_MASK_MESH, alloctype, mesh->totedge); - CustomData_merge(&mesh->fdata, &dm->faceData, CD_MASK_MESH, CD_REFERENCE, + CustomData_merge(&mesh->fdata, &dm->faceData, CD_MASK_MESH, alloctype, mesh->totface); cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); @@ -833,6 +840,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) mv->no[0] = eve->no[0] * 32767.0; mv->no[1] = eve->no[1] * 32767.0; mv->no[2] = eve->no[2] * 32767.0; + mv->bweight = (unsigned char) (eve->bweight * 255.0f); mv->mat_nr = 0; mv->flag = 0; @@ -850,6 +858,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) med->v1 = eed->v1->tmp.l; med->v2 = eed->v2->tmp.l; med->crease = (unsigned char) (eed->crease * 255.0f); + med->bweight = (unsigned char) (eed->bweight * 255.0f); med->flag = ME_EDGEDRAW|ME_EDGERENDER; if(eed->seam) med->flag |= ME_SEAM; diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index a99ac705c0b..4be4434dfda 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1,15 +1,12 @@ /* cloth.c * * -* ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +* ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. The Blender -* Foundation also sells licenses for use in proprietary software under -* the Blender License. See http://www.blender.org/BL/ for information -* about this. +* of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,58 +20,28 @@ * The Original Code is Copyright (C) Blender Foundation * All rights reserved. * -* The Original Code is: all of this file. +* Contributor(s): Daniel Genrich * -* Contributor(s): none yet. -* -* ***** END GPL/BL DUAL LICENSE BLOCK ***** +* ***** END GPL LICENSE BLOCK ***** */ - -#include <math.h> -#include <stdlib.h> -#include <string.h> - #include "MEM_guardedalloc.h" -/* types */ -#include "DNA_curve_types.h" -#include "DNA_object_types.h" -#include "DNA_object_force.h" +#include "BKE_cloth.h" + #include "DNA_cloth_types.h" -#include "DNA_key_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_lattice_types.h" +#include "DNA_object_force.h" #include "DNA_scene_types.h" -#include "DNA_modifier_types.h" -#include "BLI_blenlib.h" -#include "BLI_arithb.h" -#include "BLI_edgehash.h" -#include "BLI_linklist.h" - -#include "BKE_curve.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" #include "BKE_cdderivedmesh.h" -#include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_key.h" -#include "BKE_mesh.h" #include "BKE_object.h" -#include "BKE_cloth.h" #include "BKE_modifier.h" #include "BKE_utildefines.h" -#include "BKE_DerivedMesh.h" -#include "BIF_editdeform.h" -#include "BIF_editkey.h" -#include "DNA_screen_types.h" -#include "BSE_headerbuttons.h" -#include "BIF_screen.h" -#include "BIF_space.h" -#include "mydevice.h" #include "BKE_pointcache.h" @@ -90,9 +57,9 @@ double tval() } #else #include <sys/time.h> -static struct timeval _tstart, _tend; -static struct timezone tz; -void tstart ( void ) + static struct timeval _tstart, _tend; + static struct timezone tz; + void tstart ( void ) { gettimeofday ( &_tstart, &tz ); } @@ -113,17 +80,17 @@ double tval() // 255 is the magic reserved number, so NEVER try to put 255 solvers in here! // 254 = MAX! static CM_SOLVER_DEF solvers [] = - { - { "Implicit", CM_IMPLICIT, implicit_init, implicit_solver, implicit_free }, +{ + { "Implicit", CM_IMPLICIT, implicit_init, implicit_solver, implicit_free }, // { "Implicit C++", CM_IMPLICITCPP, implicitcpp_init, implicitcpp_solver, implicitcpp_free }, - }; +}; /* ********** cloth engine ******* */ /* Prototypes for internal functions. */ static void cloth_to_object (Object *ob, ClothModifierData *clmd, DerivedMesh *dm); static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ); -static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr); +static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first); int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ); static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ); @@ -134,42 +101,41 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ); * ******************************************************************************/ /** -* cloth_init - creates a new cloth simulation. -* -* 1. create object -* 2. fill object with standard values or with the GUI settings if given -*/ + * cloth_init - creates a new cloth simulation. + * + * 1. create object + * 2. fill object with standard values or with the GUI settings if given + */ void cloth_init ( ClothModifierData *clmd ) { /* Initialize our new data structure to reasonable values. */ clmd->sim_parms->gravity [0] = 0.0; clmd->sim_parms->gravity [1] = 0.0; clmd->sim_parms->gravity [2] = -9.81; - clmd->sim_parms->structural = 200.0; - clmd->sim_parms->shear = 200.0; - clmd->sim_parms->bending = 0.1; - clmd->sim_parms->Cdis = 5.0; + clmd->sim_parms->structural = 15.0; + clmd->sim_parms->shear = 15.0; + clmd->sim_parms->bending = 0.5; + clmd->sim_parms->Cdis = 5.0; clmd->sim_parms->Cvi = 1.0; - clmd->sim_parms->mass = 1.0f; + clmd->sim_parms->mass = 0.3f; clmd->sim_parms->stepsPerFrame = 5; - clmd->sim_parms->sim_time = 1.0; clmd->sim_parms->flags = 0; clmd->sim_parms->solver_type = 0; clmd->sim_parms->preroll = 0; clmd->sim_parms->maxspringlen = 10; - clmd->sim_parms->firstframe = 1; - clmd->sim_parms->lastframe = 250; clmd->sim_parms->vgroup_mass = 0; - clmd->sim_parms->lastcachedframe = 0; - clmd->sim_parms->editedframe = 0; - clmd->sim_parms->autoprotect = 25; - clmd->sim_parms->firstcachedframe = -1.0; + clmd->sim_parms->avg_spring_len = 0.0; + clmd->sim_parms->presets = 2; /* cotton as start setting */ + clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */ clmd->coll_parms->self_friction = 5.0; - clmd->coll_parms->friction = 10.0; + clmd->coll_parms->friction = 5.0; clmd->coll_parms->loop_count = 3; clmd->coll_parms->epsilon = 0.015f; clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED; + clmd->coll_parms->collision_list = NULL; + clmd->coll_parms->self_loop_count = 1.0; + clmd->coll_parms->selfepsilon = 0.75; /* These defaults are copied from softbody.c's * softbody_calc_forces() function. @@ -181,7 +147,7 @@ void cloth_init ( ClothModifierData *clmd ) clmd->sim_parms->maxgoal = 1.0f; clmd->sim_parms->mingoal = 0.0f; clmd->sim_parms->defgoal = 0.0f; - clmd->sim_parms->goalspring = 100.0f; + clmd->sim_parms->goalspring = 1.0f; clmd->sim_parms->goalfrict = 0.0f; } @@ -203,6 +169,10 @@ BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon) verts = cloth->verts; + // in the moment, return zero if no faces there + if(!cloth->numfaces) + return NULL; + bvh = MEM_callocN(sizeof(BVH), "BVH"); if (bvh == NULL) { @@ -212,11 +182,6 @@ BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon) // springs = cloth->springs; // numsprings = cloth->numsprings; - - bvh->flags = 0; - bvh->leaf_tree = NULL; - bvh->leaf_root = NULL; - bvh->tree = NULL; bvh->epsilon = epsilon; bvh->numfaces = cloth->numfaces; @@ -225,12 +190,17 @@ BVH *bvh_build_from_cloth (ClothModifierData *clmd, float epsilon) bvh->numverts = cloth->numverts; bvh->current_x = MEM_callocN ( sizeof ( MVert ) * bvh->numverts, "bvh->current_x" ); - bvh->current_xold = MEM_callocN ( sizeof ( MVert ) * bvh->numverts, "bvh->current_xold" ); + + if (bvh->current_x == NULL) + { + printf("bvh: Out of memory.\n"); + MEM_freeN(bvh); + return NULL; + } for(i = 0; i < bvh->numverts; i++) { VECCOPY(bvh->current_x[i].co, verts[i].tx); - VECCOPY(bvh->current_xold[i].co, verts[i].txold); } bvh_build (bvh); @@ -263,589 +233,265 @@ void bvh_update_from_cloth(ClothModifierData *clmd, int moving) bvh_update(bvh, moving); } -// unused in the moment, cloth needs quads from mesh -DerivedMesh *CDDM_convert_to_triangle ( DerivedMesh *dm ) -{ - DerivedMesh *result = NULL; - int i; - int numverts = dm->getNumVerts ( dm ); - int numedges = dm->getNumEdges ( dm ); - int numfaces = dm->getNumFaces ( dm ); - - MVert *mvert = CDDM_get_verts ( dm ); - MEdge *medge = CDDM_get_edges ( dm ); - MFace *mface = CDDM_get_faces ( dm ); - - MVert *mvert2; - MFace *mface2; - unsigned int numtris=0; - unsigned int numquads=0; - int a = 0; - int random = 0; - int firsttime = 0; - float vec1[3], vec2[3], vec3[3], vec4[3], vec5[3]; - float mag1=0, mag2=0; - - for ( i = 0; i < numfaces; i++ ) - { - if ( mface[i].v4 ) - numquads++; - else - numtris++; - } - - result = CDDM_from_template ( dm, numverts, 0, numtris + 2*numquads ); - - if ( !result ) - return NULL; - - // do verts - mvert2 = CDDM_get_verts ( result ); - for ( a=0; a<numverts; a++ ) - { - MVert *inMV; - MVert *mv = &mvert2[a]; - - inMV = &mvert[a]; - - DM_copy_vert_data ( dm, result, a, a, 1 ); - *mv = *inMV; - } - - - // do faces - mface2 = CDDM_get_faces ( result ); - for ( a=0, i=0; a<numfaces; a++ ) - { - MFace *mf = &mface2[i]; - MFace *inMF; - inMF = &mface[a]; - - /* - DM_copy_face_data(dm, result, a, i, 1); - - *mf = *inMF; - */ - - if ( mface[a].v4 && random==1 ) - { - mf->v1 = mface[a].v2; - mf->v2 = mface[a].v3; - mf->v3 = mface[a].v4; - } - else - { - mf->v1 = mface[a].v1; - mf->v2 = mface[a].v2; - mf->v3 = mface[a].v3; - } - - mf->v4 = 0; - mf->flag |= ME_SMOOTH; - - test_index_face ( mf, NULL, 0, 3 ); - - if ( mface[a].v4 ) - { - MFace *mf2; - - i++; - - mf2 = &mface2[i]; - /* - DM_copy_face_data(dm, result, a, i, 1); - - *mf2 = *inMF; - */ - - if ( random==1 ) - { - mf2->v1 = mface[a].v1; - mf2->v2 = mface[a].v2; - mf2->v3 = mface[a].v4; - } - else - { - mf2->v1 = mface[a].v4; - mf2->v2 = mface[a].v1; - mf2->v3 = mface[a].v3; - } - mf2->v4 = 0; - mf2->flag |= ME_SMOOTH; - - test_index_face ( mf2, NULL, 0, 3 ); - } - - i++; - } - - CDDM_calc_edges ( result ); - CDDM_calc_normals ( result ); - - return result; - -} - - -DerivedMesh *CDDM_create_tearing ( ClothModifierData *clmd, DerivedMesh *dm ) -{ - DerivedMesh *result = NULL; - unsigned int i = 0, a = 0, j=0; - int numverts = dm->getNumVerts ( dm ); - int numedges = dm->getNumEdges ( dm ); - int numfaces = dm->getNumFaces ( dm ); - - MVert *mvert = CDDM_get_verts ( dm ); - MEdge *medge = CDDM_get_edges ( dm ); - MFace *mface = CDDM_get_faces ( dm ); - - MVert *mvert2; - MFace *mface2; - unsigned int numtris=0; - unsigned int numquads=0; - EdgeHash *edgehash = NULL; - Cloth *cloth = clmd->clothObject; - ClothSpring *springs = cloth->springs; - unsigned int numsprings = cloth->numsprings; - - // create spring tearing hash - edgehash = BLI_edgehash_new(); - - for ( i = 0; i < numsprings; i++ ) - { - if ( ( springs[i].flags & CLOTH_SPRING_FLAG_DEACTIVATE ) - && ( !BLI_edgehash_haskey ( edgehash, springs[i].ij, springs[i].kl ) ) ) - { - BLI_edgehash_insert ( edgehash, springs[i].ij, springs[i].kl, NULL ); - BLI_edgehash_insert ( edgehash, springs[i].kl, springs[i].ij, NULL ); - j++; - } - } - - // printf("found %d tears\n", j); - - result = CDDM_from_template ( dm, numverts, 0, numfaces ); - - if ( !result ) - return NULL; - - // do verts - mvert2 = CDDM_get_verts ( result ); - for ( a=0; a<numverts; a++ ) - { - MVert *inMV; - MVert *mv = &mvert2[a]; - - inMV = &mvert[a]; - - DM_copy_vert_data ( dm, result, a, a, 1 ); - *mv = *inMV; - } - - - // do faces - mface2 = CDDM_get_faces ( result ); - for ( a=0, i=0; a<numfaces; a++ ) - { - MFace *mf = &mface2[i]; - MFace *inMF; - inMF = &mface[a]; - - /* - DM_copy_face_data(dm, result, a, i, 1); - - *mf = *inMF; - */ - - if ( ( !BLI_edgehash_haskey ( edgehash, mface[a].v1, mface[a].v2 ) ) - && ( !BLI_edgehash_haskey ( edgehash, mface[a].v2, mface[a].v3 ) ) - && ( !BLI_edgehash_haskey ( edgehash, mface[a].v3, mface[a].v4 ) ) - && ( !BLI_edgehash_haskey ( edgehash, mface[a].v4, mface[a].v1 ) ) ) - { - mf->v1 = mface[a].v1; - mf->v2 = mface[a].v2; - mf->v3 = mface[a].v3; - mf->v4 = mface[a].v4; - - test_index_face ( mf, NULL, 0, 4 ); - - i++; - } - } - - CDDM_lower_num_faces ( result, i ); - CDDM_calc_edges ( result ); - CDDM_calc_normals ( result ); - - BLI_edgehash_free ( edgehash, NULL ); - - return result; -} - int modifiers_indexInObject(Object *ob, ModifierData *md_seek); int cloth_read_cache(Object *ob, ClothModifierData *clmd, float framenr) { - FILE *fp = NULL; - int stack_index = -1; - unsigned int a, ret = 1; + PTCacheID pid; + PTCacheFile *pf; Cloth *cloth = clmd->clothObject; + unsigned int a, ret = 1; if(!cloth) return 0; - stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - - fp = BKE_ptcache_id_fopen((ID *)ob, 'r', framenr, stack_index); - if(!fp) - ret = 0; - else { - for(a = 0; a < cloth->numverts; a++) - { - if(fread(&cloth->verts[a].x, sizeof(float), 3, fp) != 3) - { + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr); + if(pf) { + for(a = 0; a < cloth->numverts; a++) { + if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].x, 3)) { ret = 0; break; } - if(fread(&cloth->verts[a].xconst, sizeof(float), 3, fp) != 3) - { + if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].xconst, 3)) { ret = 0; break; } - if(fread(&cloth->verts[a].v, sizeof(float), 3, fp) != 3) - { + if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].v, 3)) { ret = 0; break; } } - fclose(fp); - - if(clmd->sim_parms->lastcachedframe < framenr) - { - if(G.rt > 0) - printf("cloth_read_cache problem: lnex - f#: %f, lastCF: %d\n", framenr, clmd->sim_parms->lastcachedframe); - } + BKE_ptcache_file_close(pf); } - - if(G.rt > 0) - printf("cloth_read_cache: %f\n", framenr); + else + ret = 0; return ret; } void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr) { - int stack_index = -1; + PTCacheID pid; + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + // don't do anything as long as we're in editmode! - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_EDITMODE) - { - /* delete cache free request */ - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - + if(pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE) return; - } - - /* clear cache if specific frame cleaning requested or cache is not protected */ - if((!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT)) || (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE)) - { - stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - - BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_AFTER, framenr, stack_index); - - /* update last cached frame # */ - clmd->sim_parms->lastcachedframe = framenr; - - /* update first cached frame # */ - if((framenr < clmd->sim_parms->firstcachedframe) && (clmd->sim_parms->firstcachedframe >=0.0)) - clmd->sim_parms->firstcachedframe = -1.0; - - if(G.rt > 0) - printf("cloth_clear_cache: %f\n", framenr); - } - - /* delete cache free request */ - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr); } + void cloth_write_cache(Object *ob, ClothModifierData *clmd, float framenr) { - FILE *fp = NULL; - int stack_index = -1; - unsigned int a; Cloth *cloth = clmd->clothObject; - - if(G.rt > 0) - printf("cloth_write_cache: %f\n", framenr); + PTCacheID pid; + PTCacheFile *pf; + unsigned int a; if(!cloth) - { - if(G.rt > 0) - printf("cloth_write_cache: no cloth\n"); return; - } - - stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - fp = BKE_ptcache_id_fopen((ID *)ob, 'w', framenr, stack_index); - if(!fp) - { - if(G.rt > 0) - printf("cloth_write_cache: no fp\n"); + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr); + if(!pf) return; - } - for(a = 0; a < cloth->numverts; a++) - { - fwrite(&cloth->verts[a].x, sizeof(float),3,fp); - fwrite(&cloth->verts[a].xconst, sizeof(float),3,fp); - fwrite(&cloth->verts[a].v, sizeof(float),3,fp); + for(a = 0; a < cloth->numverts; a++) { + BKE_ptcache_file_write_floats(pf, cloth->verts[a].x, 3); + BKE_ptcache_file_write_floats(pf, cloth->verts[a].xconst, 3); + BKE_ptcache_file_write_floats(pf, cloth->verts[a].v, 3); } - /* update last cached frame # */ - clmd->sim_parms->lastcachedframe = MAX2(clmd->sim_parms->lastcachedframe, framenr); + BKE_ptcache_file_close(pf); +} + +static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) +{ + PointCache *cache; + + cache= clmd->point_cache; + + /* initialize simulation data if it didn't exist already */ + if(clmd->clothObject == NULL) { + if(!cloth_from_object(ob, clmd, result, framenr, 1)) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + return 0; + } - /* update first cached frame # */ - if((clmd->sim_parms->firstcachedframe < 0.0) || ((framenr < clmd->sim_parms->firstcachedframe) && (clmd->sim_parms->firstcachedframe > 0.0))) - clmd->sim_parms->firstcachedframe = framenr; + if(clmd->clothObject == NULL) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + return 0; + } - if(G.rt > 0) - printf("lcf: %d, framenr: %f\n", clmd->sim_parms->lastcachedframe, framenr); + implicit_set_positions(clmd); + } - fclose(fp); + return 1; } +static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) +{ + ClothVertex *verts = NULL; + Cloth *cloth; + ListBase *effectors = NULL; + MVert *mvert; + int i, ret = 0; + + /* simulate 1 frame forward */ + cloth = clmd->clothObject; + verts = cloth->verts; + mvert = result->getVertArray(result); + + /* force any pinned verts to their constrained location. */ + for(i = 0; i < clmd->clothObject->numverts; i++, verts++) { + /* save the previous position. */ + VECCOPY(verts->xold, verts->xconst); + VECCOPY(verts->txold, verts->x); + /* Get the current position. */ + VECCOPY(verts->xconst, mvert[i].co); + Mat4MulVecfl(ob->obmat, verts->xconst); + } + + tstart(); + + /* call the solver. */ + if(solvers [clmd->sim_parms->solver_type].solver) + ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors); + + tend(); + + printf ( "Cloth simulation time: %f\n", ( float ) tval() ); + + return ret; +} /************************************************ * clothModifier_do - main simulation function ************************************************/ -DerivedMesh *clothModifier_do(ClothModifierData *clmd,Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) - +DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { - unsigned int i; - Cloth *cloth = clmd->clothObject; - float framenr = G.scene->r.cfra; - float current_time = bsystem_time ( ob, ( float ) G.scene->r.cfra, 0.0 ); - ListBase *effectors = NULL; - ClothVertex *verts = NULL; - float deltaTime = current_time - clmd->sim_parms->sim_time; - unsigned int numverts = -1; - unsigned int numedges = -1; - unsigned int numfaces = -1; - MVert *mvert = NULL; - MEdge *medge = NULL; - MFace *mface = NULL; - DerivedMesh *result = NULL; - - if(G.rt > 0) - printf("clothModifier_do start\n"); - - /* we're getting called two times during file load, - resulting in a not valid G.relbase on the first time (cache makes problems) - --> just return back */ - if((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_LOADED)&& (!G.relbase_valid)) - { - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_LOADED; - return dm; - } - + DerivedMesh *result; + PointCache *cache; + PTCacheID pid; + float timescale; + int framedelta, framenr, startframe, endframe; + + framenr= (int)G.scene->r.cfra; + cache= clmd->point_cache; result = CDDM_copy(dm); - - if(!result) - { + + BKE_ptcache_id_from_cloth(&pid, ob, clmd); + BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, ×cale); + clmd->sim_parms->timescale= timescale; + + if(!result) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; return dm; } - numverts = result->getNumVerts(result); - numedges = result->getNumEdges(result); - numfaces = result->getNumFaces(result); - mvert = dm->getVertArray(result); - medge = dm->getEdgeArray(result); - mface = dm->getFaceArray(result); - - /* check if cache is active / if file is already saved */ - /* - if ((!G.relbase_valid) && ( deltaTime != 1.0f )) - { - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET; - } - */ - - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_RESET) - { - cloth_free_modifier (ob, clmd); - if(G.rt > 0) - printf("clothModifier_do CLOTH_SIMSETTINGS_FLAG_RESET\n"); - } - - // unused in the moment, calculated seperately in implicit.c - clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame; - - if ( ( clmd->clothObject == NULL ) || (clmd->clothObject && (numverts != clmd->clothObject->numverts )) ) - { - /* only force free the cache if we have a different number of verts */ - if(clmd->clothObject && (numverts != clmd->clothObject->numverts )) - { - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - cloth_free_modifier ( ob, clmd ); - } - - cloth_clear_cache(ob, clmd, 0); - - if ( !cloth_from_object ( ob, clmd, result, framenr ) ) - return result; - - if ( clmd->clothObject == NULL ) + /* verify we still have the same number of vertices, if not do nothing. + * note that this should only happen if the number of vertices changes + * during an animation due to a preceding modifier, this should not + * happen because of object changes! */ + if(clmd->clothObject) { + if(result->getNumVerts(result) != clmd->clothObject->numverts) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; return result; - - cloth = clmd->clothObject; - - if(!cloth_read_cache(ob, clmd, framenr)) - { - /* save first frame in case we have a reseted object - and we move one frame forward. - In that case we would only start with the SECOND frame - if we don't save the current state before - TODO PROBLEM: IMHO we can't track external movement from the - first frame in this case! */ - /* - if ( deltaTime == 1.0f ) - cloth_write_cache(ob, clmd, framenr-1.0); - */ - if(G.rt > 0) - printf("cloth_from_object NO cloth_read_cache cloth_write_cache\n"); } - else - { - if(G.rt > 0) - printf("cloth_from_object cloth_read_cache\n"); - - implicit_set_positions(clmd); - } - - clmd->sim_parms->sim_time = current_time; } - // only be active during a specific period: - // that's "first frame" and "last frame" on GUI - - // TODO: enable later again after refactoring - if ( current_time < clmd->sim_parms->firstframe ) - { + // unused in the moment, calculated seperately in implicit.c + clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame; + + /* handle continuous simulation with the play button */ + if(BKE_ptcache_get_continue_physics()) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + + /* do simulation */ + if(!do_init_cloth(ob, clmd, result, framenr)) + return result; + + do_step_cloth(ob, clmd, result, framenr); + cloth_to_object(ob, clmd, result); + return result; } - else if ( current_time > clmd->sim_parms->lastframe ) - { - int stack_index = modifiers_indexInObject(ob, (ModifierData *)clmd); - - if(BKE_ptcache_id_exist((ID *)ob, clmd->sim_parms->lastcachedframe, stack_index)) - { - if(cloth_read_cache(ob, clmd, clmd->sim_parms->lastcachedframe)) - { - implicit_set_positions(clmd); - - // Copy the result back to the object. - cloth_to_object (ob, clmd, result); - } - } + + /* simulation is only active during a specific period */ + if(framenr < startframe) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; return result; } - - /* nice moving one frame forward */ - if ( deltaTime == 1.0f ) - { - clmd->sim_parms->sim_time = current_time; - - if(G.rt > 0) - printf("clothModifier_do deltaTime=1\n"); - - if(!cloth_read_cache(ob, clmd, framenr)) - { - verts = cloth->verts; - - // Force any pinned verts to their constrained location. - for ( i = 0; i < clmd->clothObject->numverts; i++, verts++ ) - { - // Save the previous position. - VECCOPY ( verts->xold, verts->xconst ); - VECCOPY ( verts->txold, verts->x ); + else if(framenr > endframe) { + framenr= endframe; + } - // Get the current position. - VECCOPY ( verts->xconst, mvert[i].co ); - Mat4MulVecfl ( ob->obmat, verts->xconst ); - } - - tstart(); + if(cache->flag & PTCACHE_SIMULATION_VALID) + framedelta= framenr - cache->simframe; + else + framedelta= -1; - // Call the solver. - if ( solvers [clmd->sim_parms->solver_type].solver ) - solvers [clmd->sim_parms->solver_type].solver ( ob, framenr, clmd, effectors ); + /* initialize simulation data if it didn't exist already */ + if(!do_init_cloth(ob, clmd, result, framenr)) + return result; - tend(); - // printf ( "Cloth simulation time: %f\n", ( float ) tval() ); + /* try to read from cache */ + if(cloth_read_cache(ob, clmd, framenr)) { + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; - cloth_write_cache(ob, clmd, framenr); - - // check for autoprotection - if(framenr >= clmd->sim_parms->autoprotect) - { - if(G.rt > 0) - printf("fr#: %f, auto: %d\n", framenr, clmd->sim_parms->autoprotect); - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_PROTECT; - } - if(G.rt > 0) - printf("clothModifier_do deltaTime=1 cachewrite\n"); - } - else - { - if(G.rt > 0) - printf("clothModifier_do deltaTime=1 cacheread\n"); - implicit_set_positions(clmd); - } - - // Copy the result back to the object. + implicit_set_positions(clmd); cloth_to_object (ob, clmd, result); + + return result; } - else if(deltaTime == 0.0f) - { - if(G.rt > 0) - printf("clothModifier_do deltaTime!=1 clmd->clothObject != NULL\n"); - if(cloth_read_cache(ob, clmd, framenr)) - { - cloth_to_object (ob, clmd, result); - implicit_set_positions(clmd); - } - else /* same cache parts are missing */ - { - /* - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET; - */ - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_CCACHE_FFREE; - cloth_clear_cache(ob, clmd, 0); - - cloth_write_cache(ob, clmd, framenr); - } + else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { + /* if baked and nothing in cache, do nothing */ + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + return result; } - else - { - if(G.rt > 0) - printf("clothModifier_do deltaTime!=1 clmd->clothObject != NULL\n"); - if(cloth_read_cache(ob, clmd, framenr)) - { - cloth_to_object (ob, clmd, result); - implicit_set_positions(clmd); - clmd->sim_parms->sim_time = current_time; + + if(framenr == startframe) { + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; + + /* don't write cache on first frame, but on second frame write + * cache for frame 1 and 2 */ + } + else if(framedelta == 1) { + /* if on second frame, write cache for first frame */ + if(framenr == startframe+1) + cloth_write_cache(ob, clmd, startframe); + + /* do simulation */ + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; + + if(!do_step_cloth(ob, clmd, result, framenr)) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; } else - { - /* jump to a non-existing frame makes sim reset */ - clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESET; - } + cloth_write_cache(ob, clmd, framenr); + + cloth_to_object (ob, clmd, result); } - + else { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } + return result; } @@ -901,14 +547,18 @@ void cloth_free_modifier ( Object *ob, ClothModifierData *clmd ) // we save our faces for collision objects if ( cloth->mfaces ) MEM_freeN ( cloth->mfaces ); + + if(cloth->edgehash) + BLI_edgehash_free ( cloth->edgehash, NULL ); + + /* if(clmd->clothObject->facemarks) - MEM_freeN(clmd->clothObject->facemarks); + MEM_freeN(clmd->clothObject->facemarks); */ MEM_freeN ( cloth ); clmd->clothObject = NULL; } - clmd->sim_parms->flags &= ~CLOTH_SIMSETTINGS_FLAG_RESET; } /* frees all */ @@ -916,7 +566,7 @@ void cloth_free_modifier_extern ( ClothModifierData *clmd ) { Cloth *cloth = NULL; if(G.rt > 0) - printf("cloth_free_modifier_extern\n"); + printf("cloth_free_modifier_extern\n"); if ( !clmd ) return; @@ -926,7 +576,7 @@ void cloth_free_modifier_extern ( ClothModifierData *clmd ) if ( cloth ) { if(G.rt > 0) - printf("cloth_free_modifier_extern in\n"); + printf("cloth_free_modifier_extern in\n"); // If our solver provides a free function, call it if ( solvers [clmd->sim_parms->solver_type].free ) @@ -967,6 +617,11 @@ void cloth_free_modifier_extern ( ClothModifierData *clmd ) // we save our faces for collision objects if ( cloth->mfaces ) MEM_freeN ( cloth->mfaces ); + + if(cloth->edgehash) + BLI_edgehash_free ( cloth->edgehash, NULL ); + + /* if(clmd->clothObject->facemarks) MEM_freeN(clmd->clothObject->facemarks); @@ -983,9 +638,9 @@ void cloth_free_modifier_extern ( ClothModifierData *clmd ) ******************************************************************************/ /** -* cloth_to_object - copies the deformed vertices to the object. -* -**/ + * cloth_to_object - copies the deformed vertices to the object. + * + **/ static void cloth_to_object (Object *ob, ClothModifierData *clmd, DerivedMesh *dm) { unsigned int i = 0; @@ -1010,9 +665,9 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, DerivedMesh * /** -* cloth_apply_vgroup - applies a vertex group as specified by type -* -**/ + * cloth_apply_vgroup - applies a vertex group as specified by type + * + **/ /* can be optimized to do all groups in one loop */ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) { @@ -1023,7 +678,6 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) unsigned int numverts = dm->getNumVerts ( dm ); float goalfac = 0; ClothVertex *verts = NULL; - // clmd->sim_parms->vgroup_mass clothObj = clmd->clothObject; @@ -1041,7 +695,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) (clmd->sim_parms->vgroup_bend>0))) { for ( i = 0; i < numverts; i++, verts++ ) - { + { dvert = dm->getVertData ( dm, i, CD_MDEFORMVERT ); if ( dvert ) { @@ -1059,7 +713,9 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) verts->goal = ( float ) pow ( verts->goal , 4.0f ); if ( verts->goal >=SOFTGOALSNAP ) - verts->flags |= CLOTH_VERT_FLAG_PINNED; + { + verts->flags |= CLOTH_VERT_FLAG_PINNED; + } } if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) @@ -1075,40 +731,33 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) verts->bend_stiff = dvert->dw [j].weight; } } + /* + // for later + if( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_weight-1)) + { + verts->mass = dvert->dw [j].weight; + } + */ } } } } } -/* -helper function to get proper spring length -when object is rescaled -*/ -float cloth_globallen ( float *v1,float *v2,Object *ob ) -{ - float p1[3],p2[3]; - VECCOPY ( p1,v1 ); - Mat4MulVecfl ( ob->obmat, p1 ); - VECCOPY ( p2,v2 ); - Mat4MulVecfl ( ob->obmat, p2 ); - return VecLenf ( p1,p2 ); -} - -static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr) +static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first) { unsigned int i = 0; MVert *mvert = NULL; ClothVertex *verts = NULL; float tnull[3] = {0,0,0}; - int cache_there = 0; + Cloth *cloth = NULL; // If we have a clothObject, free it. if ( clmd->clothObject != NULL ) { cloth_free_modifier ( ob, clmd ); if(G.rt > 0) - printf("cloth_free_modifier cloth_from_object\n"); + printf("cloth_free_modifier cloth_from_object\n"); } // Allocate a new cloth object. @@ -1117,6 +766,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d { clmd->clothObject->old_solver_type = 255; // clmd->clothObject->old_collision_type = 255; + cloth = clmd->clothObject; + clmd->clothObject->edgehash = NULL; } else if ( !clmd->clothObject ) { @@ -1130,21 +781,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d cloth_from_mesh ( ob, clmd, dm ); - if((clmd->sim_parms->firstcachedframe < 0.0) || ((clmd->sim_parms->firstcachedframe >= 0.0) && (!cloth_read_cache(ob, clmd, clmd->sim_parms->firstcachedframe)))) - { - // no cache there - cache_there = 0; - if(G.rt > 0) - printf("cache_there = 0\n"); - } - else - { - // we have a cache - cache_there = 1; - if(G.rt > 0) - printf("cache_there = 1, fcf: %d\n", clmd->sim_parms->firstcachedframe); - } - // create springs clmd->clothObject->springs = NULL; clmd->clothObject->numsprings = -1; @@ -1155,13 +791,15 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d // set initial values for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) { - if(!cache_there) + if(first) { VECCOPY ( verts->x, mvert[i].co ); Mat4MulVecfl ( ob->obmat, verts->x ); } - verts->mass = clmd->sim_parms->mass; + /* no GUI interface yet */ + verts->mass = clmd->sim_parms->mass; + verts->impulse_count = 0; if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) verts->goal= clmd->sim_parms->defgoal; @@ -1182,6 +820,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d // has to be happen before springs are build! cloth_apply_vgroup (clmd, dm); + if ( !cloth_build_springs ( clmd, dm ) ) { cloth_free_modifier ( ob, clmd ); @@ -1190,12 +829,24 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d return 0; } + for ( i = 0; i < dm->getNumVerts(dm); i++) + { + if((!(cloth->verts[i].flags & CLOTH_VERT_FLAG_PINNED)) && (cloth->verts[i].goal > ALMOST_ZERO)) + { + cloth_add_spring (clmd, i, i, 0.0, CLOTH_SPRING_TYPE_GOAL); + } + } + // init our solver - if ( solvers [clmd->sim_parms->solver_type].init ) + if ( solvers [clmd->sim_parms->solver_type].init ) { solvers [clmd->sim_parms->solver_type].init ( ob, clmd ); + } + + if(!first) + implicit_set_positions(clmd); clmd->clothObject->tree = bvh_build_from_cloth ( clmd, clmd->coll_parms->epsilon ); - + return 1; } @@ -1207,8 +858,7 @@ static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh * MFace *mface = CDDM_get_faces(dm); unsigned int i = 0; - /* Allocate our vertices. - */ + /* Allocate our vertices. */ clmd->clothObject->numverts = numverts; clmd->clothObject->verts = MEM_callocN ( sizeof ( ClothVertex ) * clmd->clothObject->numverts, "clothVertex" ); if ( clmd->clothObject->verts == NULL ) @@ -1257,21 +907,58 @@ int cloth_add_spring ( ClothModifierData *clmd, unsigned int indexA, unsigned in spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + if(!spring) + return 0; + spring->ij = indexA; spring->kl = indexB; spring->restlen = restlength; spring->type = spring_type; spring->flags = 0; + spring->stiffness = 0; cloth->numsprings++; - BLI_linklist_append ( &cloth->springs, spring ); + BLI_linklist_prepend ( &cloth->springs, spring ); return 1; } return 0; } +void cloth_free_errorsprings(Cloth *cloth, EdgeHash *edgehash, LinkNode **edgelist) +{ + unsigned int i = 0; + + if ( cloth->springs != NULL ) + { + LinkNode *search = cloth->springs; + while(search) + { + ClothSpring *spring = search->link; + + MEM_freeN ( spring ); + search = search->next; + } + BLI_linklist_free(cloth->springs, NULL); + + cloth->springs = NULL; + } + + if(edgelist) + { + for ( i = 0; i < cloth->numverts; i++ ) + { + BLI_linklist_free ( edgelist[i],NULL ); + } + + MEM_freeN ( edgelist ); + } + + if(cloth->edgehash) + BLI_edgehash_free ( cloth->edgehash, NULL ); +} + int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) { Cloth *cloth = clmd->clothObject; @@ -1288,7 +975,6 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) EdgeHash *edgehash = NULL; LinkNode *search = NULL, *search2 = NULL; float temp[3]; - LinkNode *node = NULL, *node2 = NULL; // error handling if ( numedges==0 ) @@ -1297,6 +983,10 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) cloth->springs = NULL; edgelist = MEM_callocN ( sizeof ( LinkNode * ) * numverts, "cloth_edgelist_alloc" ); + + if(!edgelist) + return 0; + for ( i = 0; i < numverts; i++ ) { edgelist[i] = NULL; @@ -1315,41 +1005,54 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) if ( spring ) { - spring->ij = medge[i].v1; - spring->kl = medge[i].v2; + spring->ij = MIN2(medge[i].v1, medge[i].v2); + spring->kl = MAX2(medge[i].v2, medge[i].v1); VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x ); spring->restlen = sqrt ( INPR ( temp, temp ) ); - /* - if(spring->restlen > 1.0) - { - printf("i: %d, L: %f\n", i, spring->restlen); - printf("%d, x: %f, y: %f, z: %f\n", cloth->verts[spring->ij].x[0], cloth->verts[spring->ij].x[1], spring->ij, cloth->verts[spring->ij].x[2]); - printf("%d, x: %f, y: %f, z: %f\n\n",spring->kl, cloth->verts[spring->kl].x[0], cloth->verts[spring->kl].x[1], cloth->verts[spring->kl].x[2]); - } - */ - clmd->coll_parms->avg_spring_len += spring->restlen; + clmd->sim_parms->avg_spring_len += spring->restlen; + cloth->verts[spring->ij].avg_spring_len += spring->restlen; + cloth->verts[spring->kl].avg_spring_len += spring->restlen; + cloth->verts[spring->ij].spring_count++; + cloth->verts[spring->kl].spring_count++; spring->type = CLOTH_SPRING_TYPE_STRUCTURAL; spring->flags = 0; spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0; struct_springs++; - if(!i) - node2 = BLI_linklist_append_fast ( &cloth->springs, spring ); - else - node2 = BLI_linklist_append_fast ( &node->next, spring ); - node = node2; + BLI_linklist_prepend ( &cloth->springs, spring ); + } + else + { + cloth_free_errorsprings(cloth, edgehash, edgelist); + return 0; } } - clmd->coll_parms->avg_spring_len /= struct_springs; + if(struct_springs > 0) + clmd->sim_parms->avg_spring_len /= struct_springs; + + for(i = 0; i < numverts; i++) + { + cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49 / ((float)cloth->verts[i].spring_count); + } // shear springs for ( i = 0; i < numfaces; i++ ) { + // triangle faces already have shear springs due to structural geometry + if ( !mface[i].v4 ) + continue; + spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + + if(!spring) + { + cloth_free_errorsprings(cloth, edgehash, edgelist); + return 0; + } - spring->ij = mface[i].v1; - spring->kl = mface[i].v3; + spring->ij = MIN2(mface[i].v1, mface[i].v3); + spring->kl = MAX2(mface[i].v3, mface[i].v1); VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_SHEAR; @@ -1359,27 +1062,30 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) BLI_linklist_append ( &edgelist[spring->kl], spring ); shear_springs++; - node2 = BLI_linklist_append_fast ( &node->next, spring ); - node = node2; + BLI_linklist_prepend ( &cloth->springs, spring ); - if ( mface[i].v4 ) + + // if ( mface[i].v4 ) --> Quad face + spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + + if(!spring) { - spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + cloth_free_errorsprings(cloth, edgehash, edgelist); + return 0; + } - spring->ij = mface[i].v2; - spring->kl = mface[i].v4; - VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x ); - spring->restlen = sqrt ( INPR ( temp, temp ) ); - spring->type = CLOTH_SPRING_TYPE_SHEAR; - spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; + spring->ij = MIN2(mface[i].v2, mface[i].v4); + spring->kl = MAX2(mface[i].v4, mface[i].v2); + VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x ); + spring->restlen = sqrt ( INPR ( temp, temp ) ); + spring->type = CLOTH_SPRING_TYPE_SHEAR; + spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0; - BLI_linklist_append ( &edgelist[spring->ij], spring ); - BLI_linklist_append ( &edgelist[spring->kl], spring ); - shear_springs++; + BLI_linklist_append ( &edgelist[spring->ij], spring ); + BLI_linklist_append ( &edgelist[spring->kl], spring ); + shear_springs++; - node2 = BLI_linklist_append_fast ( &node->next, spring ); - node = node2; - } + BLI_linklist_prepend ( &cloth->springs, spring ); } // bending springs @@ -1398,39 +1104,64 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) // check for existing spring // check also if startpoint is equal to endpoint - if ( !BLI_edgehash_haskey ( edgehash, index2, tspring2->ij ) - && !BLI_edgehash_haskey ( edgehash, tspring2->ij, index2 ) - && ( index2!=tspring2->ij ) ) + if ( !BLI_edgehash_haskey ( edgehash, MIN2(tspring2->ij, index2), MAX2(tspring2->ij, index2) ) + && ( index2!=tspring2->ij ) ) { spring = ( ClothSpring * ) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + + if(!spring) + { + cloth_free_errorsprings(cloth, edgehash, edgelist); + return 0; + } - spring->ij = tspring2->ij; - spring->kl = index2; - VECSUB ( temp, cloth->verts[index2].x, cloth->verts[tspring2->ij].x ); + spring->ij = MIN2(tspring2->ij, index2); + spring->kl = MAX2(tspring2->ij, index2); + VECSUB ( temp, cloth->verts[spring->kl].x, cloth->verts[spring->ij].x ); spring->restlen = sqrt ( INPR ( temp, temp ) ); spring->type = CLOTH_SPRING_TYPE_BENDING; spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0; - BLI_edgehash_insert ( edgehash, spring->ij, index2, NULL ); + BLI_edgehash_insert ( edgehash, spring->ij, spring->kl, NULL ); bend_springs++; - node2 = BLI_linklist_append_fast ( &node->next, spring ); - node = node2; + BLI_linklist_prepend ( &cloth->springs, spring ); } search = search->next; } search2 = search2->next; } - cloth->numsprings = struct_springs + shear_springs + bend_springs; + /* insert other near springs in edgehash AFTER bending springs are calculated (for selfcolls) */ + for ( i = 0; i < numedges; i++ ) // struct springs + BLI_edgehash_insert ( edgehash, MIN2(medge[i].v1, medge[i].v2), MAX2(medge[i].v2, medge[i].v1), NULL ); - for ( i = 0; i < numverts; i++ ) + for ( i = 0; i < numfaces; i++ ) // edge springs { - BLI_linklist_free ( edgelist[i],NULL ); + if(mface[i].v4) + { + BLI_edgehash_insert ( edgehash, MIN2(mface[i].v1, mface[i].v3), MAX2(mface[i].v3, mface[i].v1), NULL ); + + BLI_edgehash_insert ( edgehash, MIN2(mface[i].v2, mface[i].v4), MAX2(mface[i].v2, mface[i].v4), NULL ); + } } + + + cloth->numsprings = struct_springs + shear_springs + bend_springs; + if ( edgelist ) + { + for ( i = 0; i < numverts; i++ ) + { + BLI_linklist_free ( edgelist[i],NULL ); + } + MEM_freeN ( edgelist ); + } + + cloth->edgehash = edgehash; - BLI_edgehash_free ( edgehash, NULL ); + if(G.rt>0) + printf("avg_len: %f\n",clmd->sim_parms->avg_spring_len); return 1; diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 0689b8b6dd2..e244ccca306 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1,15 +1,12 @@ -/* collision.c -* +/* collision.c * -* ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +* +* ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. The Blender -* Foundation also sells licenses for use in proprietary software under -* the Blender License. See http://www.blender.org/BL/ for information -* about this. +* of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,34 +24,20 @@ * * Contributor(s): none yet. * -* ***** END GPL/BL DUAL LICENSE BLOCK ***** +* ***** END GPL LICENSE BLOCK ***** */ -#include <math.h> -#include <stdlib.h> -#include <string.h> #include "MEM_guardedalloc.h" -/* types */ -#include "DNA_curve_types.h" + +#include "BKE_cloth.h" + +#include "DNA_group_types.h" #include "DNA_object_types.h" -#include "DNA_object_force.h" -#include "DNA_cloth_types.h" -#include "DNA_key_types.h" +#include "DNA_cloth_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_lattice_types.h" #include "DNA_scene_types.h" -#include "DNA_modifier_types.h" -#include "BLI_blenlib.h" -#include "BLI_arithb.h" -#include "BLI_edgehash.h" -#include "BLI_linklist.h" -#include "BKE_curve.h" -#include "BKE_deform.h" + #include "BKE_DerivedMesh.h" -#include "BKE_cdderivedmesh.h" -#include "BKE_displist.h" -#include "BKE_effect.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -62,10 +45,6 @@ #include "BKE_modifier.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" -#include "DNA_screen_types.h" -#include "BSE_headerbuttons.h" -#include "BIF_screen.h" -#include "BIF_space.h" #include "mydevice.h" #include "Bullet-C-Api.h" @@ -75,71 +54,70 @@ Collision modifier code start ***********************************/ /* step is limited from 0 (frame start position) to 1 (frame end position) */ -void collision_move_object(CollisionModifierData *collmd, float step, float prevstep) +void collision_move_object ( CollisionModifierData *collmd, float step, float prevstep ) { float tv[3] = {0,0,0}; unsigned int i = 0; - + for ( i = 0; i < collmd->numverts; i++ ) { - VECSUB(tv, collmd->xnew[i].co, collmd->x[i].co); - VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep); - VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step); - VECSUB(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co); + VECSUB ( tv, collmd->xnew[i].co, collmd->x[i].co ); + VECADDS ( collmd->current_x[i].co, collmd->x[i].co, tv, prevstep ); + VECADDS ( collmd->current_xnew[i].co, collmd->x[i].co, tv, step ); + VECSUB ( collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co ); } + bvh_update_from_mvert ( collmd->bvh, collmd->current_x, collmd->numverts, collmd->current_xnew, 1 ); } /* build bounding volume hierarchy from mverts (see kdop.c for whole BVH code) */ -BVH *bvh_build_from_mvert (MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon) +BVH *bvh_build_from_mvert ( MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon ) { BVH *bvh=NULL; - - bvh = MEM_callocN(sizeof(BVH), "BVH"); - if (bvh == NULL) + + bvh = MEM_callocN ( sizeof ( BVH ), "BVH" ); + if ( bvh == NULL ) { - printf("bvh: Out of memory.\n"); + printf ( "bvh: Out of memory.\n" ); return NULL; } - - bvh->flags = 0; - bvh->leaf_tree = NULL; - bvh->leaf_root = NULL; - bvh->tree = NULL; + + // in the moment, return zero if no faces there + if ( !numfaces ) + return NULL; bvh->epsilon = epsilon; bvh->numfaces = numfaces; bvh->mfaces = mfaces; - + // we have no faces, we save seperate points - if(!mfaces) + if ( !mfaces ) { bvh->numfaces = numverts; } bvh->numverts = numverts; - bvh->current_x = MEM_dupallocN(x); - bvh->current_xold = MEM_dupallocN(x); - - bvh_build(bvh); - + bvh->current_x = MEM_dupallocN ( x ); + + bvh_build ( bvh ); + return bvh; } -void bvh_update_from_mvert(BVH * bvh, MVert *x, unsigned int numverts, MVert *xnew, int moving) +void bvh_update_from_mvert ( BVH * bvh, MVert *x, unsigned int numverts, MVert *xnew, int moving ) { - if(!bvh) + if ( !bvh ) return; - - if(numverts!=bvh->numverts) + + if ( numverts!=bvh->numverts ) return; - - if(x) - memcpy(bvh->current_xold, x, sizeof(MVert) * numverts); - - if(xnew) - memcpy(bvh->current_x, xnew, sizeof(MVert) * numverts); - - bvh_update(bvh, moving); + + if ( x ) + memcpy ( bvh->current_xold, x, sizeof ( MVert ) * numverts ); + + if ( xnew ) + memcpy ( bvh->current_x, xnew, sizeof ( MVert ) * numverts ); + + bvh_update ( bvh, moving ); } /*********************************** @@ -151,12 +129,14 @@ Collision modifier code end * * copied from SOLVE_CUBIC.C --> GSL */ + +/* DG: debug hint! don't forget that all functions were "fabs", "sinf", etc before */ #define mySWAP(a,b) { float tmp = b ; b = a ; a = tmp ; } -int gsl_poly_solve_cubic (float a, float b, float c, float *x0, float *x1, float *x2) +int gsl_poly_solve_cubic ( float a, float b, float c, float *x0, float *x1, float *x2 ) { - float q = (a * a - 3 * b); - float r = (2 * a * a * a - 9 * a * b + 27 * c); + float q = ( a * a - 3 * b ); + float r = ( 2 * a * a * a - 9 * a * b + 27 * c ); float Q = q / 9; float R = r / 54; @@ -167,25 +147,25 @@ int gsl_poly_solve_cubic (float a, float b, float c, float *x0, float *x1, float float CR2 = 729 * r * r; float CQ3 = 2916 * q * q * q; - if (R == 0 && Q == 0) + if ( R == 0 && Q == 0 ) { *x0 = - a / 3 ; *x1 = - a / 3 ; *x2 = - a / 3 ; return 3 ; } - else if (CR2 == CQ3) + else if ( CR2 == CQ3 ) { - /* this test is actually R2 == Q3, written in a form suitable - for exact computation with integers */ + /* this test is actually R2 == Q3, written in a form suitable + for exact computation with integers */ - /* Due to finite precision some float roots may be missed, and - considered to be a pair of complex roots z = x +/- epsilon i - close to the real axis. */ + /* Due to finite precision some float roots may be missed, and + considered to be a pair of complex roots z = x +/- epsilon i + close to the real axis. */ - float sqrtQ = sqrtf (Q); + float sqrtQ = sqrt ( Q ); - if (R > 0) + if ( R > 0 ) { *x0 = -2 * sqrtQ - a / 3; *x1 = sqrtQ - a / 3; @@ -199,35 +179,35 @@ int gsl_poly_solve_cubic (float a, float b, float c, float *x0, float *x1, float } return 3 ; } - else if (CR2 < CQ3) /* equivalent to R2 < Q3 */ + else if ( CR2 < CQ3 ) /* equivalent to R2 < Q3 */ { - float sqrtQ = sqrtf (Q); + float sqrtQ = sqrt ( Q ); float sqrtQ3 = sqrtQ * sqrtQ * sqrtQ; - float theta = acosf (R / sqrtQ3); + float theta = acos ( R / sqrtQ3 ); float norm = -2 * sqrtQ; - *x0 = norm * cosf (theta / 3) - a / 3; - *x1 = norm * cosf ((theta + 2.0 * M_PI) / 3) - a / 3; - *x2 = norm * cosf ((theta - 2.0 * M_PI) / 3) - a / 3; - + *x0 = norm * cos ( theta / 3 ) - a / 3; + *x1 = norm * cos ( ( theta + 2.0 * M_PI ) / 3 ) - a / 3; + *x2 = norm * cos ( ( theta - 2.0 * M_PI ) / 3 ) - a / 3; + /* Sort *x0, *x1, *x2 into increasing order */ - if (*x0 > *x1) - mySWAP(*x0, *x1) ; - - if (*x1 > *x2) + if ( *x0 > *x1 ) + mySWAP ( *x0, *x1 ) ; + + if ( *x1 > *x2 ) { - mySWAP(*x1, *x2) ; - - if (*x0 > *x1) - mySWAP(*x0, *x1) ; + mySWAP ( *x1, *x2 ) ; + + if ( *x0 > *x1 ) + mySWAP ( *x0, *x1 ) ; } - + return 3; } else { - float sgnR = (R >= 0 ? 1 : -1); - float A = -sgnR * powf (fabs (R) + sqrtf (R2 - Q3), 1.0/3.0); + float sgnR = ( R >= 0 ? 1 : -1 ); + float A = -sgnR * pow ( ABS ( R ) + sqrt ( R2 - Q3 ), 1.0/3.0 ); float B = Q / A ; *x0 = A + B - a / 3; return 1; @@ -240,31 +220,31 @@ int gsl_poly_solve_cubic (float a, float b, float c, float *x0, float *x1, float * * copied from GSL */ -int gsl_poly_solve_quadratic (float a, float b, float c, float *x0, float *x1) +int gsl_poly_solve_quadratic ( float a, float b, float c, float *x0, float *x1 ) { float disc = b * b - 4 * a * c; - if (disc > 0) + if ( disc > 0 ) { - if (b == 0) + if ( b == 0 ) { - float r = fabs (0.5 * sqrtf (disc) / a); + float r = ABS ( 0.5 * sqrt ( disc ) / a ); *x0 = -r; *x1 = r; } else { - float sgnb = (b > 0 ? 1 : -1); - float temp = -0.5 * (b + sgnb * sqrtf (disc)); + float sgnb = ( b > 0 ? 1 : -1 ); + float temp = -0.5 * ( b + sgnb * sqrt ( disc ) ); float r1 = temp / a ; float r2 = c / temp ; - if (r1 < r2) + if ( r1 < r2 ) { *x0 = r1 ; *x1 = r2 ; - } - else + } + else { *x0 = r2 ; *x1 = r1 ; @@ -272,7 +252,7 @@ int gsl_poly_solve_quadratic (float a, float b, float c, float *x0, float *x1) } return 2; } - else if (disc == 0) + else if ( disc == 0 ) { *x0 = -0.5 * b / a ; *x1 = -0.5 * b / a ; @@ -291,56 +271,56 @@ int gsl_poly_solve_quadratic (float a, float b, float c, float *x0, float *x1) * page 4, left column */ -int cloth_get_collision_time(float a[3], float b[3], float c[3], float d[3], float e[3], float f[3], float solution[3]) +int cloth_get_collision_time ( float a[3], float b[3], float c[3], float d[3], float e[3], float f[3], float solution[3] ) { int num_sols = 0; - + float g = -a[2] * c[1] * e[0] + a[1] * c[2] * e[0] + - a[2] * c[0] * e[1] - a[0] * c[2] * e[1] - - a[1] * c[0] * e[2] + a[0] * c[1] * e[2]; + a[2] * c[0] * e[1] - a[0] * c[2] * e[1] - + a[1] * c[0] * e[2] + a[0] * c[1] * e[2]; float h = -b[2] * c[1] * e[0] + b[1] * c[2] * e[0] - a[2] * d[1] * e[0] + - a[1] * d[2] * e[0] + b[2] * c[0] * e[1] - b[0] * c[2] * e[1] + - a[2] * d[0] * e[1] - a[0] * d[2] * e[1] - b[1] * c[0] * e[2] + - b[0] * c[1] * e[2] - a[1] * d[0] * e[2] + a[0] * d[1] * e[2] - - a[2] * c[1] * f[0] + a[1] * c[2] * f[0] + a[2] * c[0] * f[1] - - a[0] * c[2] * f[1] - a[1] * c[0] * f[2] + a[0] * c[1] * f[2]; + a[1] * d[2] * e[0] + b[2] * c[0] * e[1] - b[0] * c[2] * e[1] + + a[2] * d[0] * e[1] - a[0] * d[2] * e[1] - b[1] * c[0] * e[2] + + b[0] * c[1] * e[2] - a[1] * d[0] * e[2] + a[0] * d[1] * e[2] - + a[2] * c[1] * f[0] + a[1] * c[2] * f[0] + a[2] * c[0] * f[1] - + a[0] * c[2] * f[1] - a[1] * c[0] * f[2] + a[0] * c[1] * f[2]; float i = -b[2] * d[1] * e[0] + b[1] * d[2] * e[0] + - b[2] * d[0] * e[1] - b[0] * d[2] * e[1] - - b[1] * d[0] * e[2] + b[0] * d[1] * e[2] - - b[2] * c[1] * f[0] + b[1] * c[2] * f[0] - - a[2] * d[1] * f[0] + a[1] * d[2] * f[0] + - b[2] * c[0] * f[1] - b[0] * c[2] * f[1] + - a[2] * d[0] * f[1] - a[0] * d[2] * f[1] - - b[1] * c[0] * f[2] + b[0] * c[1] * f[2] - - a[1] * d[0] * f[2] + a[0] * d[1] * f[2]; + b[2] * d[0] * e[1] - b[0] * d[2] * e[1] - + b[1] * d[0] * e[2] + b[0] * d[1] * e[2] - + b[2] * c[1] * f[0] + b[1] * c[2] * f[0] - + a[2] * d[1] * f[0] + a[1] * d[2] * f[0] + + b[2] * c[0] * f[1] - b[0] * c[2] * f[1] + + a[2] * d[0] * f[1] - a[0] * d[2] * f[1] - + b[1] * c[0] * f[2] + b[0] * c[1] * f[2] - + a[1] * d[0] * f[2] + a[0] * d[1] * f[2]; float j = -b[2] * d[1] * f[0] + b[1] * d[2] * f[0] + - b[2] * d[0] * f[1] - b[0] * d[2] * f[1] - - b[1] * d[0] * f[2] + b[0] * d[1] * f[2]; + b[2] * d[0] * f[1] - b[0] * d[2] * f[1] - + b[1] * d[0] * f[2] + b[0] * d[1] * f[2]; // Solve cubic equation to determine times t1, t2, t3, when the collision will occur. - if(ABS(j) > ALMOST_ZERO) + if ( ABS ( j ) > ALMOST_ZERO ) { i /= j; h /= j; g /= j; - - num_sols = gsl_poly_solve_cubic(i, h, g, &solution[0], &solution[1], &solution[2]); + + num_sols = gsl_poly_solve_cubic ( i, h, g, &solution[0], &solution[1], &solution[2] ); } - else if(ABS(i) > ALMOST_ZERO) - { - num_sols = gsl_poly_solve_quadratic(i, h, g, &solution[0], &solution[1]); + else if ( ABS ( i ) > ALMOST_ZERO ) + { + num_sols = gsl_poly_solve_quadratic ( i, h, g, &solution[0], &solution[1] ); solution[2] = -1.0; } - else if(ABS(h) > ALMOST_ZERO) + else if ( ABS ( h ) > ALMOST_ZERO ) { solution[0] = -g / h; solution[1] = solution[2] = -1.0; num_sols = 1; } - else if(ABS(g) > ALMOST_ZERO) + else if ( ABS ( g ) > ALMOST_ZERO ) { solution[0] = 0; solution[1] = solution[2] = -1.0; @@ -348,42 +328,45 @@ int cloth_get_collision_time(float a[3], float b[3], float c[3], float d[3], flo } // Discard negative solutions - if ((num_sols >= 1) && (solution[0] < 0)) + if ( ( num_sols >= 1 ) && ( solution[0] < 0 ) ) { --num_sols; solution[0] = solution[num_sols]; } - if ((num_sols >= 2) && (solution[1] < 0)) + if ( ( num_sols >= 2 ) && ( solution[1] < 0 ) ) { --num_sols; solution[1] = solution[num_sols]; } - if ((num_sols == 3) && (solution[2] < 0)) + if ( ( num_sols == 3 ) && ( solution[2] < 0 ) ) { --num_sols; } // Sort - if (num_sols == 2) + if ( num_sols == 2 ) { - if (solution[0] > solution[1]) + if ( solution[0] > solution[1] ) { double tmp = solution[0]; solution[0] = solution[1]; solution[1] = tmp; } } - else if (num_sols == 3) + else if ( num_sols == 3 ) { // Bubblesort - if (solution[0] > solution[1]) { + if ( solution[0] > solution[1] ) + { double tmp = solution[0]; solution[0] = solution[1]; solution[1] = tmp; } - if (solution[1] > solution[2]) { + if ( solution[1] > solution[2] ) + { double tmp = solution[1]; solution[1] = solution[2]; solution[2] = tmp; } - if (solution[0] > solution[1]) { + if ( solution[0] > solution[1] ) + { double tmp = solution[0]; solution[0] = solution[1]; solution[1] = tmp; } } @@ -392,63 +375,52 @@ int cloth_get_collision_time(float a[3], float b[3], float c[3], float d[3], flo } // w3 is not perfect -void cloth_compute_barycentric (float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3) +void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 ) { double tempV1[3], tempV2[3], tempV4[3]; double a,b,c,d,e,f; - VECSUB (tempV1, p1, p3); - VECSUB (tempV2, p2, p3); - VECSUB (tempV4, pv, p3); - - a = INPR (tempV1, tempV1); - b = INPR (tempV1, tempV2); - c = INPR (tempV2, tempV2); - e = INPR (tempV1, tempV4); - f = INPR (tempV2, tempV4); - - d = (a * c - b * b); - - if (ABS(d) < ALMOST_ZERO) { + VECSUB ( tempV1, p1, p3 ); + VECSUB ( tempV2, p2, p3 ); + VECSUB ( tempV4, pv, p3 ); + + a = INPR ( tempV1, tempV1 ); + b = INPR ( tempV1, tempV2 ); + c = INPR ( tempV2, tempV2 ); + e = INPR ( tempV1, tempV4 ); + f = INPR ( tempV2, tempV4 ); + + d = ( a * c - b * b ); + + if ( ABS ( d ) < ALMOST_ZERO ) + { *w1 = *w2 = *w3 = 1.0 / 3.0; return; } - - w1[0] = (float)((e * c - b * f) / d); - - if(w1[0] < 0) + + w1[0] = ( float ) ( ( e * c - b * f ) / d ); + + if ( w1[0] < 0 ) w1[0] = 0; - - w2[0] = (float)((f - b * (double)w1[0]) / c); - - if(w2[0] < 0) + + w2[0] = ( float ) ( ( f - b * ( double ) w1[0] ) / c ); + + if ( w2[0] < 0 ) w2[0] = 0; - + w3[0] = 1.0f - w1[0] - w2[0]; } -DO_INLINE void interpolateOnTriangle(float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3) +DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3], double w1, double w2, double w3 ) { to[0] = to[1] = to[2] = 0; - VECADDMUL(to, v1, w1); - VECADDMUL(to, v2, w2); - VECADDMUL(to, v3, w3); + VECADDMUL ( to, v1, w1 ); + VECADDMUL ( to, v2, w2 ); + VECADDMUL ( to, v3, w3 ); } -// unused in the moment, has some bug in -DO_INLINE void calculateFrictionImpulse(float to[3], float vrel[3], float normal[3], double normalVelocity, - double frictionConstant, double delta_V_n) +int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd ) { - float vrel_t_pre[3]; - float vrel_t[3]; - VECSUBS(vrel_t_pre, vrel, normal, normalVelocity); - VECCOPY(to, vrel_t_pre); - VecMulf(to, MAX2(1.0f - frictionConstant * delta_V_n / INPR(vrel_t_pre,vrel_t_pre), 0.0f)); -} - -int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd) -{ - unsigned int i = 0; int result = 0; LinkNode *search = NULL; CollPair *collpair = NULL; @@ -456,185 +428,172 @@ int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierDa float w1, w2, w3, u1, u2, u3; float v1[3], v2[3], relativeVelocity[3]; float magrelVel; - + float epsilon2 = collmd->bvh->epsilon; + cloth1 = clmd->clothObject; search = clmd->coll_parms->collision_list; - - while(search) + + while ( search ) { collpair = search->link; - + // compute barycentric coordinates for both collision points - cloth_compute_barycentric(collpair->pa, - cloth1->verts[collpair->ap1].txold, - cloth1->verts[collpair->ap2].txold, - cloth1->verts[collpair->ap3].txold, - &w1, &w2, &w3); - + collision_compute_barycentric ( collpair->pa, + cloth1->verts[collpair->ap1].txold, + cloth1->verts[collpair->ap2].txold, + cloth1->verts[collpair->ap3].txold, + &w1, &w2, &w3 ); + // was: txold - cloth_compute_barycentric(collpair->pb, - collmd->current_x[collpair->bp1].co, - collmd->current_x[collpair->bp2].co, - collmd->current_x[collpair->bp3].co, - &u1, &u2, &u3); - + collision_compute_barycentric ( collpair->pb, + collmd->current_x[collpair->bp1].co, + collmd->current_x[collpair->bp2].co, + collmd->current_x[collpair->bp3].co, + &u1, &u2, &u3 ); + // Calculate relative "velocity". - interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3); - - interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3); - - VECSUB(relativeVelocity, v1, v2); - + collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 ); + + collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 ); + + VECSUB ( relativeVelocity, v2, v1 ); + // Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). - magrelVel = INPR(relativeVelocity, collpair->normal); - + magrelVel = INPR ( relativeVelocity, collpair->normal ); + // printf("magrelVel: %f\n", magrelVel); - + // Calculate masses of points. - + // TODO + // If v_n_mag < 0 the edges are approaching each other. - if(magrelVel < -ALMOST_ZERO) + if ( magrelVel > ALMOST_ZERO ) { // Calculate Impulse magnitude to stop all motion in normal direction. - // const double I_mag = v_n_mag / (1/m1 + 1/m2); - float magnitude_i = magrelVel / 2.0f; // TODO implement masses - float tangential[3], magtangent, magnormal, collvel[3]; + float magtangent = 0, repulse = 0, d = 0; + double impulse = 0.0; float vrel_t_pre[3]; - float vrel_t[3]; - double impulse; - float epsilon = clmd->coll_parms->epsilon; - float overlap = (epsilon + ALMOST_ZERO-collpair->distance); - - // calculateFrictionImpulse(tangential, relativeVelocity, collpair->normal, magrelVel, clmd->coll_parms->friction*0.01, magrelVel); - - // magtangent = INPR(tangential, tangential); - + float temp[3]; + + // calculate tangential velocity + VECCOPY ( temp, collpair->normal ); + VecMulf ( temp, magrelVel ); + VECSUB ( vrel_t_pre, relativeVelocity, temp ); + + // Decrease in magnitude of relative tangential velocity due to coulomb friction + // in original formula "magrelVel" should be the "change of relative velocity in normal direction" + magtangent = MIN2 ( clmd->coll_parms->friction * 0.01 * magrelVel,sqrt ( INPR ( vrel_t_pre,vrel_t_pre ) ) ); + // Apply friction impulse. - if (magtangent < -ALMOST_ZERO) + if ( magtangent > ALMOST_ZERO ) { - - // printf("friction applied: %f\n", magtangent); - // TODO check original code - /* - VECSUB(cloth1->verts[face1->v1].tv, cloth1->verts[face1->v1].tv,tangential); - VECSUB(cloth1->verts[face1->v1].tv, cloth1->verts[face1->v2].tv,tangential); - VECSUB(cloth1->verts[face1->v1].tv, cloth1->verts[face1->v3].tv,tangential); - VECSUB(cloth1->verts[face1->v1].tv, cloth1->verts[face1->v4].tv,tangential); - */ + Normalize ( vrel_t_pre ); + + impulse = 2.0 * magtangent / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); + VECADDMUL ( cloth1->verts[collpair->ap1].impulse, vrel_t_pre, w1 * impulse ); + VECADDMUL ( cloth1->verts[collpair->ap2].impulse, vrel_t_pre, w2 * impulse ); + VECADDMUL ( cloth1->verts[collpair->ap3].impulse, vrel_t_pre, w3 * impulse ); } - - impulse = -2.0f * magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3); - - // printf("impulse: %f\n", impulse); - - VECADDMUL(cloth1->verts[collpair->ap1].impulse, collpair->normal, w1 * impulse); + // Apply velocity stopping impulse + // I_c = m * v_N / 2.0 + // no 2.0 * magrelVel normally, but looks nicer DG + impulse = magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); + + VECADDMUL ( cloth1->verts[collpair->ap1].impulse, collpair->normal, w1 * impulse ); cloth1->verts[collpair->ap1].impulse_count++; - - VECADDMUL(cloth1->verts[collpair->ap2].impulse, collpair->normal, w2 * impulse); + + VECADDMUL ( cloth1->verts[collpair->ap2].impulse, collpair->normal, w2 * impulse ); cloth1->verts[collpair->ap2].impulse_count++; - - VECADDMUL(cloth1->verts[collpair->ap3].impulse, collpair->normal, w3 * impulse); + + VECADDMUL ( cloth1->verts[collpair->ap3].impulse, collpair->normal, w3 * impulse ); cloth1->verts[collpair->ap3].impulse_count++; - + + // Apply repulse impulse if distance too short + // I_r = -min(dt*kd, m(0,1d/dt - v_n)) + d = clmd->coll_parms->epsilon*8.0/9.0 + epsilon2*8.0/9.0 - collpair->distance; + if ( ( magrelVel < 0.1*d*clmd->sim_parms->stepsPerFrame ) && ( d > ALMOST_ZERO ) ) + { + repulse = MIN2 ( d*1.0/clmd->sim_parms->stepsPerFrame, 0.1*d*clmd->sim_parms->stepsPerFrame - magrelVel ); + + // stay on the safe side and clamp repulse + if ( impulse > ALMOST_ZERO ) + repulse = MIN2 ( repulse, 5.0*impulse ); + repulse = MAX2 ( impulse, repulse ); + + impulse = repulse / ( 1.0 + w1*w1 + w2*w2 + w3*w3 ); // original 2.0 / 0.25 + VECADDMUL ( cloth1->verts[collpair->ap1].impulse, collpair->normal, impulse ); + VECADDMUL ( cloth1->verts[collpair->ap2].impulse, collpair->normal, impulse ); + VECADDMUL ( cloth1->verts[collpair->ap3].impulse, collpair->normal, impulse ); + } + result = 1; - - /* - if (overlap > ALMOST_ZERO) { - double I_mag = overlap * 0.1; - - impulse = -I_mag / ( 1.0 + w1*w1 + w2*w2 + w3*w3); - - VECADDMUL(cloth1->verts[collpair->ap1].impulse, collpair->normal, w1 * impulse); - cloth1->verts[collpair->ap1].impulse_count++; - - VECADDMUL(cloth1->verts[collpair->ap2].impulse, collpair->normal, w2 * impulse); - cloth1->verts[collpair->ap2].impulse_count++; - - VECADDMUL(cloth1->verts[collpair->ap3].impulse, collpair->normal, w3 * impulse); - cloth1->verts[collpair->ap3].impulse_count++; - } - */ - - // printf("magnitude_i: %f\n", magnitude_i); // negative before collision in my case - - // Apply the impulse and increase impulse counters. - - /* - // calculateFrictionImpulse(tangential, collvel, collpair->normal, magtangent, clmd->coll_parms->friction*0.01, magtangent); - VECSUBS(vrel_t_pre, collvel, collpair->normal, magnormal); - // VecMulf(vrel_t_pre, clmd->coll_parms->friction*0.01f/INPR(vrel_t_pre,vrel_t_pre)); - magtangent = Normalize(vrel_t_pre); - VecMulf(vrel_t_pre, MIN2(clmd->coll_parms->friction*0.01f*magnormal,magtangent)); - - VECSUB(cloth1->verts[face1->v1].tv, cloth1->verts[face1->v1].tv,vrel_t_pre); - */ - - - } - + search = search->next; } - - + + return result; } -int cloth_collision_response_moving_tris(ClothModifierData *clmd, ClothModifierData *coll_clmd) +int cloth_collision_response_moving_tris ( ClothModifierData *clmd, ClothModifierData *coll_clmd ) { return 1; } -int cloth_collision_response_moving_edges(ClothModifierData *clmd, ClothModifierData *coll_clmd) +int cloth_collision_response_moving_edges ( ClothModifierData *clmd, ClothModifierData *coll_clmd ) { return 1; } -void cloth_collision_static(ClothModifierData *clmd, CollisionModifierData *collmd, CollisionTree *tree1, CollisionTree *tree2) +void cloth_collision_static ( ModifierData *md1, ModifierData *md2, CollisionTree *tree1, CollisionTree *tree2 ) { + ClothModifierData *clmd = ( ClothModifierData * ) md1; + CollisionModifierData *collmd = ( CollisionModifierData * ) md2; CollPair *collpair = NULL; Cloth *cloth1=NULL; MFace *face1=NULL, *face2=NULL; ClothVertex *verts1=NULL; double distance = 0; float epsilon = clmd->coll_parms->epsilon; + float epsilon2 = ( ( CollisionModifierData * ) md2 )->bvh->epsilon; unsigned int i = 0; - for(i = 0; i < 4; i++) + for ( i = 0; i < 4; i++ ) { - collpair = (CollPair *)MEM_callocN(sizeof(CollPair), "cloth coll pair"); - + collpair = ( CollPair * ) MEM_callocN ( sizeof ( CollPair ), "cloth coll pair" ); + cloth1 = clmd->clothObject; - + verts1 = cloth1->verts; - - face1 = &(cloth1->mfaces[tree1->tri_index]); - face2 = &(collmd->mfaces[tree2->tri_index]); - + + face1 = & ( cloth1->mfaces[tree1->tri_index] ); + face2 = & ( collmd->mfaces[tree2->tri_index] ); + // check all possible pairs of triangles - if(i == 0) + if ( i == 0 ) { collpair->ap1 = face1->v1; collpair->ap2 = face1->v2; collpair->ap3 = face1->v3; - + collpair->bp1 = face2->v1; collpair->bp2 = face2->v2; collpair->bp3 = face2->v3; - + } - - if(i == 1) + + if ( i == 1 ) { - if(face1->v4) + if ( face1->v4 ) { collpair->ap1 = face1->v3; collpair->ap2 = face1->v4; collpair->ap3 = face1->v1; - + collpair->bp1 = face2->v1; collpair->bp2 = face2->v2; collpair->bp3 = face2->v3; @@ -642,15 +601,15 @@ void cloth_collision_static(ClothModifierData *clmd, CollisionModifierData *coll else i++; } - - if(i == 2) + + if ( i == 2 ) { - if(face2->v4) + if ( face2->v4 ) { collpair->ap1 = face1->v1; collpair->ap2 = face1->v2; collpair->ap3 = face1->v3; - + collpair->bp1 = face2->v3; collpair->bp2 = face2->v4; collpair->bp3 = face2->v1; @@ -658,15 +617,15 @@ void cloth_collision_static(ClothModifierData *clmd, CollisionModifierData *coll else i+=2; } - - if(i == 3) + + if ( i == 3 ) { - if((face1->v4)&&(face2->v4)) + if ( ( face1->v4 ) && ( face2->v4 ) ) { collpair->ap1 = face1->v3; collpair->ap2 = face1->v4; collpair->ap3 = face1->v1; - + collpair->bp1 = face2->v3; collpair->bp2 = face2->v4; collpair->bp3 = face2->v1; @@ -674,126 +633,128 @@ void cloth_collision_static(ClothModifierData *clmd, CollisionModifierData *coll else i++; } - + // calc SIPcode (?) - - if(i < 4) + + if ( i < 4 ) { - // calc distance + normal - distance = plNearestPoints( - verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa,collpair->pb,collpair->vector); - - if (distance <= (epsilon + ALMOST_ZERO)) + // calc distance + normal +#ifdef WITH_BULLET + distance = plNearestPoints ( + verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa,collpair->pb,collpair->vector ); +#else + // just be sure that we don't add anything + distance = 2.0 * ( epsilon + epsilon2 + ALMOST_ZERO ); +#endif + if ( distance <= ( epsilon + epsilon2 + ALMOST_ZERO ) ) { // printf("dist: %f\n", (float)distance); - + // collpair->face1 = tree1->tri_index; // collpair->face2 = tree2->tri_index; - - VECCOPY(collpair->normal, collpair->vector); - Normalize(collpair->normal); - + + VECCOPY ( collpair->normal, collpair->vector ); + Normalize ( collpair->normal ); + collpair->distance = distance; - BLI_linklist_prepend(&clmd->coll_parms->collision_list, collpair); - + BLI_linklist_prepend ( &clmd->coll_parms->collision_list, collpair ); + } else { - MEM_freeN(collpair); + MEM_freeN ( collpair ); } } else { - MEM_freeN(collpair); + MEM_freeN ( collpair ); } } } -int cloth_are_edges_adjacent(ClothModifierData *clmd, ClothModifierData *coll_clmd, EdgeCollPair *edgecollpair) +int cloth_are_edges_adjacent ( ClothModifierData *clmd, ClothModifierData *coll_clmd, EdgeCollPair *edgecollpair ) { Cloth *cloth1 = NULL, *cloth2 = NULL; ClothVertex *verts1 = NULL, *verts2 = NULL; float temp[3]; - + cloth1 = clmd->clothObject; cloth2 = coll_clmd->clothObject; - + verts1 = cloth1->verts; verts2 = cloth2->verts; - - VECSUB(temp, verts1[edgecollpair->p11].xold, verts2[edgecollpair->p21].xold); - if(ABS(INPR(temp, temp)) < ALMOST_ZERO) + + VECSUB ( temp, verts1[edgecollpair->p11].xold, verts2[edgecollpair->p21].xold ); + if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; - - VECSUB(temp, verts1[edgecollpair->p11].xold, verts2[edgecollpair->p22].xold); - if(ABS(INPR(temp, temp)) < ALMOST_ZERO) + + VECSUB ( temp, verts1[edgecollpair->p11].xold, verts2[edgecollpair->p22].xold ); + if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; - - VECSUB(temp, verts1[edgecollpair->p12].xold, verts2[edgecollpair->p21].xold); - if(ABS(INPR(temp, temp)) < ALMOST_ZERO) + + VECSUB ( temp, verts1[edgecollpair->p12].xold, verts2[edgecollpair->p21].xold ); + if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; - - VECSUB(temp, verts1[edgecollpair->p12].xold, verts2[edgecollpair->p22].xold); - if(ABS(INPR(temp, temp)) < ALMOST_ZERO) + + VECSUB ( temp, verts1[edgecollpair->p12].xold, verts2[edgecollpair->p22].xold ); + if ( ABS ( INPR ( temp, temp ) ) < ALMOST_ZERO ) return 1; - + return 0; } -void cloth_collision_moving_edges(ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2) +void cloth_collision_moving_edges ( ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2 ) { EdgeCollPair edgecollpair; Cloth *cloth1=NULL, *cloth2=NULL; MFace *face1=NULL, *face2=NULL; ClothVertex *verts1=NULL, *verts2=NULL; - double distance = 0; - float epsilon = clmd->coll_parms->epsilon; unsigned int i = 0, j = 0, k = 0; int numsolutions = 0; float a[3], b[3], c[3], d[3], e[3], f[3], solution[3]; - + cloth1 = clmd->clothObject; cloth2 = coll_clmd->clothObject; - + verts1 = cloth1->verts; verts2 = cloth2->verts; - face1 = &(cloth1->mfaces[tree1->tri_index]); - face2 = &(cloth2->mfaces[tree2->tri_index]); - - for( i = 0; i < 5; i++) + face1 = & ( cloth1->mfaces[tree1->tri_index] ); + face2 = & ( cloth2->mfaces[tree2->tri_index] ); + + for ( i = 0; i < 5; i++ ) { - if(i == 0) + if ( i == 0 ) { edgecollpair.p11 = face1->v1; edgecollpair.p12 = face1->v2; } - else if(i == 1) + else if ( i == 1 ) { edgecollpair.p11 = face1->v2; edgecollpair.p12 = face1->v3; } - else if(i == 2) + else if ( i == 2 ) { - if(face1->v4) + if ( face1->v4 ) { edgecollpair.p11 = face1->v3; edgecollpair.p12 = face1->v4; } - else + else { edgecollpair.p11 = face1->v3; edgecollpair.p12 = face1->v1; i+=5; // get out of here after this edge pair is handled } } - else if(i == 3) + else if ( i == 3 ) { - if(face1->v4) + if ( face1->v4 ) { edgecollpair.p11 = face1->v4; edgecollpair.p12 = face1->v1; - } + } else continue; } @@ -803,35 +764,35 @@ void cloth_collision_moving_edges(ClothModifierData *clmd, ClothModifierData *co edgecollpair.p12 = face1->v1; } - - for( j = 0; j < 5; j++) + + for ( j = 0; j < 5; j++ ) { - if(j == 0) + if ( j == 0 ) { edgecollpair.p21 = face2->v1; edgecollpair.p22 = face2->v2; } - else if(j == 1) + else if ( j == 1 ) { edgecollpair.p21 = face2->v2; edgecollpair.p22 = face2->v3; } - else if(j == 2) + else if ( j == 2 ) { - if(face2->v4) + if ( face2->v4 ) { edgecollpair.p21 = face2->v3; edgecollpair.p22 = face2->v4; } - else + else { edgecollpair.p21 = face2->v3; edgecollpair.p22 = face2->v1; } } - else if(j == 3) + else if ( j == 3 ) { - if(face2->v4) + if ( face2->v4 ) { edgecollpair.p21 = face2->v4; edgecollpair.p22 = face2->v1; @@ -844,81 +805,79 @@ void cloth_collision_moving_edges(ClothModifierData *clmd, ClothModifierData *co edgecollpair.p21 = face2->v3; edgecollpair.p22 = face2->v1; } - - - if(!cloth_are_edges_adjacent(clmd, coll_clmd, &edgecollpair)) + + + if ( !cloth_are_edges_adjacent ( clmd, coll_clmd, &edgecollpair ) ) { - VECSUB(a, verts1[edgecollpair.p12].xold, verts1[edgecollpair.p11].xold); - VECSUB(b, verts1[edgecollpair.p12].v, verts1[edgecollpair.p11].v); - VECSUB(c, verts1[edgecollpair.p21].xold, verts1[edgecollpair.p11].xold); - VECSUB(d, verts1[edgecollpair.p21].v, verts1[edgecollpair.p11].v); - VECSUB(e, verts2[edgecollpair.p22].xold, verts1[edgecollpair.p11].xold); - VECSUB(f, verts2[edgecollpair.p22].v, verts1[edgecollpair.p11].v); - - numsolutions = cloth_get_collision_time(a, b, c, d, e, f, solution); - - for (k = 0; k < numsolutions; k++) - { - if ((solution[k] >= 0.0) && (solution[k] <= 1.0)) + VECSUB ( a, verts1[edgecollpair.p12].xold, verts1[edgecollpair.p11].xold ); + VECSUB ( b, verts1[edgecollpair.p12].v, verts1[edgecollpair.p11].v ); + VECSUB ( c, verts1[edgecollpair.p21].xold, verts1[edgecollpair.p11].xold ); + VECSUB ( d, verts1[edgecollpair.p21].v, verts1[edgecollpair.p11].v ); + VECSUB ( e, verts2[edgecollpair.p22].xold, verts1[edgecollpair.p11].xold ); + VECSUB ( f, verts2[edgecollpair.p22].v, verts1[edgecollpair.p11].v ); + + numsolutions = cloth_get_collision_time ( a, b, c, d, e, f, solution ); + + for ( k = 0; k < numsolutions; k++ ) + { + if ( ( solution[k] >= 0.0 ) && ( solution[k] <= 1.0 ) ) { - float out_collisionTime = solution[k]; - - // TODO: check for collisions - + //float out_collisionTime = solution[k]; + + // TODO: check for collisions + // TODO: put into (edge) collision list - + // printf("Moving edge found!\n"); } } } } - } + } } -void cloth_collision_moving_tris(ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2) +void cloth_collision_moving_tris ( ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2 ) { CollPair collpair; Cloth *cloth1=NULL, *cloth2=NULL; MFace *face1=NULL, *face2=NULL; ClothVertex *verts1=NULL, *verts2=NULL; - double distance = 0; - float epsilon = clmd->coll_parms->epsilon; unsigned int i = 0, j = 0, k = 0; int numsolutions = 0; float a[3], b[3], c[3], d[3], e[3], f[3], solution[3]; - for(i = 0; i < 2; i++) - { + for ( i = 0; i < 2; i++ ) + { cloth1 = clmd->clothObject; cloth2 = coll_clmd->clothObject; - + verts1 = cloth1->verts; verts2 = cloth2->verts; - - face1 = &(cloth1->mfaces[tree1->tri_index]); - face2 = &(cloth2->mfaces[tree2->tri_index]); - + + face1 = & ( cloth1->mfaces[tree1->tri_index] ); + face2 = & ( cloth2->mfaces[tree2->tri_index] ); + // check all possible pairs of triangles - if(i == 0) + if ( i == 0 ) { collpair.ap1 = face1->v1; collpair.ap2 = face1->v2; collpair.ap3 = face1->v3; - + collpair.pointsb[0] = face2->v1; collpair.pointsb[1] = face2->v2; collpair.pointsb[2] = face2->v3; collpair.pointsb[3] = face2->v4; } - - if(i == 1) + + if ( i == 1 ) { - if(face1->v4) + if ( face1->v4 ) { collpair.ap1 = face1->v3; collpair.ap2 = face1->v4; collpair.ap3 = face1->v1; - + collpair.pointsb[0] = face2->v1; collpair.pointsb[1] = face2->v2; collpair.pointsb[2] = face2->v3; @@ -927,335 +886,337 @@ void cloth_collision_moving_tris(ClothModifierData *clmd, ClothModifierData *col else i++; } - + // calc SIPcode (?) - - if(i < 2) + + if ( i < 2 ) { - VECSUB(a, verts1[collpair.ap2].xold, verts1[collpair.ap1].xold); - VECSUB(b, verts1[collpair.ap2].v, verts1[collpair.ap1].v); - VECSUB(c, verts1[collpair.ap3].xold, verts1[collpair.ap1].xold); - VECSUB(d, verts1[collpair.ap3].v, verts1[collpair.ap1].v); - - for(j = 0; j < 4; j++) - { - if((j==3) && !(face2->v4)) + VECSUB ( a, verts1[collpair.ap2].xold, verts1[collpair.ap1].xold ); + VECSUB ( b, verts1[collpair.ap2].v, verts1[collpair.ap1].v ); + VECSUB ( c, verts1[collpair.ap3].xold, verts1[collpair.ap1].xold ); + VECSUB ( d, verts1[collpair.ap3].v, verts1[collpair.ap1].v ); + + for ( j = 0; j < 4; j++ ) + { + if ( ( j==3 ) && ! ( face2->v4 ) ) break; - - VECSUB(e, verts2[collpair.pointsb[j]].xold, verts1[collpair.ap1].xold); - VECSUB(f, verts2[collpair.pointsb[j]].v, verts1[collpair.ap1].v); - - numsolutions = cloth_get_collision_time(a, b, c, d, e, f, solution); - - for (k = 0; k < numsolutions; k++) - { - if ((solution[k] >= 0.0) && (solution[k] <= 1.0)) + + VECSUB ( e, verts2[collpair.pointsb[j]].xold, verts1[collpair.ap1].xold ); + VECSUB ( f, verts2[collpair.pointsb[j]].v, verts1[collpair.ap1].v ); + + numsolutions = cloth_get_collision_time ( a, b, c, d, e, f, solution ); + + for ( k = 0; k < numsolutions; k++ ) + { + if ( ( solution[k] >= 0.0 ) && ( solution[k] <= 1.0 ) ) { - float out_collisionTime = solution[k]; - - // TODO: check for collisions - + //float out_collisionTime = solution[k]; + + // TODO: check for collisions + // TODO: put into (point-face) collision list - + // printf("Moving found!\n"); - + } } - + // TODO: check borders for collisions } - + } } } -void cloth_collision_moving(ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2) +void cloth_collision_moving ( ClothModifierData *clmd, ClothModifierData *coll_clmd, CollisionTree *tree1, CollisionTree *tree2 ) { // TODO: check for adjacent - cloth_collision_moving_edges(clmd, coll_clmd, tree1, tree2); - - cloth_collision_moving_tris(clmd, coll_clmd, tree1, tree2); - cloth_collision_moving_tris(coll_clmd, clmd, tree2, tree1); + cloth_collision_moving_edges ( clmd, coll_clmd, tree1, tree2 ); + + cloth_collision_moving_tris ( clmd, coll_clmd, tree1, tree2 ); + cloth_collision_moving_tris ( coll_clmd, clmd, tree2, tree1 ); +} + +void cloth_free_collision_list ( ClothModifierData *clmd ) +{ + // free collision list + if ( clmd->coll_parms->collision_list ) + { + LinkNode *search = clmd->coll_parms->collision_list; + while ( search ) + { + CollPair *coll_pair = search->link; + + MEM_freeN ( coll_pair ); + search = search->next; + } + BLI_linklist_free ( clmd->coll_parms->collision_list,NULL ); + + clmd->coll_parms->collision_list = NULL; + } +} + +int cloth_bvh_objcollisions_do ( ClothModifierData * clmd, CollisionModifierData *collmd, float step, float dt ) +{ + Cloth *cloth = clmd->clothObject; + BVH *cloth_bvh= ( BVH * ) cloth->tree; + long i=0, j = 0, numfaces = 0, numverts = 0; + ClothVertex *verts = NULL; + int ret = 0; + unsigned int result = 0; + float tnull[3] = {0,0,0}; + + numfaces = clmd->clothObject->numfaces; + numverts = clmd->clothObject->numverts; + + verts = cloth->verts; + + if ( collmd->bvh ) + { + /* get pointer to bounding volume hierarchy */ + BVH *coll_bvh = collmd->bvh; + + /* move object to position (step) in time */ + collision_move_object ( collmd, step + dt, step ); + + /* search for overlapping collision pairs */ + bvh_traverse ( ( ModifierData * ) clmd, ( ModifierData * ) collmd, cloth_bvh->root, coll_bvh->root, step, cloth_collision_static, 0 ); + } + else + { + if ( G.rt > 0 ) + printf ( "cloth_bvh_objcollision: found a collision object with clothObject or collData NULL.\n" ); + } + + // process all collisions (calculate impulses, TODO: also repulses if distance too short) + result = 1; + for ( j = 0; j < 5; j++ ) // 5 is just a value that ensures convergence + { + result = 0; + + if ( collmd->bvh ) + result += cloth_collision_response_static ( clmd, collmd ); + + // apply impulses in parallel + if ( result ) + for ( i = 0; i < numverts; i++ ) + { + // calculate "velocities" (just xnew = xold + v; no dt in v) + if ( verts[i].impulse_count ) + { + VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count ); + VECCOPY ( verts[i].impulse, tnull ); + verts[i].impulse_count = 0; + + ret++; + } + } + + if ( !result ) + break; + } + + cloth_free_collision_list ( clmd ); + + return ret; } // cloth - object collisions -int cloth_bvh_objcollision(ClothModifierData * clmd, float step, float dt) +int cloth_bvh_objcollision ( ClothModifierData * clmd, float step, float dt ) { Base *base=NULL; CollisionModifierData *collmd=NULL; Cloth *cloth=NULL; Object *coll_ob=NULL; BVH *cloth_bvh=NULL; - unsigned int i=0, j = 0, numfaces = 0, numverts = 0; - unsigned int result = 0, ic = 0, rounds = 0; // result counts applied collisions; ic is for debug output; + long i=0, j = 0, numfaces = 0, numverts = 0; + unsigned int result = 0, rounds = 0; // result counts applied collisions; ic is for debug output; ClothVertex *verts = NULL; - float tnull[3] = {0,0,0}; int ret = 0; ClothModifierData *tclmd; + int collisions = 0, count = 0; - if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || !(((Cloth *)clmd->clothObject)->tree)) + if ( ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ ) || ! ( ( ( Cloth * ) clmd->clothObject )->tree ) ) { return 0; } - + cloth = clmd->clothObject; verts = cloth->verts; - cloth_bvh = (BVH *) cloth->tree; + cloth_bvh = ( BVH * ) cloth->tree; numfaces = clmd->clothObject->numfaces; numverts = clmd->clothObject->numverts; - + //////////////////////////////////////////////////////////// // static collisions //////////////////////////////////////////////////////////// // update cloth bvh - bvh_update_from_cloth(clmd, 0); // 0 means STATIC, 1 means MOVING (see later in this function) - + bvh_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function) + do { result = 0; - ic = 0; - clmd->coll_parms->collision_list = NULL; - + clmd->coll_parms->collision_list = NULL; + // check all collision objects - for (base = G.scene->base.first; base; base = base->next) + for ( base = G.scene->base.first; base; base = base->next ) { coll_ob = base->object; - collmd = (CollisionModifierData *) modifiers_findByType (coll_ob, eModifierType_Collision); - - if (!collmd) - continue; - - tclmd = (ClothModifierData *) modifiers_findByType (coll_ob, eModifierType_Cloth); - if(tclmd == clmd) - continue; - - if (collmd->tree) - { - BVH *coll_bvh = collmd->tree; - - collision_move_object(collmd, step + dt, step); - - bvh_traverse(clmd, collmd, cloth_bvh->root, coll_bvh->root, step, cloth_collision_static); - } - else - printf ("cloth_bvh_objcollision: found a collision object with clothObject or collData NULL.\n"); - - - // process all collisions (calculate impulses, TODO: also repulses if distance too short) - result = 1; - for(j = 0; j < 10; j++) // 10 is just a value that ensures convergence + collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); + + if ( !collmd ) { - result = 0; - - if (collmd->tree) - result += cloth_collision_response_static(clmd, collmd); - - - // apply impulses in parallel - ic=0; - for(i = 0; i < numverts; i++) + if ( coll_ob->dup_group ) { - // calculate "velocities" (just xnew = xold + v; no dt in v) - if(verts[i].impulse_count) + GroupObject *go; + Group *group = coll_ob->dup_group; + + for ( go= group->gobject.first; go; go= go->next ) { - VECADDMUL(verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count); - VECCOPY(verts[i].impulse, tnull); - verts[i].impulse_count = 0; - - ic++; - ret++; + coll_ob = go->ob; + + collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision ); + + if ( !collmd ) + continue; + + tclmd = ( ClothModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Cloth ); + if ( tclmd == clmd ) + continue; + + ret += cloth_bvh_objcollisions_do ( clmd, collmd, step, dt ); } } } - - // free collision list - if(clmd->coll_parms->collision_list) + else { - LinkNode *search = clmd->coll_parms->collision_list; - while(search) - { - CollPair *coll_pair = search->link; - - MEM_freeN(coll_pair); - search = search->next; - } - BLI_linklist_free(clmd->coll_parms->collision_list,NULL); - - clmd->coll_parms->collision_list = NULL; + tclmd = ( ClothModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Cloth ); + if ( tclmd == clmd ) + continue; + + ret += cloth_bvh_objcollisions_do ( clmd, collmd, step, dt ); } } rounds++; - } - while(result && (clmd->coll_parms->loop_count>rounds)); - - //////////////////////////////////////////////////////////// - // update positions - // this is needed for bvh_calc_DOP_hull_moving() [kdop.c] - //////////////////////////////////////////////////////////// - - // verts come from clmd - for(i = 0; i < numverts; i++) - { - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) - { - if(verts [i].goal >= SOFTGOALSNAP) - { - continue; - } - } - - VECADD(verts[i].tx, verts[i].txold, verts[i].tv); - } - //////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////// - // moving collisions - // - // response code is just missing itm - //////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////// + // update positions + // this is needed for bvh_calc_DOP_hull_moving() [kdop.c] + //////////////////////////////////////////////////////////// - /* - // update cloth bvh - bvh_update_from_cloth(clmd, 1); // 0 means STATIC, 1 means MOVING - - // update moving bvh for collision object once - for (base = G.scene->base.first; base; base = base->next) - { - - coll_ob = base->object; - coll_clmd = (ClothModifierData *) modifiers_findByType (coll_ob, eModifierType_Cloth); - if (!coll_clmd) - continue; - - if(!coll_clmd->clothObject) - continue; - - // if collision object go on - if (coll_clmd->clothObject && coll_clmd->clothObject->tree) - { - BVH *coll_bvh = coll_clmd->clothObject->tree; - - bvh_update_from_cloth(coll_clmd, 1); // 0 means STATIC, 1 means MOVING - } - } - - - do - { - result = 0; - ic = 0; - clmd->coll_parms->collision_list = NULL; - - // check all collision objects - for (base = G.scene->base.first; base; base = base->next) + // verts come from clmd + for ( i = 0; i < numverts; i++ ) { - coll_ob = base->object; - coll_clmd = (ClothModifierData *) modifiers_findByType (coll_ob, eModifierType_Cloth); - - if (!coll_clmd) - continue; - - // if collision object go on - if (coll_clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) + if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) { - if (coll_clmd->clothObject && coll_clmd->clothObject->tree) + if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) { - BVH *coll_bvh = coll_clmd->clothObject->tree; - - bvh_traverse(clmd, coll_clmd, cloth_bvh->root, coll_bvh->root, step, cloth_collision_moving); + continue; } - else - printf ("cloth_bvh_objcollision: found a collision object with clothObject or collData NULL.\n"); } + + VECADD ( verts[i].tx, verts[i].txold, verts[i].tv ); } - - // process all collisions (calculate impulses, TODO: also repulses if distance too short) - result = 1; - for(j = 0; j < 10; j++) // 10 is just a value that ensures convergence + //////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////// + // Test on *simple* selfcollisions + //////////////////////////////////////////////////////////// + if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) { - result = 0; - - // handle all collision objects - for (base = G.scene->base.first; base; base = base->next) + collisions = 1; + verts = cloth->verts; // needed for openMP + + for ( count = 0; count < clmd->coll_parms->self_loop_count; count++ ) { - - coll_ob = base->object; - coll_clmd = (ClothModifierData *) modifiers_findByType (coll_ob, eModifierType_Cloth); - - if (!coll_clmd) - continue; - - // if collision object go on - if (coll_clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) + if ( collisions ) { - if (coll_clmd->clothObject) - result += cloth_collision_response_moving_tris(clmd, coll_clmd); - else - printf ("cloth_bvh_objcollision: found a collision object with clothObject or collData NULL.\n"); + collisions = 0; +#pragma omp parallel for private(i,j, collisions) shared(verts, ret) + for ( i = 0; i < cloth->numverts; i++ ) + { + for ( j = i + 1; j < cloth->numverts; j++ ) + { + float temp[3]; + float length = 0; + float mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len ); + + if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) + { + if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + && ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) ) + { + continue; + } + } + + VECSUB ( temp, verts[i].tx, verts[j].tx ); + + if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue; + + // check for adjacent points (i must be smaller j) + if ( BLI_edgehash_haskey ( cloth->edgehash, i, j ) ) + { + continue; + } + + length = Normalize ( temp ); + + if ( length < mindistance ) + { + float correction = mindistance - length; + + if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) + { + VecMulf ( temp, -correction ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + } + else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) + { + VecMulf ( temp, correction ); + VECADD ( verts[i].tx, verts[i].tx, temp ); + } + else + { + VecMulf ( temp, -correction*0.5 ); + VECADD ( verts[j].tx, verts[j].tx, temp ); + + VECSUB ( verts[i].tx, verts[i].tx, temp ); + } + + collisions = 1; + + if ( !ret ) + { +#pragma omp critical + { + ret = 1; + } + } + } + } + } } } - - // apply impulses in parallel - ic=0; - for(i = 0; i < numverts; i++) + //////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////// + // SELFCOLLISIONS: update velocities + //////////////////////////////////////////////////////////// + if ( ret ) { - // calculate "velocities" (just xnew = xold + v; no dt in v) - if(verts[i].impulse_count) + for ( i = 0; i < cloth->numverts; i++ ) { - VECADDMUL(verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count); - VECCOPY(verts[i].impulse, tnull); - verts[i].impulse_count = 0; - - ic++; - ret++; + if ( ! ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) + VECSUB ( verts[i].tv, verts[i].tx, verts[i].txold ); } } + //////////////////////////////////////////////////////////// } - - - // verts come from clmd - for(i = 0; i < numverts; i++) - { - VECADD(verts[i].tx, verts[i].txold, verts[i].tv); - } - - // update cloth bvh - bvh_update_from_cloth(clmd, 1); // 0 means STATIC, 1 means MOVING - - - // free collision list - if(clmd->coll_parms->collision_list) - { - LinkNode *search = clmd->coll_parms->collision_list; - while(search) - { - CollPair *coll_pair = search->link; - - MEM_freeN(coll_pair); - search = search->next; - } - BLI_linklist_free(clmd->coll_parms->collision_list,NULL); - - clmd->coll_parms->collision_list = NULL; - } - - // printf("ic: %d\n", ic); - rounds++; - } - while(result && (CLOTH_MAX_THRESHOLD>rounds)); - - //////////////////////////////////////////////////////////// - // update positions + velocities - //////////////////////////////////////////////////////////// - - // verts come from clmd - for(i = 0; i < numverts; i++) - { - VECADD(verts[i].tx, verts[i].txold, verts[i].tv); } - //////////////////////////////////////////////////////////// - */ - - return MIN2(ret, 1); + while ( result && ( clmd->coll_parms->loop_count>rounds ) ); + + return MIN2 ( ret, 1 ); } diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index e4336576e2a..295b8fe3552 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -592,7 +592,8 @@ float curvemap_evaluateF(CurveMap *cuma, float value) fi= (value-cuma->mintable)*cuma->range; i= (int)fi; - if(fi<0.0f || fi>cuma->range) + /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */ + if(fi<0.0f || fi>CM_TABLE) return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x); else { if(i<0) return cuma->table[0].y; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 38f25b54fd8..f60e39769a2 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ * * Contributor(s): 2007, Joshua Leung, major recode * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -84,10 +81,10 @@ /* ******************* Constraint Channels ********************** */ /* Constraint Channels exist in one of two places: * - Under Action Channels in an Action (act->chanbase->achan->constraintChannels) - * - Under Object without object-level action yet (ob->constraintChannels) + * - Under Object without Object-level Action yet (ob->constraintChannels) * - * The main purpose that constraint channels serve is to act as a link - * between an IPO-block which + * The main purpose that Constraint Channels serve is to act as a link + * between an IPO-block (which provides values to interpolate between for some settings) */ /* ------------ Data Management ----------- */ @@ -143,7 +140,7 @@ bConstraintChannel *get_constraint_channel (ListBase *list, const char name[]) { bConstraintChannel *chan; - if(list) { + if (list) { for (chan = list->first; chan; chan=chan->next) { if (!strcmp(name, chan->name)) { return chan; @@ -183,11 +180,11 @@ void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, for (con=conbase->first; con; con=con->next) { Ipo *ipo= NULL; - if(con->flag & CONSTRAINT_OWN_IPO) + if (con->flag & CONSTRAINT_OWN_IPO) ipo= con->ipo; else { bConstraintChannel *chan = get_constraint_channel(chanbase, con->name); - if(chan) ipo= chan->ipo; + if (chan) ipo= chan->ipo; } if (ipo) { @@ -206,7 +203,24 @@ void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, break; case CO_HEADTAIL: { - con->headtail = icu->curval; + /* we need to check types of constraints that can get this here, as user + * may have created an IPO-curve for this from IPO-editor but for a constraint + * that cannot support this + */ + switch (con->type) { + /* supported constraints go here... */ + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_MINMAX: + case CONSTRAINT_TYPE_STRETCHTO: + case CONSTRAINT_TYPE_DISTLIMIT: + con->headtail = icu->curval; + break; + + default: + /* not supported */ + break; + } } break; } @@ -438,7 +452,7 @@ void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4 /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */ if (pchan->parent) { float offs_bone[4][4]; - + /* construct offs_bone the same way it is done in armature.c */ Mat4CpyMat3(offs_bone, pchan->bone->bone_mat); VECCOPY(offs_bone[3], pchan->bone->head); @@ -878,7 +892,7 @@ static void childof_new_data (void *cdata) Mat4One(data->invmat); } -static void childof_get_tars (bConstraint *con, ListBase *list) +static int childof_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bChildOfConstraint *data= con->data; @@ -886,7 +900,11 @@ static void childof_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void childof_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -976,7 +994,7 @@ static void trackto_new_data (void *cdata) data->reserved2 = UP_Z; } -static void trackto_get_tars (bConstraint *con, ListBase *list) +static int trackto_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bTrackToConstraint *data= con->data; @@ -984,7 +1002,11 @@ static void trackto_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void trackto_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -1082,9 +1104,9 @@ static void vectomat (float *vec, float *target_up, short axis, short upflag, sh /* identity matrix - don't do anything if the two axes are the same */ else { m[0][0]= m[1][1]= m[2][2]= 1.0; - m[0][1]= m[0][2]= m[0][3]= 0.0; - m[1][0]= m[1][2]= m[1][3]= 0.0; - m[2][0]= m[2][1]= m[2][3]= 0.0; + m[0][1]= m[0][2]= 0.0; + m[1][0]= m[1][2]= 0.0; + m[2][0]= m[2][1]= 0.0; } } @@ -1153,16 +1175,20 @@ static void kinematic_new_data (void *cdata) data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_STRETCH|CONSTRAINT_IK_POS; } -static void kinematic_get_tars (bConstraint *con, ListBase *list) +static int kinematic_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bKinematicConstraint *data= con->data; bConstraintTarget *ct; - /* standard target-getting macro for single-target constraints */ + /* standard target-getting macro for single-target constraints is used twice here */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list) + + return 2; } + + return 0; } static void kinematic_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -1231,7 +1257,7 @@ static void followpath_new_data (void *cdata) data->followflag = 0; } -static void followpath_get_tars (bConstraint *con, ListBase *list) +static int followpath_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bFollowPathConstraint *data= con->data; @@ -1239,7 +1265,11 @@ static void followpath_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints without subtargets */ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list) + + return 1; } + + return 0; } static void followpath_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -1259,7 +1289,7 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr if (VALID_CONS_TARGET(ct)) { Curve *cu= ct->tar->data; - float q[4], vec[4], dir[3], *quat, x1; + float q[4], vec[4], dir[3], quat[4], x1; float totmat[4][4]; float curvetime; @@ -1284,7 +1314,7 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr if ( where_on_path(ct->tar, curvetime, vec, dir) ) { if (data->followflag) { - quat= vectoquat(dir, (short) data->trackflag, (short) data->upflag); + vectoquat(dir, (short) data->trackflag, (short) data->upflag, quat); Normalize(dir); q[0]= (float)cos(0.5*vec[3]); @@ -1532,7 +1562,7 @@ static void loclike_new_data (void *cdata) data->flag = LOCLIKE_X|LOCLIKE_Y|LOCLIKE_Z; } -static void loclike_get_tars (bConstraint *con, ListBase *list) +static int loclike_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bLocateLikeConstraint *data= con->data; @@ -1540,7 +1570,11 @@ static void loclike_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void loclike_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -1610,7 +1644,7 @@ static void rotlike_new_data (void *cdata) data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z; } -static void rotlike_get_tars (bConstraint *con, ListBase *list) +static int rotlike_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bRotateLikeConstraint *data= con->data; @@ -1618,7 +1652,11 @@ static void rotlike_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void rotlike_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -1707,7 +1745,7 @@ static void sizelike_new_data (void *cdata) data->flag = SIZELIKE_X|SIZELIKE_Y|SIZELIKE_Z; } -static void sizelike_get_tars (bConstraint *con, ListBase *list) +static int sizelike_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bSizeLikeConstraint *data= con->data; @@ -1715,7 +1753,11 @@ static void sizelike_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void sizelike_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -1821,14 +1863,18 @@ static void pycon_new_data (void *cdata) data->prop->type = IDP_GROUP; } -static void pycon_get_tars (bConstraint *con, ListBase *list) +static int pycon_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bPythonConstraint *data= con->data; list->first = data->targets.first; list->last = data->targets.last; + + return data->tarnum; } + + return 0; } /* Whether this approach is maintained remains to be seen (aligorith) */ @@ -1904,7 +1950,7 @@ static void actcon_new_data (void *cdata) data->type = 20; } -static void actcon_get_tars (bConstraint *con, ListBase *list) +static int actcon_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bActionConstraint *data= con->data; @@ -1912,7 +1958,11 @@ static void actcon_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void actcon_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -2043,7 +2093,7 @@ static void locktrack_new_data (void *cdata) data->lockflag = LOCK_Z; } -static void locktrack_get_tars (bConstraint *con, ListBase *list) +static int locktrack_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bLockTrackConstraint *data= con->data; @@ -2051,7 +2101,11 @@ static void locktrack_get_tars (bConstraint *con, ListBase *list) /* the following macro is used for all standard single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void locktrack_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -2391,7 +2445,7 @@ static void distlimit_new_data (void *cdata) data->dist= 0.0; } -static void distlimit_get_tars (bConstraint *con, ListBase *list) +static int distlimit_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bDistLimitConstraint *data= con->data; @@ -2399,7 +2453,11 @@ static void distlimit_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void distlimit_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -2506,7 +2564,7 @@ static void stretchto_new_data (void *cdata) data->bulge = 1.0; } -static void stretchto_get_tars (bConstraint *con, ListBase *list) +static int stretchto_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bStretchToConstraint *data= con->data; @@ -2514,7 +2572,11 @@ static void stretchto_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void stretchto_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -2682,7 +2744,7 @@ static void minmax_new_data (void *cdata) data->flag = 0; } -static void minmax_get_tars (bConstraint *con, ListBase *list) +static int minmax_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bMinMaxConstraint *data= con->data; @@ -2690,7 +2752,11 @@ static void minmax_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void minmax_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -2812,7 +2878,7 @@ static void rbj_new_data (void *cdata) data->type=1; } -static void rbj_get_tars (bConstraint *con, ListBase *list) +static int rbj_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bRigidBodyJointConstraint *data= con->data; @@ -2820,7 +2886,11 @@ static void rbj_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints without subtargets */ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list) + + return 1; } + + return 0; } static void rbj_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -2851,7 +2921,7 @@ static bConstraintTypeInfo CTI_RIGIDBODYJOINT = { /* -------- Clamp To ---------- */ -static void clampto_get_tars (bConstraint *con, ListBase *list) +static int clampto_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bClampToConstraint *data= con->data; @@ -2859,7 +2929,11 @@ static void clampto_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints without subtargets */ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list) + + return 1; } + + return 0; } static void clampto_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -3024,7 +3098,7 @@ static void transform_new_data (void *cdata) data->map[2]= 2; } -static void transform_get_tars (bConstraint *con, ListBase *list) +static int transform_get_tars (bConstraint *con, ListBase *list) { if (con && list) { bTransformConstraint *data= con->data; @@ -3032,7 +3106,11 @@ static void transform_get_tars (bConstraint *con, ListBase *list) /* standard target-getting macro for single-target constraints */ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list) + + return 1; } + + return 0; } static void transform_flush_tars (bConstraint *con, ListBase *list, short nocopy) @@ -3059,11 +3137,13 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* obtain target effect */ switch (data->from) { - case 2: /* scale */ + case 2: /* scale */ Mat4ToSize(ct->matrix, dvec); break; - case 1: /* rotation */ + case 1: /* rotation (convert to degrees first) */ Mat4ToEul(ct->matrix, dvec); + for (i=0; i<3; i++) + dvec[i] = dvec[i] / M_PI * 180; break; default: /* location */ VecCopyf(dvec, ct->matrix[3]); @@ -3073,7 +3153,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* extract components of owner's matrix */ VECCOPY(loc, cob->matrix[3]); Mat4ToEul(cob->matrix, eul); - Mat4ToSize(cob->matrix, size); + Mat4ToSize(cob->matrix, size); /* determine where in range current transforms lie */ if (data->expo) { @@ -3095,17 +3175,6 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * } } - /* convert radian<->degree */ - if (data->from==1 && data->to==0) { - /* from radians to degrees */ - for (i=0; i<3; i++) - sval[i] = sval[i] / M_PI * 180; - } - else if (data->from==0 && data->to==1) { - /* from degrees to radians */ - for (i=0; i<3; i++) - sval[i] = sval[i] / 180 * M_PI; - } /* apply transforms */ switch (data->to) { @@ -3117,11 +3186,14 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * for (i=0; i<3; i++) { float tmin, tmax; - /* convert destination min/max ranges from degrees to radians */ - tmin= data->to_min[i] / M_PI * 180; - tmax= data->to_max[i] / M_PI * 180; + tmin= data->to_min[i]; + tmax= data->to_max[i]; + /* all values here should be in degrees */ eul[i]= tmin + (sval[data->map[i]] * (tmax - tmin)); + + /* now convert final value back to radians */ + eul[i] = eul[i] / 180 * M_PI; } break; default: /* location */ diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index c23cc90aeb8..0db327f6efb 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -4,15 +4,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> // floor @@ -1788,13 +1785,13 @@ void makeBevelList(Object *ob) bevp2->cosa= bevp1->cosa; if(cu->flag & CU_3D) { /* 3D */ - float *quat, q[4]; + float quat[4], q[4]; vec[0]= bevp1->x - bevp2->x; vec[1]= bevp1->y - bevp2->y; vec[2]= bevp1->z - bevp2->z; - quat= vectoquat(vec, 5, 1); + vectoquat(vec, 5, 1, quat); Normalize(vec); q[0]= (float)cos(0.5*bevp1->alfa); @@ -1820,7 +1817,7 @@ void makeBevelList(Object *ob) while(nr--) { if(cu->flag & CU_3D) { /* 3D */ - float *quat, q[4]; + float quat[4], q[4]; vec[0]= bevp2->x - bevp0->x; vec[1]= bevp2->y - bevp0->y; @@ -1828,7 +1825,7 @@ void makeBevelList(Object *ob) Normalize(vec); - quat= vectoquat(vec, 5, 1); + vectoquat(vec, 5, 1, quat); q[0]= (float)cos(0.5*bevp1->alfa); x1= (float)sin(0.5*bevp1->alfa); @@ -1976,13 +1973,16 @@ float calc_curve_subdiv_radius(Curve *cu, Nurb *nu, int cursubdiv) if ( ((nu->type & 7)==CU_NURBS) && (nu->flagu & CU_CYCLIC)) { if (bp >= bplast) bp = bpfirst; else bp++; + } else if ( bp > bplast ) { + /* this can happen in rare cases, refer to bug [#8596] */ + bp = bplast; } rad = prevrad = bp->radius; if ((bp == bplast) && (nu->flagu & CU_CYCLIC)) { /* loop around */ bp= bpfirst; - } else if (bp != bplast) { + } else if (bp < bplast) { bp++; } nextrad = bp->radius; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index d8ce311b5ca..663c94e5155 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -97,11 +97,16 @@ static void layerCopy_mdeformvert(const void *source, void *dest, for(i = 0; i < count; ++i) { MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size); - MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw), - "layerCopy_mdeformvert dw"); - memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw)); - dvert->dw = dw; + if(dvert->totweight) { + MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw), + "layerCopy_mdeformvert dw"); + + memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw)); + dvert->dw = dw; + } + else + dvert->dw = NULL; } } diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 9356ba14071..ab53571b62d 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -6,15 +6,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -32,7 +29,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <string.h> diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index e1cecaa7a61..1331c9a7d12 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,7 +22,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -49,6 +46,7 @@ #include "DNA_effect_types.h" #include "DNA_group_types.h" #include "DNA_lattice_types.h" +#include "DNA_lamp_types.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" @@ -74,6 +72,7 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BKE_utildefines.h" #include "BKE_scene.h" @@ -326,9 +325,9 @@ static void dag_add_driver_relation(Ipo *ipo, DagForest *dag, DagNode *node, int ob = *oba; node1 = dag_get_node(dag, ob); if (ob->type == OB_ARMATURE) - dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB); + dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Python Ipo Driver"); else - dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB); + dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Python Ipo Driver"); oba++; } @@ -339,9 +338,9 @@ static void dag_add_driver_relation(Ipo *ipo, DagForest *dag, DagNode *node, int else if (icu->driver->ob) { node1 = dag_get_node(dag, icu->driver->ob); if(icu->driver->blocktype==ID_AR) - dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB); + dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Ipo Driver"); else - dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB); + dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Ipo Driver"); } } } @@ -362,7 +361,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int if ((ob->data) && (mask&DAG_RL_DATA)) { node2 = dag_get_node(dag,ob->data); - dag_add_relation(dag,node,node2,DAG_RL_DATA); + dag_add_relation(dag,node,node2,DAG_RL_DATA, "Object-Data Relation"); node2->first_ancestor = ob; node2->ancestor_count += 1; } @@ -387,11 +386,11 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int node3 = dag_get_node(dag, ct->tar); if (ct->subtarget[0]) - dag_add_relation(dag,node3,node, DAG_RL_OB_DATA|DAG_RL_DATA_DATA); + dag_add_relation(dag,node3,node, DAG_RL_OB_DATA|DAG_RL_DATA_DATA, cti->name); else if(ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) - dag_add_relation(dag,node3,node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag,node3,node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, cti->name); else - dag_add_relation(dag,node3,node, DAG_RL_OB_DATA); + dag_add_relation(dag,node3,node, DAG_RL_OB_DATA, cti->name); } } @@ -439,7 +438,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int for(amod= strip->modifiers.first; amod; amod= amod->next) { if(amod->ob) { node2 = dag_get_node(dag, amod->ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "NLA Strip Modifier"); } } } @@ -459,46 +458,55 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int switch(ob->partype) { case PARSKEL: - dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB, "Parent"); break; case PARVERT1: case PARVERT3: case PARBONE: - dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB, "Vertex Parent"); break; default: if(ob->parent->type==OB_LATTICE) - dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB, "Lattice Parent"); else if(ob->parent->type==OB_CURVE) { Curve *cu= ob->parent->data; if(cu->flag & CU_PATH) - dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB, "Curve Parent"); else - dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_OB_OB, "Curve Parent"); } else - dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_OB_OB, "Curve Parent"); } /* exception case: parent is duplivert */ if(ob->type==OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) { - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_OB); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_OB, "Duplivert"); } addtoroot = 0; } if (ob->track) { node2 = dag_get_node(dag,ob->track); - dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_OB_OB, "Track To"); addtoroot = 0; } if (ob->proxy) { node2 = dag_get_node(dag, ob->proxy); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA|DAG_RL_OB_OB); + dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA|DAG_RL_OB_OB, "Proxy"); /* inverted relation, so addtoroot shouldn't be set to zero */ } if (ob->type==OB_CAMERA) { Camera *cam = (Camera *)ob->data; + if (cam->ipo) { + dag_add_driver_relation(cam->ipo, dag, node, 1); + } if (cam->dof_ob) { node2 = dag_get_node(dag, cam->dof_ob); - dag_add_relation(dag,node2,node,DAG_RL_OB_OB); + dag_add_relation(dag,node2,node,DAG_RL_OB_OB, "Camera DoF"); + } + } + if (ob->type==OB_LAMP) { + Lamp *la = (Lamp *)ob->data; + if (la->ipo) { + dag_add_driver_relation(la->ipo, dag, node, 1); } } if (ob->transflag & OB_DUPLI) { @@ -508,7 +516,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int if(go->ob) { node2 = dag_get_node(dag, go->ob); /* node2 changes node1, this keeps animations updated in groups?? not logical? */ - dag_add_relation(dag, node2, node, DAG_RL_OB_OB); + dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Dupligroup"); } } } @@ -525,7 +533,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int Object *ob1= base->object; if((ob1->pd->deflect) && (ob1 != ob)) { node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Softbody Collision"); } } } @@ -536,18 +544,18 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int Object *mom= find_basis_mball(ob); if(mom!=ob) { node2 = dag_get_node(dag, mom); - dag_add_relation(dag,node,node2,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); // mom depends on children! + dag_add_relation(dag,node,node2,DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Metaball"); // mom depends on children! } } else if (ob->type==OB_CURVE) { Curve *cu= ob->data; if(cu->bevobj) { node2 = dag_get_node(dag, cu->bevobj); - dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Curve Bevel"); } if(cu->taperobj) { node2 = dag_get_node(dag, cu->taperobj); - dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Curve Taper"); } if(cu->ipo) dag_add_driver_relation(cu->ipo, dag, node, 1); @@ -557,52 +565,38 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int Curve *cu= ob->data; if(cu->textoncurve) { node2 = dag_get_node(dag, cu->textoncurve); - dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Texture On Curve"); } } - else if(ob->type==OB_MESH) { - PartEff *paf= give_parteff(ob); - if(paf) { - ListBase *listb; - pEffectorCache *ec; - - /* ob location depends on itself */ - if((paf->flag & PAF_STATIC)==0) - dag_add_relation(dag, node, node, DAG_RL_OB_DATA); - - listb= pdInitEffectors(ob, paf->group); /* note, makes copy... */ - if(listb) { - for(ec= listb->first; ec; ec= ec->next) { - Object *ob1= ec->ob; - PartDeflect *pd= ob1->pd; - - if(pd->forcefield) { - node2 = dag_get_node(dag, ob1); - if(pd->forcefield==PFIELD_GUIDE) - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); - else - dag_add_relation(dag, node2, node, DAG_RL_OB_DATA); - } - } - - pdEndEffectors(listb); /* restores copy... */ - } - } - } - + psys= ob->particlesystem.first; if(psys) { ParticleEffectorCache *nec; + GroupObject *go; for(; psys; psys=psys->next) { ParticleSettings *part= psys->part; - dag_add_relation(dag, node, node, DAG_RL_OB_DATA); + dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); if(part->phystype==PART_PHYS_KEYED && psys->keyed_ob && BLI_findlink(&psys->keyed_ob->particlesystem,psys->keyed_psys-1)) { node2 = dag_get_node(dag, psys->keyed_ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Keyed Physics"); + } + + if(part->draw_as == PART_DRAW_OB && part->dup_ob) { + node2 = dag_get_node(dag, part->dup_ob); + dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualisation"); + if(part->dup_ob->type == OB_MBALL) + dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualisation"); + } + + if(part->draw_as == PART_DRAW_GR && part->dup_group) { + for(go=part->dup_group->gobject.first; go; go=go->next) { + node2 = dag_get_node(dag, go->ob); + dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Group Visualisation"); + } } if(psys->effectors.first) @@ -616,22 +610,22 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int if(nec->type & PSYS_EC_EFFECTOR) { node2 = dag_get_node(dag, ob1); if(ob1->pd->forcefield==PFIELD_GUIDE) - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field"); else - dag_add_relation(dag, node2, node, DAG_RL_OB_DATA); + dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field"); } else if(nec->type & PSYS_EC_DEFLECT) { node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision"); } else if(nec->type & PSYS_EC_PARTICLE) { node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field"); } if(nec->type & PSYS_EC_REACTOR) { node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA); + dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor"); } } } @@ -656,12 +650,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int node2 = dag_get_node(dag, obt); if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB); + dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB, cti->name); else { if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) - dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB); + dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB, cti->name); else - dag_add_relation(dag, node2, node, DAG_RL_OB_OB); + dag_add_relation(dag, node2, node, DAG_RL_OB_OB, cti->name); } addtoroot = 0; } @@ -672,7 +666,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int } if (addtoroot == 1 ) - dag_add_relation(dag,scenenode,node,DAG_RL_SCENE); + dag_add_relation(dag,scenenode,node,DAG_RL_SCENE, "Scene Relation"); } struct DagForest *build_dag(struct Scene *sce, short mask) @@ -863,7 +857,7 @@ DagNode * dag_get_sub_node (DagForest *forest,void * fob) return node; } -void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel) +void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, char *name) { DagAdjList *itA = fob1->child; @@ -881,10 +875,11 @@ void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel itA->type = rel; itA->count = 1; itA->next = fob1->child; + itA->name = name; fob1->child = itA; } -static void dag_add_parent_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel) +static void dag_add_parent_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, char *name) { DagAdjList *itA = fob2->parent; @@ -902,9 +897,66 @@ static void dag_add_parent_relation(DagForest *forest, DagNode *fob1, DagNode *f itA->type = rel; itA->count = 1; itA->next = fob2->parent; + itA->name = name; fob2->parent = itA; } +static char *dag_node_name(DagNode *node) +{ + if(node->ob == NULL) + return "null"; + else if(ugly_hack_sorry) + return ((ID*)(node->ob))->name+2; + else + return ((bPoseChannel*)(node->ob))->name; +} + +#if 0 +static void dag_node_print_dependencies(DagNode *node) +{ + DagAdjList *itA; + + printf("%s depends on:\n", dag_node_name(node)); + + for(itA= node->parent; itA; itA= itA->next) + printf(" %s through %s\n", dag_node_name(itA->node), itA->name); + printf("\n"); +} +#endif + +static int dag_node_print_dependency_recurs(DagNode *node, DagNode *endnode) +{ + DagAdjList *itA; + + if(node->color == DAG_BLACK) + return 0; + + node->color= DAG_BLACK; + + if(node == endnode) + return 1; + + for(itA= node->parent; itA; itA= itA->next) { + if(dag_node_print_dependency_recurs(itA->node, endnode)) { + printf(" %s depends on %s through %s.\n", dag_node_name(node), dag_node_name(itA->node), itA->name); + return 1; + } + } + + return 0; +} + +static void dag_node_print_dependency_cycle(DagForest *dag, DagNode *startnode, DagNode *endnode, char *name) +{ + DagNode *node; + + for(node = dag->DagNode.first; node; node= node->next) + node->color= DAG_WHITE; + + printf(" %s depends on %s through %s.\n", dag_node_name(endnode), dag_node_name(startnode), name); + dag_node_print_dependency_recurs(startnode, endnode); + printf("\n"); +} /* * MainDAG is the DAG of all objects in current scene @@ -1634,6 +1686,7 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) ob= node->ob; if(ob && (ob->recalc & OB_RECALC)) { all_layer= ob->lay; + /* got an object node that changes, now check relations */ for(itA = node->child; itA; itA= itA->next) { all_layer |= itA->lay; @@ -1707,18 +1760,24 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) } /* node was checked to have lasttime != curtime , and is of type ID_OB */ -static unsigned int flush_layer_node(DagNode *node, int curtime) +static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) { + Base *base; DagAdjList *itA; node->lasttime= curtime; - node->lay= ((Object *)node->ob)->lay; + node->lay= 0; + for(base= sce->base.first; base; base= base->next) { + if(node->ob == base->object) { + node->lay= ((Object *)node->ob)->lay; + break; + } + } for(itA = node->child; itA; itA= itA->next) { if(itA->node->type==ID_OB) { if(itA->node->lasttime!=curtime) { - itA->lay= flush_layer_node(itA->node, curtime); // lay is only set once for each relation - //printf("layer %d for relation %s to %s\n", itA->lay, ((Object *)node->ob)->id.name, ((Object *)itA->node->ob)->id.name); + itA->lay= flush_layer_node(sce, itA->node, curtime); // lay is only set once for each relation } else itA->lay= itA->node->lay; @@ -1729,11 +1788,38 @@ static unsigned int flush_layer_node(DagNode *node, int curtime) return node->lay; } +/* node was checked to have lasttime != curtime , and is of type ID_OB */ +static void flush_pointcache_reset(DagNode *node, int curtime, int reset) +{ + DagAdjList *itA; + Object *ob; + + node->lasttime= curtime; + + for(itA = node->child; itA; itA= itA->next) { + if(itA->node->type==ID_OB) { + if(itA->node->lasttime!=curtime) { + ob= (Object*)(node->ob); + + if(reset || (ob->recalc & OB_RECALC)) { + if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH)) + ob->recalc |= OB_RECALC_DATA; + + flush_pointcache_reset(itA->node, curtime, 1); + } + else + flush_pointcache_reset(itA->node, curtime, 0); + } + } + } +} + /* flushes all recalc flags in objects down the dependency tree */ -void DAG_scene_flush_update(Scene *sce, unsigned int lay) +void DAG_scene_flush_update(Scene *sce, unsigned int lay, int time) { DagNode *firstnode; DagAdjList *itA; + Object *ob; int lasttime; if(sce->theDag==NULL) { @@ -1742,21 +1828,43 @@ void DAG_scene_flush_update(Scene *sce, unsigned int lay) } firstnode= sce->theDag->DagNode.first; // always scene node + + for(itA = firstnode->child; itA; itA= itA->next) + itA->lay= 0; /* first we flush the layer flags */ sce->theDag->time++; // so we know which nodes were accessed lasttime= sce->theDag->time; - for(itA = firstnode->child; itA; itA= itA->next) { + + for(itA = firstnode->child; itA; itA= itA->next) if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) - flush_layer_node(itA->node, lasttime); - } + flush_layer_node(sce, itA->node, lasttime); /* then we use the relationships + layer info to flush update events */ sce->theDag->time++; // so we know which nodes were accessed lasttime= sce->theDag->time; - for(itA = firstnode->child; itA; itA= itA->next) { - if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) + for(itA = firstnode->child; itA; itA= itA->next) + if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) flush_update_node(itA->node, lay, lasttime); + + /* if update is not due to time change, do pointcache clears */ + if(!time) { + sce->theDag->time++; // so we know which nodes were accessed + lasttime= sce->theDag->time; + for(itA = firstnode->child; itA; itA= itA->next) { + if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) { + ob= (Object*)(itA->node->ob); + + if(ob->recalc & OB_RECALC) { + if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH)) + ob->recalc |= OB_RECALC_DATA; + + flush_pointcache_reset(itA->node, lasttime, 1); + } + else + flush_pointcache_reset(itA->node, lasttime, 0); + } + } } } @@ -1835,6 +1943,7 @@ static void dag_object_time_update_flags(Object *ob) } else if(modifiers_isSoftbodyEnabled(ob)) ob->recalc |= OB_RECALC_DATA; else if(object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA; + else if((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA; else { Mesh *me; Curve *cu; @@ -1849,15 +1958,6 @@ static void dag_object_time_update_flags(Object *ob) ob->shapeflag &= ~OB_SHAPE_TEMPLOCK; } } - else if(ob->effect.first) { - Effect *eff= ob->effect.first; - PartEff *paf= give_parteff(ob); - - if(eff->type==EFF_WAVE) - ob->recalc |= OB_RECALC_DATA; - else if(paf && paf->keys==NULL) - ob->recalc |= OB_RECALC_DATA; - } if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (ob->fluidsimSettings)) { // fluidsimSettings might not be initialized during load... if(ob->fluidsimSettings->type & (OB_FLUIDSIM_DOMAIN|OB_FLUIDSIM_PARTICLE)) { @@ -1941,7 +2041,7 @@ void DAG_scene_update_flags(Scene *scene, unsigned int lay) } for(sce= scene; sce; sce= sce->set) - DAG_scene_flush_update(sce, lay); + DAG_scene_flush_update(sce, lay, 1); /* test: set time flag, to disable baked systems to update */ for(SETLOOPER(scene, base)) { @@ -1991,7 +2091,9 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) { if(ob==NULL || sce->theDag==NULL) return; + ob->recalc |= flag; + BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH); /* all users of this ob->data should be checked */ /* BUT! displists for curves are still only on cu */ @@ -2004,8 +2106,9 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) else { Object *obt; for (obt=G.main->object.first; obt; obt= obt->id.next) { - if (obt->data==ob->data) { + if (obt != ob && obt->data==ob->data) { obt->recalc |= OB_RECALC_DATA; + BKE_ptcache_object_reset(obt, PTCACHE_RESET_DEPSGRAPH); } } } @@ -2014,9 +2117,9 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) } if(G.curscreen) - DAG_scene_flush_update(sce, dag_screen_view3d_layers()); + DAG_scene_flush_update(sce, dag_screen_view3d_layers(), 0); else - DAG_scene_flush_update(sce, sce->lay); + DAG_scene_flush_update(sce, sce->lay, 0); } /* recursively descends tree, each node only checked once */ @@ -2101,16 +2204,21 @@ void DAG_object_update_flags(Scene *sce, Object *ob, unsigned int lay) static int node_recurs_level(DagNode *node, int level) { DagAdjList *itA; - + int newlevel; + node->color= DAG_BLACK; /* done */ - level++; + newlevel= ++level; for(itA= node->parent; itA; itA= itA->next) { - if(itA->node->color==DAG_WHITE) + if(itA->node->color==DAG_WHITE) { itA->node->ancestor_count= node_recurs_level(itA->node, level); + newlevel= MAX2(newlevel, level+itA->node->ancestor_count); + } + else + newlevel= MAX2(newlevel, level+itA->node->ancestor_count); } - return level; + return newlevel; } static void pose_check_cycle(DagForest *dag) @@ -2135,9 +2243,10 @@ static void pose_check_cycle(DagForest *dag) bPoseChannel *pchan= (bPoseChannel *)node->ob; bPoseChannel *parchan= (bPoseChannel *)itA->node->ob; - if(pchan && parchan) - if(pchan->parent!=parchan) - printf("Cycle in %s to %s\n", pchan->name, parchan->name); + if(pchan && parchan) { + printf("Cycle detected:\n"); + dag_node_print_dependency_cycle(dag, itA->node, node, itA->name); + } } } } @@ -2171,8 +2280,8 @@ void DAG_pose_sort(Object *ob) if(pchan->parent) { node2 = dag_get_node(dag, pchan->parent); - dag_add_relation(dag, node2, node, 0); - dag_add_parent_relation(dag, node2, node, 0); + dag_add_relation(dag, node2, node, 0, "Parent Relation"); + dag_add_parent_relation(dag, node2, node, 0, "Parent Relation"); addtoroot = 0; } for (con = pchan->constraints.first; con; con=con->next) { @@ -2183,12 +2292,15 @@ void DAG_pose_sort(Object *ob) if(con->ipo) { IpoCurve *icu; for(icu= con->ipo->curve.first; icu; icu= icu->next) { - if(icu->driver && icu->driver->ob==ob) { + /* icu->driver->ob should actually point to ob->proxy if it + * is a proxy, but since it wasn't set correct it older + * files comparing with ob->proxy makes it work for those */ + if(icu->driver && (icu->driver->ob==ob || icu->driver->ob==ob->proxy)) { bPoseChannel *target= get_pose_channel(ob->pose, icu->driver->name); if(target) { node2 = dag_get_node(dag, target); - dag_add_relation(dag, node2, node, 0); - dag_add_parent_relation(dag, node2, node, 0); + dag_add_relation(dag, node2, node, 0, "Ipo Driver"); + dag_add_parent_relation(dag, node2, node, 0, "Ipo Driver"); /* uncommented this line, results in dependencies * not being added properly for this constraint, @@ -2207,9 +2319,9 @@ void DAG_pose_sort(Object *ob) bPoseChannel *target= get_pose_channel(ob->pose, ct->subtarget); if (target) { node2= dag_get_node(dag, target); - dag_add_relation(dag, node2, node, 0); - dag_add_parent_relation(dag, node2, node, 0); - + dag_add_relation(dag, node2, node, 0, "IK Constraint"); + dag_add_parent_relation(dag, node2, node, 0, "IK Constraint"); + if (con->type==CONSTRAINT_TYPE_KINEMATIC) { bKinematicConstraint *data = (bKinematicConstraint *)con->data; bPoseChannel *parchan; @@ -2224,8 +2336,8 @@ void DAG_pose_sort(Object *ob) /* Walk to the chain's root */ while (parchan) { node3= dag_get_node(dag, parchan); - dag_add_relation(dag, node2, node3, 0); - dag_add_parent_relation(dag, node2, node3, 0); + dag_add_relation(dag, node2, node3, 0, "IK Constraint"); + dag_add_parent_relation(dag, node2, node3, 0, "IK Constraint"); segcount++; if (segcount==data->rootbone || segcount>255) break; // 255 is weak @@ -2241,8 +2353,8 @@ void DAG_pose_sort(Object *ob) } } if (addtoroot == 1 ) { - dag_add_relation(dag, rootnode, node, 0); - dag_add_parent_relation(dag, rootnode, node, 0); + dag_add_relation(dag, rootnode, node, 0, "Root Bone Relation"); + dag_add_parent_relation(dag, rootnode, node, 0, "Root Bone Relation"); } } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index a9f009cd876..6f5660b2a3f 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 6e33805fbeb..4588ef800e1 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> @@ -99,43 +96,19 @@ typedef struct VeNoCo { float co[3], no[3]; } VeNoCo; -Effect *add_effect(int type) +/* ***************** PARTICLES ***************** */ + +/* deprecated, only keep this for readfile.c */ +PartEff *give_parteff(Object *ob) { - Effect *eff=0; PartEff *paf; - int a; - switch(type) { - case EFF_PARTICLE: - paf= MEM_callocN(sizeof(PartEff), "neweff"); - eff= (Effect *)paf; - - paf->sta= 1.0; - paf->end= 100.0; - paf->lifetime= 50.0; - for(a=0; a<PAF_MAXMULT; a++) { - paf->life[a]= 50.0; - paf->child[a]= 4; - paf->mat[a]= 1; - } - - paf->totpart= 1000; - paf->totkey= 8; - paf->staticstep= 5; - paf->defvec[2]= 1.0f; - paf->nabla= 0.05f; - paf->disp = 100; - paf->speedtex = 8; - paf->omat = 1; - paf->flag= PAF_FACE; - - break; + paf= ob->effect.first; + while(paf) { + if(paf->type==EFF_PARTICLE) return paf; + paf= paf->next; } - - eff->type= eff->buttype= type; - eff->flag |= SELECT; - - return eff; + return 0; } void free_effect(Effect *eff) @@ -162,172 +135,6 @@ void free_effects(ListBase *lb) } } -Effect *copy_effect(Effect *eff) -{ - Effect *effn; - - effn= MEM_dupallocN(eff); - if(effn->type==EFF_PARTICLE) ((PartEff *)effn)->keys= 0; - - return effn; -} - -void copy_act_effect(Object *ob) -{ - /* return a copy of the active effect */ - Effect *effn, *eff; - - eff= ob->effect.first; - while(eff) { - if(eff->flag & SELECT) { - - effn= copy_effect(eff); - BLI_addtail(&ob->effect, effn); - - eff->flag &= ~SELECT; - return; - - } - eff= eff->next; - } - - /* when it comes here: add new effect */ - eff= add_effect(EFF_PARTICLE); - BLI_addtail(&ob->effect, eff); - -} - -void copy_effects(ListBase *lbn, ListBase *lb) -{ - Effect *eff, *effn; - - lbn->first= lbn->last= 0; - - eff= lb->first; - while(eff) { - effn= copy_effect(eff); - BLI_addtail(lbn, effn); - - eff= eff->next; - } - -} - -void deselectall_eff(Object *ob) -{ - Effect *eff= ob->effect.first; - - while(eff) { - eff->flag &= ~SELECT; - eff= eff->next; - } -} - -/* ***************** PARTICLES ***************** */ - -static Particle *new_particle(PartEff *paf) -{ - static Particle *pa; - static int cur; - - /* we agree: when paf->keys==0: alloc */ - if(paf->keys==NULL) { - pa= paf->keys= MEM_callocN( paf->totkey*paf->totpart*sizeof(Particle), "particlekeys" ); - cur= 0; - } - else { - if(cur && cur<paf->totpart) pa+=paf->totkey; - cur++; - } - return pa; -} - -PartEff *give_parteff(Object *ob) -{ - PartEff *paf; - - paf= ob->effect.first; - while(paf) { - if(paf->type==EFF_PARTICLE) return paf; - paf= paf->next; - } - return 0; -} - -void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec) -{ - Particle *p[4]; - float dt, t[4]; - int a; - - if(paf->totkey==1 || ctime < pa->time) { - VECCOPY(vec, pa->co); - return; - } - - /* first find the first particlekey */ - a= (int)((paf->totkey-1)*(ctime-pa->time)/pa->lifetime); - if(a>=paf->totkey) a= paf->totkey-1; - else if(a<0) a= 0; - - pa+= a; - - if(a>0) p[0]= pa-1; else p[0]= pa; - p[1]= pa; - - if(a+1<paf->totkey) p[2]= pa+1; else p[2]= pa; - if(a+2<paf->totkey) p[3]= pa+2; else p[3]= p[2]; - - if(p[1]==p[2] || p[2]->time == p[1]->time) dt= 0.0; - else dt= (ctime-p[1]->time)/(p[2]->time - p[1]->time); - - if(paf->flag & PAF_BSPLINE) set_four_ipo(dt, t, KEY_BSPLINE); - else set_four_ipo(dt, t, KEY_CARDINAL); - - vec[0]= t[0]*p[0]->co[0] + t[1]*p[1]->co[0] + t[2]*p[2]->co[0] + t[3]*p[3]->co[0]; - vec[1]= t[0]*p[0]->co[1] + t[1]*p[1]->co[1] + t[2]*p[2]->co[1] + t[3]*p[3]->co[1]; - vec[2]= t[0]*p[0]->co[2] + t[1]*p[1]->co[2] + t[2]*p[2]->co[2] + t[3]*p[3]->co[2]; - -} - -static void particle_tex(MTex *mtex, PartEff *paf, float *co, float *no) -{ - float tin, tr, tg, tb, ta; - float old; - - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - - if(paf->texmap==PAF_TEXINT) { - tin*= paf->texfac; - no[0]+= tin*paf->defvec[0]; - no[1]+= tin*paf->defvec[1]; - no[2]+= tin*paf->defvec[2]; - } - else if(paf->texmap==PAF_TEXRGB) { - no[0]+= (tr-0.5f)*paf->texfac; - no[1]+= (tg-0.5f)*paf->texfac; - no[2]+= (tb-0.5f)*paf->texfac; - } - else { /* PAF_TEXGRAD */ - - old= tin; - co[0]+= paf->nabla; - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - no[0]+= (old-tin)*paf->texfac; - - co[0]-= paf->nabla; - co[1]+= paf->nabla; - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - no[1]+= (old-tin)*paf->texfac; - - co[1]-= paf->nabla; - co[2]+= paf->nabla; - externtex(mtex, co, &tin, &tr, &tg, &tb, &ta); - no[2]+= (old-tin)*paf->texfac; - - } -} - /* -------------------------- Effectors ------------------ */ static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) @@ -404,49 +211,6 @@ void pdEndEffectors(ListBase *lb) } } -/* local for this c file, only for guides now */ -static void precalc_effectors(Object *ob, PartEff *paf, Particle *pa, ListBase *lb) -{ - pEffectorCache *ec; - - for(ec= lb->first; ec; ec= ec->next) { - PartDeflect *pd= ec->ob->pd; - - ec->oldspeed[0]= ec->oldspeed[1]= ec->oldspeed[2]= 0.0f; - - if(pd->forcefield==PFIELD_GUIDE && ec->ob->type==OB_CURVE) { - float vec[4], dir[3]; - - if(!(paf->flag & PAF_STATIC)) - where_is_object_time(ec->ob, pa->time); - - /* scale corrects speed vector to curve size */ - if(paf->totkey>1) ec->scale= (paf->totkey-1)/pa->lifetime; - else ec->scale= 1.0f; - - /* time_scale is for random life */ - if(pa->lifetime>paf->lifetime) - ec->time_scale= paf->lifetime/pa->lifetime; - else - ec->time_scale= pa->lifetime/paf->lifetime; - - /* distance of first path point to particle origin */ - where_on_path(ec->ob, 0.0f, vec, dir); - VECCOPY(ec->oldloc, vec); /* store local coord for differences */ - Mat4MulVecfl(ec->ob->obmat, vec); - - /* for static we need to move to global space */ - if(paf->flag & PAF_STATIC) { - VECCOPY(dir, pa->co); - Mat4MulVecfl(ob->obmat, dir); - ec->guide_dist= VecLenf(vec, dir); - } - else - ec->guide_dist= VecLenf(vec, pa->co); - } - } -} - /* -------- pdDoEffectors() -------- generic force/speed system, now used for particles and softbodies @@ -522,6 +286,8 @@ void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist && pd->forcefield != PFIELD_GUIDE) ; /* don't do anything */ + else if((pd->flag & PFIELD_USEMIN) && distance<pd->mindist && pd->forcefield != PFIELD_GUIDE) + ; /* don't do anything */ else if(pd->forcefield == PFIELD_WIND) { VECCOPY(force_vec, ob->obmat[2]); @@ -659,879 +425,6 @@ void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float } } -static void cache_object_vertices(Object *ob) -{ - Mesh *me; - MVert *mvert; - float *fp; - int a; - - me= ob->data; - if(me->totvert==0) return; - - fp= ob->sumohandle= MEM_mallocN(3*sizeof(float)*me->totvert, "cache particles"); - mvert= me->mvert; - a= me->totvert; - while(a--) { - VECCOPY(fp, mvert->co); - Mat4MulVecfl(ob->obmat, fp); - mvert++; - fp+= 3; - } -} - -static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3], - float npno[3], float life, float force[3], int def_depth, - float cur_time, unsigned int par_layer, int *last_object, - int *last_face, int *same_face) -{ - /* Particle deflection code */ - /* The code is in two sections: the first part checks whether a particle has */ - /* intersected a face of a deflector mesh, given its old and new co-ords, opco and npco */ - /* and which face it hit first */ - /* The second part calculates the new co-ordinates given that collision and updates */ - /* the new co-ordinates accordingly */ - Base *base; - Object *ob, *deflection_object = NULL; - Mesh *def_mesh; - MFace *mface, *deflection_face = NULL; - float *v1, *v2, *v3, *v4, *vcache=NULL; - float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3]; - float dv1[3] = {0}, dv2[3] = {0}, dv3[3] = {0}; - float vect_to_int[3], refl_vel[3]; - float d_intersect_co[3], d_intersect_vect[3], d_nvect[3], d_i_co_above[3]; - float forcec[3]; - float k_point3, dist_to_plane; - float first_dist, ref_plane_mag; - float dk_plane=0, dk_point1=0; - float icalctop, icalcbot, n_mag; - float mag_iv, x_m,y_m,z_m; - float damping, perm_thresh; - float perm_val, rdamp_val; - int a, deflected=0, deflected_now=0; - float t,t2, min_t; - float mat[3][3], obloc[3] = {0}; - int cur_frame; - float time_before, time_after; - float force_mag_norm; - int d_object=0, d_face=0, ds_object=0, ds_face=0; - - first_dist = 200000; - min_t = 200000; - - /* The first part of the code, finding the first intersected face*/ - base= G.scene->base.first; - while (base) { - /*Only proceed for mesh object in same layer */ - if(base->object->type==OB_MESH && (base->lay & par_layer)) { - ob= base->object; - /* only with deflecting set */ - if(ob->pd && ob->pd->deflect) { - def_mesh= ob->data; - - d_object = d_object + 1; - - d_face = d_face + 1; - mface= def_mesh->mface; - a = def_mesh->totface; - - - if(ob->parent==NULL && ob->ipo==NULL) { // static - if(ob->sumohandle==NULL) cache_object_vertices(ob); - vcache= ob->sumohandle; - } - else { - /*Find out where the object is at this time*/ - cur_frame = G.scene->r.cfra; - G.scene->r.cfra = (int)cur_time; - where_is_object_time(ob, cur_time); - G.scene->r.cfra = cur_frame; - - /*Pass the values from ob->obmat to mat*/ - /*and the location values to obloc */ - Mat3CpyMat4(mat,ob->obmat); - obloc[0] = ob->obmat[3][0]; - obloc[1] = ob->obmat[3][1]; - obloc[2] = ob->obmat[3][2]; - vcache= NULL; - - } - - while (a--) { - - if(vcache) { - v1= vcache+ 3*(mface->v1); - VECCOPY(nv1, v1); - v1= vcache+ 3*(mface->v2); - VECCOPY(nv2, v1); - v1= vcache+ 3*(mface->v3); - VECCOPY(nv3, v1); - v1= vcache+ 3*(mface->v4); - VECCOPY(nv4, v1); - } - else { - /* Calculate the global co-ordinates of the vertices*/ - v1= (def_mesh->mvert+(mface->v1))->co; - v2= (def_mesh->mvert+(mface->v2))->co; - v3= (def_mesh->mvert+(mface->v3))->co; - v4= (def_mesh->mvert+(mface->v4))->co; - - VECCOPY(nv1, v1); - VECCOPY(nv2, v2); - VECCOPY(nv3, v3); - VECCOPY(nv4, v4); - - /*Apply the objects deformation matrix*/ - Mat3MulVecfl(mat, nv1); - Mat3MulVecfl(mat, nv2); - Mat3MulVecfl(mat, nv3); - Mat3MulVecfl(mat, nv4); - - VECADD(nv1, nv1, obloc); - VECADD(nv2, nv2, obloc); - VECADD(nv3, nv3, obloc); - VECADD(nv4, nv4, obloc); - } - - deflected_now = 0; - - - -// t= 0.5; // this is labda of line, can use it optimize quad intersection -// sorry but no .. see below (BM) - if( LineIntersectsTriangle(opco, npco, nv1, nv2, nv3, &t, NULL) ) { - if (t < min_t) { - deflected = 1; - deflected_now = 1; - } - } -// else if (mface->v4 && (t>=0.0 && t<=1.0)) { -// no, you can't skip testing the other triangle -// it might give a smaller t on (close to) the edge .. this is numerics not esoteric maths :) -// note: the 2 triangles don't need to share a plane ! (BM) - if (mface->v4) { - if( LineIntersectsTriangle(opco, npco, nv1, nv3, nv4, &t2, NULL) ) { - if (t2 < min_t) { - deflected = 1; - deflected_now = 2; - } - } - } - - if ((deflected_now > 0) && ((t < min_t) ||(t2 < min_t))) { - min_t = t; - ds_object = d_object; - ds_face = d_face; - deflection_object = ob; - deflection_face = mface; - if (deflected_now==1) { - min_t = t; - VECCOPY(dv1, nv1); - VECCOPY(dv2, nv2); - VECCOPY(dv3, nv3); - } - else { - min_t = t2; - VECCOPY(dv1, nv1); - VECCOPY(dv2, nv3); - VECCOPY(dv3, nv4); - } - } - mface++; - } - } - } - base = base->next; - } - - - /* Here's the point to do the permeability calculation */ - /* Set deflected to 0 if a random number is below the value */ - /* Get the permeability IPO here*/ - if (deflected) { - - if (has_ipo_code(deflection_object->ipo, OB_PD_PERM)) - perm_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_PERM, cur_time); - else - perm_val = deflection_object->pd->pdef_perm; - - perm_thresh = rng_getFloat(rng) - perm_val; - if (perm_thresh < 0 ) { - deflected = 0; - } - } - - /* Now for the second part of the deflection code - work out the new speed */ - /* and position of the particle if a collision occurred */ - if (deflected) { - VECSUB(edge1, dv1, dv2); - VECSUB(edge2, dv3, dv2); - Crossf(d_nvect, edge2, edge1); - n_mag = Normalize(d_nvect); - dk_plane = INPR(d_nvect, nv1); - dk_point1 = INPR(d_nvect,opco); - - VECSUB(d_intersect_vect, npco, opco); - - d_intersect_co[0] = opco[0] + (min_t * (npco[0] - opco[0])); - d_intersect_co[1] = opco[1] + (min_t * (npco[1] - opco[1])); - d_intersect_co[2] = opco[2] + (min_t * (npco[2] - opco[2])); - - d_i_co_above[0] = (d_intersect_co[0] + (0.001f * d_nvect[0])); - d_i_co_above[1] = (d_intersect_co[1] + (0.001f * d_nvect[1])); - d_i_co_above[2] = (d_intersect_co[2] + (0.001f * d_nvect[2])); - mag_iv = Normalize(d_intersect_vect); - VECCOPY(npco, d_intersect_co); - - VECSUB(vect_to_int, opco, d_intersect_co); - first_dist = Normalize(vect_to_int); - - /* Work out the lengths of time before and after collision*/ - time_before = (life*(first_dist / (mag_iv))); - time_after = (life*((mag_iv - first_dist) / (mag_iv))); - - /* We have to recalculate what the speed would have been at the */ - /* point of collision, not the key frame time */ - npno[0]= opno[0] + time_before*force[0]; - npno[1]= opno[1] + time_before*force[1]; - npno[2]= opno[2] + time_before*force[2]; - - - /* Reflect the speed vector in the face */ - x_m = (2 * npno[0] * d_nvect[0]); - y_m = (2 * npno[1] * d_nvect[1]); - z_m = (2 * npno[2] * d_nvect[2]); - refl_vel[0] = npno[0] - (d_nvect[0] * (x_m + y_m + z_m)); - refl_vel[1] = npno[1] - (d_nvect[1] * (x_m + y_m + z_m)); - refl_vel[2] = npno[2] - (d_nvect[2] * (x_m + y_m + z_m)); - - /*A random variation in the damping factor........ */ - /*Get the IPO values for damping here*/ - - if (has_ipo_code(deflection_object->ipo, OB_PD_SDAMP)) - damping = IPO_GetFloatValue(deflection_object->ipo, OB_PD_SDAMP, cur_time); - else - damping = deflection_object->pd->pdef_damp; - - if (has_ipo_code(deflection_object->ipo, OB_PD_RDAMP)) - rdamp_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_RDAMP, cur_time); - else - rdamp_val = deflection_object->pd->pdef_rdamp; - - damping = damping + ((1.0f - damping) * rng_getFloat(rng) *rdamp_val); - damping = damping * damping; - ref_plane_mag = INPR(refl_vel,d_nvect); - - if (damping > 0.999) damping = 0.999f; - - /* Now add in the damping force - only damp in the direction of */ - /* the faces normal vector */ - npno[0] = (refl_vel[0] - (d_nvect[0] * ref_plane_mag * damping)); - npno[1] = (refl_vel[1] - (d_nvect[1] * ref_plane_mag * damping)); - npno[2] = (refl_vel[2] - (d_nvect[2] * ref_plane_mag * damping)); - - /* Now reset opno */ - VECCOPY(opno,npno); - VECCOPY(forcec, force); - - /* If the particle has bounced more than four times on the same */ - /* face within this cycle (depth > 4, same face > 4 ) */ - /* Then set the force to be only that component of the force */ - /* in the same direction as the face normal */ - /* i.e. subtract the component of the force in the direction */ - /* of the face normal from the actual force */ - if ((ds_object == *last_object) && (ds_face == *last_face)) { - /* Increment same_face */ - *same_face = *same_face + 1; - if ((*same_face > 3) && (def_depth > 3)) { - force_mag_norm = INPR(forcec, d_nvect); - forcec[0] = forcec[0] - (d_nvect[0] * force_mag_norm); - forcec[1] = forcec[1] - (d_nvect[1] * force_mag_norm); - forcec[2] = forcec[2] - (d_nvect[2] * force_mag_norm); - } - } - else *same_face = 1; - - *last_object = ds_object; - *last_face = ds_face; - - /* We have the particles speed at the point of collision */ - /* Now we want the particles speed at the current key frame */ - - npno[0]= npno[0] + time_after*forcec[0]; - npno[1]= npno[1] + time_after*forcec[1]; - npno[2]= npno[2] + time_after*forcec[2]; - - /* Now we have to recalculate pa->co for the remainder*/ - /* of the time since the intersect*/ - npco[0]= npco[0] + time_after*npno[0]; - npco[1]= npco[1] + time_after*npno[1]; - npco[2]= npco[2] + time_after*npno[2]; - - /* And set the old co-ordinates back to the point just above the intersection */ - VECCOPY(opco, d_i_co_above); - - /* Finally update the time */ - life = time_after; - cur_time += time_before; - - /* The particle may have fallen through the face again by now!!*/ - /* So check if the particle has changed sides of the plane compared*/ - /* the co-ordinates at the last keyframe*/ - /* But only do this as a last resort, if we've got to the end of the */ - /* number of collisions allowed */ - if (def_depth==9) { - k_point3 = INPR(d_nvect,npco); - if (((dk_plane > k_point3) && (dk_plane < dk_point1))||((dk_plane < k_point3) && (dk_plane > dk_point1))) { - - /* Yup, the pesky particle may have fallen through a hole!!! */ - /* So we'll cheat a bit and move the particle along the normal vector */ - /* until it's just the other side of the plane */ - icalctop = (dk_plane - d_nvect[0]*npco[0] - d_nvect[1]*npco[1] - d_nvect[2]*npco[2]); - icalcbot = (d_nvect[0]*d_nvect[0] + d_nvect[1]*d_nvect[1] + d_nvect[2]*d_nvect[2]); - dist_to_plane = icalctop / icalcbot; - - /* Now just increase the distance a little to place */ - /* the point the other side of the plane */ - dist_to_plane *= 1.1f; - npco[0]= npco[0] + (dist_to_plane * d_nvect[0]); - npco[1]= npco[1] + (dist_to_plane * d_nvect[1]); - npco[2]= npco[2] + (dist_to_plane * d_nvect[2]); - - } - } - } - return deflected; -} - -/* - rng= random number generator - ob = object that spawns the particles - depth = for fireworks - nr = index nr of current particle - paf = the particle system - part = current particle - force = force vector - deform = flag to indicate lattice deform - */ -static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, ListBase *effectorbase) -{ - Particle *pa, *opa = NULL; - float damp, deltalife, life; - float cur_time, maxspeed= paf->maxlen/(float)paf->totkey; - float opco[3], opno[3], npco[3], npno[3], new_force[3], new_speed[3]; - int b, rt1, rt2, deflected, deflection, finish_defs, def_count; - int last_ob, last_fc, same_fc; - - damp= 1.0f-paf->damp; - pa= part; - - /* start speed: random */ - if(paf->randfac!=0.0) { - pa->no[0]+= paf->randfac*(rng_getFloat(rng) - 0.5f); - pa->no[1]+= paf->randfac*(rng_getFloat(rng) - 0.5f); - pa->no[2]+= paf->randfac*(rng_getFloat(rng) - 0.5f); - } - - /* start speed: texture */ - if(mtex && paf->texfac!=0.0) { - particle_tex(mtex, paf, pa->co, pa->no); - } - - /* effectors here? */ - if(effectorbase) - precalc_effectors(ob, paf, pa, effectorbase); - - if(paf->totkey>1) deltalife= pa->lifetime/(paf->totkey-1); - else deltalife= pa->lifetime; - - /* longer lifetime results in longer distance covered */ - VecMulf(pa->no, deltalife); - - opa= pa; - pa++; - - for(b=1; b<paf->totkey; b++) { - - /* new time */ - pa->time= opa->time+deltalife; - cur_time = pa->time; - - /* set initial variables */ - VECCOPY(opco, opa->co); - VECCOPY(new_force, force); - VECCOPY(new_speed, opa->no); - VecMulf(new_speed, 1.0f/deltalife); - //new_speed[0] = new_speed[1] = new_speed[2] = 0.0f; - - /* handle differences between static (local coords, fixed frame) and dynamic */ - if(effectorbase) { - float loc_time= ((float)b)/(float)(paf->totkey-1); - - if(paf->flag & PAF_STATIC) { - float opco1[3], new_force1[3]; - - /* move co and force to global coords */ - VECCOPY(opco1, opco); - Mat4MulVecfl(ob->obmat, opco1); - VECCOPY(new_force1, new_force); - Mat4Mul3Vecfl(ob->obmat, new_force1); - Mat4Mul3Vecfl(ob->obmat, new_speed); - - cur_time = G.scene->r.cfra; - - /* force fields */ - pdDoEffectors(effectorbase, opco1, new_force1, new_speed, cur_time, loc_time, 0); - - /* move co, force and newspeed back to local */ - VECCOPY(opco, opco1); - Mat4MulVecfl(ob->imat, opco); - VECCOPY(new_force, new_force1); - Mat4Mul3Vecfl(ob->imat, new_force); - Mat4Mul3Vecfl(ob->imat, new_speed); - } - else { - /* force fields */ - pdDoEffectors(effectorbase, opco, new_force, new_speed, cur_time, loc_time, 0); - } - } - - /* new speed */ - pa->no[0]= deltalife * (new_speed[0] + new_force[0]); - pa->no[1]= deltalife * (new_speed[1] + new_force[1]); - pa->no[2]= deltalife * (new_speed[2] + new_force[2]); - - /* speed limitor */ - if((paf->flag & PAF_STATIC) && maxspeed!=0.0f) { - float len= VecLength(pa->no); - if(len > maxspeed) - VecMulf(pa->no, maxspeed/len); - } - - /* new location */ - pa->co[0]= opa->co[0] + pa->no[0]; - pa->co[1]= opa->co[1] + pa->no[1]; - pa->co[2]= opa->co[2] + pa->no[2]; - - /* Particle deflection code */ - if((paf->flag & PAF_STATIC)==0) { - deflection = 0; - finish_defs = 1; - def_count = 0; - - VECCOPY(opno, opa->no); - VECCOPY(npco, pa->co); - VECCOPY(npno, pa->no); - - life = deltalife; - cur_time -= deltalife; - - last_ob = -1; - last_fc = -1; - same_fc = 0; - - /* First call the particle deflection check for the particle moving */ - /* between the old co-ordinates and the new co-ordinates */ - /* If a deflection occurs, call the code again, this time between the */ - /* intersection point and the updated new co-ordinates */ - /* Bail out if we've done the calculation 10 times - this seems ok */ - /* for most scenes I've tested */ - while (finish_defs) { - deflected = pdDoDeflection(rng, opco, npco, opno, npno, life, new_force, - def_count, cur_time, ob->lay, - &last_ob, &last_fc, &same_fc); - if (deflected) { - def_count = def_count + 1; - deflection = 1; - if (def_count==10) finish_defs = 0; - } - else { - finish_defs = 0; - } - } - - /* Only update the particle positions and speed if we had a deflection */ - if (deflection) { - pa->co[0] = npco[0]; - pa->co[1] = npco[1]; - pa->co[2] = npco[2]; - pa->no[0] = npno[0]; - pa->no[1] = npno[1]; - pa->no[2] = npno[2]; - } - } - - /* speed: texture */ - if(mtex && paf->texfac!=0.0) { - particle_tex(mtex, paf, pa->co, pa->no); - } - if(damp!=1.0) { - pa->no[0]*= damp; - pa->no[1]*= damp; - pa->no[2]*= damp; - } - - opa= pa; - pa++; - /* opa is used later on too! */ - } - - if(deform) { - /* deform all keys */ - pa= part; - b= paf->totkey; - while(b--) { - calc_latt_deform(pa->co, 1.0f); - pa++; - } - } - - /* the big multiplication */ - if(depth<PAF_MAXMULT && paf->mult[depth]!=0.0) { - - /* new 'child' emerges from an average 'mult' part from - the particles */ - damp = (float)nr; - rt1= (int)(damp*paf->mult[depth]); - rt2= (int)((damp+1.0)*paf->mult[depth]); - if(rt1!=rt2) { - - for(b=0; b<paf->child[depth]; b++) { - pa= new_particle(paf); - *pa= *opa; - pa->lifetime= paf->life[depth]; - if(paf->randlife!=0.0) { - pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f); - } - pa->mat_nr= paf->mat[depth]; - - make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, effectorbase); - } - } - } -} - -static void init_mv_jit(float *jit, int num, int seed2) -{ - RNG *rng; - float *jit2, x, rad1, rad2, rad3; - int i, num2; - - if(num==0) return; - - rad1= (float)(1.0/sqrt((float)num)); - rad2= (float)(1.0/((float)num)); - rad3= (float)sqrt((float)num)/((float)num); - - rng = rng_new(31415926 + num + seed2); - x= 0; - num2 = 2 * num; - for(i=0; i<num2; i+=2) { - - jit[i]= x + rad1*(0.5f - rng_getFloat(rng)); - jit[i+1]= i/(2.0f*num) + rad1*(0.5f - rng_getFloat(rng)); - - jit[i]-= (float)floor(jit[i]); - jit[i+1]-= (float)floor(jit[i+1]); - - x+= rad3; - x -= (float)floor(x); - } - - jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit"); - - for (i=0 ; i<4 ; i++) { - BLI_jitterate1(jit, jit2, num, rad1); - BLI_jitterate1(jit, jit2, num, rad1); - BLI_jitterate2(jit, jit2, num, rad2); - } - MEM_freeN(jit2); - rng_free(rng); -} - -#define JIT_RAND 32 - -/* for a position within a face, tot is total amount of faces */ -static void give_mesh_particle_coord(PartEff *paf, VeNoCo *noco, MFace *mface, int partnr, int subnr, float *co, float *no) -{ - static float *jit= NULL; - static float *trands= NULL; - static int jitlevel= 1; - float *v1, *v2, *v3, *v4; - float u, v; - float *n1, *n2, *n3, *n4; - - /* free signal */ - if(paf==NULL) { - if(jit) MEM_freeN(jit); - jit= NULL; - if(trands) MEM_freeN(trands); - trands= NULL; - return; - } - - /* first time initialize jitter or trand, partnr then is total amount of particles, subnr total amount of faces */ - if(trands==NULL && jit==NULL) { - RNG *rng = rng_new(31415926 + paf->seed); - int i, tot; - - if(paf->flag & PAF_TRAND) - tot= partnr; - else - tot= JIT_RAND; /* arbitrary... allows JIT_RAND times more particles in a face for jittered distro */ - - trands= MEM_callocN(2+2*tot*sizeof(float), "trands"); - for(i=0; i<tot; i++) { - trands[2*i]= rng_getFloat(rng); - trands[2*i+1]= rng_getFloat(rng); - } - rng_free(rng); - - if((paf->flag & PAF_TRAND)==0) { - jitlevel= paf->userjit; - - if(jitlevel == 0) { - jitlevel= partnr/subnr; - if(paf->flag & PAF_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */ - if(jitlevel<3) jitlevel= 3; - if(jitlevel>100) jitlevel= 100; - } - - jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit"); - init_mv_jit(jit, jitlevel, paf->seed); - BLI_array_randomize(jit, 2*sizeof(float), jitlevel, paf->seed); /* for custom jit or even distribution */ - } - return; - } - - if(paf->flag & PAF_TRAND) { - u= trands[2*partnr]; - v= trands[2*partnr+1]; - } - else { - /* jittered distribution gets fixed random offset */ - if(subnr>=jitlevel) { - int jitrand= (subnr/jitlevel) % JIT_RAND; - - subnr %= jitlevel; - u= jit[2*subnr] + trands[2*jitrand]; - v= jit[2*subnr+1] + trands[2*jitrand+1]; - if(u > 1.0f) u-= 1.0f; - if(v > 1.0f) v-= 1.0f; - } - else { - u= jit[2*subnr]; - v= jit[2*subnr+1]; - } - } - - v1= (noco+(mface->v1))->co; - v2= (noco+(mface->v2))->co; - v3= (noco+(mface->v3))->co; - n1= (noco+(mface->v1))->no; - n2= (noco+(mface->v2))->no; - n3= (noco+(mface->v3))->no; - - if(mface->v4) { - float uv= u*v; - float muv= (1.0f-u)*(v); - float umv= (u)*(1.0f-v); - float mumv= (1.0f-u)*(1.0f-v); - - v4= (noco+(mface->v4))->co; - n4= (noco+(mface->v4))->no; - - co[0]= mumv*v1[0] + muv*v2[0] + uv*v3[0] + umv*v4[0]; - co[1]= mumv*v1[1] + muv*v2[1] + uv*v3[1] + umv*v4[1]; - co[2]= mumv*v1[2] + muv*v2[2] + uv*v3[2] + umv*v4[2]; - - no[0]= mumv*n1[0] + muv*n2[0] + uv*n3[0] + umv*n4[0]; - no[1]= mumv*n1[1] + muv*n2[1] + uv*n3[1] + umv*n4[1]; - no[2]= mumv*n1[2] + muv*n2[2] + uv*n3[2] + umv*n4[2]; - } - else { - /* mirror triangle uv coordinates when on other side */ - if(u + v > 1.0f) { - u= 1.0f-u; - v= 1.0f-v; - } - co[0]= v1[0] + u*(v3[0]-v1[0]) + v*(v2[0]-v1[0]); - co[1]= v1[1] + u*(v3[1]-v1[1]) + v*(v2[1]-v1[1]); - co[2]= v1[2] + u*(v3[2]-v1[2]) + v*(v2[2]-v1[2]); - - no[0]= n1[0] + u*(n3[0]-n1[0]) + v*(n2[0]-n1[0]); - no[1]= n1[1] + u*(n3[1]-n1[1]) + v*(n2[1]-n1[1]); - no[2]= n1[2] + u*(n3[2]-n1[2]) + v*(n2[2]-n1[2]); - } -} - - -/* Gets a MDeformVert's weight in group (0 if not in group) */ -/* note; this call could be in mesh.c or deform.c, but OK... it's in armature.c too! (ton) */ -static float vert_weight(MDeformVert *dvert, int group) -{ - MDeformWeight *dw; - int i; - - if(dvert) { - dw= dvert->dw; - for(i= dvert->totweight; i>0; i--, dw++) { - if(dw->def_nr == group) return dw->weight; - if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/ - } - } - return 0.0; -} - -/* Gets a faces average weight in a group, helper for below, face and weights are always set */ -static float face_weight(MFace *face, float *weights) -{ - float tweight; - - tweight = weights[face->v1] + weights[face->v2] + weights[face->v3]; - - if(face->v4) { - tweight += weights[face->v4]; - tweight /= 4.0; - } - else { - tweight /= 3.0; - } - - return tweight; -} - -/* helper function for build_particle_system() */ -static void make_weight_tables(PartEff *paf, Mesh *me, int totpart, VeNoCo *vertlist, int totvert, MFace *facelist, int totface, float **vweights, float **fweights) -{ - MFace *mface; - float *foweights=NULL, *voweights=NULL; - float totvweight=0.0f, totfweight=0.0f; - int a; - - if((paf->flag & PAF_FACE)==0) totface= 0; - - /* collect emitting vertices & faces if vert groups used */ - if(paf->vertgroup && me->dvert) { - - /* allocate weights array for all vertices, also for lookup of faces later on. note it's a malloc */ - *vweights= voweights= MEM_mallocN( totvert*sizeof(float), "pafvoweights" ); - totvweight= 0.0f; - for(a=0; a<totvert; a++) { - voweights[a]= vert_weight(me->dvert+a, paf->vertgroup-1); - totvweight+= voweights[a]; - } - - if(totface) { - /* allocate weights array for faces, note it's a malloc */ - *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" ); - for(a=0, mface=facelist; a<totface; a++, mface++) { - foweights[a] = face_weight(mface, voweights); - } - } - } - - /* make weights for faces or for even area distribution */ - if(totface && (paf->flag & PAF_EDISTR)) { - float maxfarea= 0.0f, curfarea; - - /* two cases for area distro, second case we already have group weights */ - if(foweights==NULL) { - /* allocate weights array for faces, note it's a malloc */ - *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" ); - - for(a=0, mface=facelist; a<totface; a++, mface++) { - if (mface->v4) - curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co); - else - curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co); - if(curfarea>maxfarea) - maxfarea = curfarea; - foweights[a]= curfarea; - } - } - else { - for(a=0, mface=facelist; a<totface; a++, mface++) { - if(foweights[a]!=0.0f) { - if (mface->v4) - curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co); - else - curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co); - if(curfarea>maxfarea) - maxfarea = curfarea; - foweights[a]*= curfarea; - } - } - } - - /* normalize weights for max face area, calculate tot */ - if(maxfarea!=0.0f) { - maxfarea= 1.0f/maxfarea; - for(a=0; a< totface; a++) { - if(foweights[a]!=0.0) { - foweights[a] *= maxfarea; - totfweight+= foweights[a]; - } - } - } - } - else if(foweights) { - /* only add totfweight value */ - for(a=0; a< totface; a++) { - if(foweights[a]!=0.0) { - totfweight+= foweights[a]; - } - } - } - - /* if weight arrays, we turn these arrays into the amount of particles */ - if(totvert && voweights) { - float mult= (float)totpart/totvweight; - - for(a=0; a< totvert; a++) { - if(voweights[a]!=0.0) - voweights[a] *= mult; - } - } - - if(totface && foweights) { - float mult= (float)totpart/totfweight; - - for(a=0; a< totface; a++) { - if(foweights[a]!=0.0) - foweights[a] *= mult; - } - } -} - -/* helper function for build_particle_system() */ -static void make_length_tables(PartEff *paf, Mesh *me, int totvert, MFace *facelist, int totface, float **vlengths, float **flengths) -{ - MFace *mface; - float *folengths=NULL, *volengths=NULL; - int a; - - if((paf->flag & PAF_FACE)==0) totface= 0; - - /* collect emitting vertices & faces if vert groups used */ - if(paf->vertgroup_v && me->dvert) { - - /* allocate lengths array for all vertices, also for lookup of faces later on. note it's a malloc */ - *vlengths= volengths= MEM_mallocN( totvert*sizeof(float), "pafvolengths" ); - for(a=0; a<totvert; a++) { - volengths[a]= vert_weight(me->dvert+a, paf->vertgroup_v-1); - } - - if(totface) { - /* allocate lengths array for faces, note it's a malloc */ - *flengths= folengths= MEM_mallocN(totface*sizeof(float), "paffolengths" ); - for(a=0, mface=facelist; a<totface; a++, mface++) { - folengths[a] = face_weight(mface, volengths); - } - } - } -} - /* for paf start to end, store all matrices for objects */ typedef struct pMatrixCache { @@ -1539,572 +432,7 @@ typedef struct pMatrixCache { float imat[3][3]; } pMatrixCache; - -/* WARN: this function stores data in ob->id.idnew! */ -/* error: this function changes ob->recalc of other objects... */ -static pMatrixCache *cache_object_matrices(Object *ob, int start, int end) -{ - pMatrixCache *mcache, *mc; - Group *group= NULL; - Object *obcopy; - Base *base; - float framelenold, cfrao, sfo; - - /* object can be linked in group... stupid exception */ - if(NULL==object_in_scene(ob, G.scene)) - group= find_group(ob, NULL); /* TODO - dont just use the first group! - Campbell */ - - mcache= mc= MEM_mallocN( (end-start+1)*sizeof(pMatrixCache), "ob matrix cache"); - - framelenold= G.scene->r.framelen; - G.scene->r.framelen= 1.0f; - cfrao= G.scene->r.cfra; - sfo= ob->sf; /* warning, dont use sfo, value should be from give_timeoffset if used for anything */ - ob->sf= 0.0f; - - /* clear storage, copy recalc tag (bad loop) */ - for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next) { - obcopy->id.newid= NULL; - obcopy->recalco= obcopy->recalc; - obcopy->recalc= 0; - } - - /* all objects get tagged recalc that influence this object (does group too) */ - /* note that recalco has the real recalc tags, set by callers of this function */ - ob->recalc |= OB_RECALC_OB; /* make sure a recalc gets flushed */ - DAG_object_update_flags(G.scene, ob, -1); - - for(G.scene->r.cfra= start; G.scene->r.cfra<=end; G.scene->r.cfra++, mc++) { - - if(group) { - GroupObject *go; - - for(go= group->gobject.first; go; go= go->next) { - if(go->ob->recalc) { - where_is_object(go->ob); - - do_ob_key(go->ob); - if(go->ob->type==OB_ARMATURE) { - do_all_pose_actions(go->ob); // only does this object actions - where_is_pose(go->ob); - } - } - } - } - else { - for(base= G.scene->base.first; base; base= base->next) { - if(base->object->recalc) { - if(base->object->id.newid==NULL) - base->object->id.newid= MEM_dupallocN(base->object); - - where_is_object(base->object); - - do_ob_key(base->object); - if(base->object->type==OB_ARMATURE) { - do_all_pose_actions(base->object); // only does this object actions - where_is_pose(base->object); - } - } - } - } - Mat4CpyMat4(mc->obmat, ob->obmat); - Mat4Invert(ob->imat, ob->obmat); - Mat3CpyMat4(mc->imat, ob->imat); - Mat3Transp(mc->imat); - } - - /* restore */ - G.scene->r.cfra= cfrao; - G.scene->r.framelen= framelenold; - ob->sf= sfo; - - if(group) { - GroupObject *go; - - for(go= group->gobject.first; go; go= go->next) { - if(go->ob->recalc) { - where_is_object(go->ob); - - do_ob_key(go->ob); - if(go->ob->type==OB_ARMATURE) { - do_all_pose_actions(go->ob); // only does this object actions - where_is_pose(go->ob); - } - } - } - } - else { - for(base= G.scene->base.first; base; base= base->next) { - if(base->object->recalc) { - - if(base->object->id.newid) { - obcopy= (Object *)base->object->id.newid; - *(base->object) = *(obcopy); - MEM_freeN(obcopy); - base->object->id.newid= NULL; - } - - do_ob_key(base->object); - if(base->object->type==OB_ARMATURE) { - do_all_pose_actions(base->object); // only does this object actions - where_is_pose(base->object); - } - } - } - } - - /* copy recalc tag (bad loop) */ - for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next) - obcopy->recalc= obcopy->recalco; - - return mcache; -} - /* for fluidsim win32 debug messages */ #if defined(WIN32) && (!(defined snprintf)) #define snprintf _snprintf #endif - -/* main particle building function - one day particles should become dynamic (realtime) with the current method as a 'bake' (ton) */ -void build_particle_system(Object *ob) -{ - RNG *rng; - PartEff *paf; - Particle *pa; - Mesh *me; - Base *base; - MTex *mtexmove=0, *mtextime=0; - Material *ma; - MFace *facelist= NULL; - pMatrixCache *mcache=NULL, *mcnow, *mcprev; - ListBase *effectorbase; - VeNoCo *vertexcosnos; - double startseconds= PIL_check_seconds_timer(); - float ftime, dtime, force[3], vec[3], fac, co[3], no[3]; - float *voweights= NULL, *foweights= NULL, maxw=1.0f; - float *volengths= NULL, *folengths= NULL; - int deform=0, a, totpart, paf_sta, paf_end; - int waitcursor_set= 0, totvert, totface, curface, curvert; -#ifndef DISABLE_ELBEEM - int readMask, activeParts, fileParts; -#endif - - /* return conditions */ - if(ob->type!=OB_MESH) return; - me= ob->data; - - paf= give_parteff(ob); - if(paf==NULL) return; - - if(G.rendering==0 && paf->disp==0) return; - - if(paf->keys) MEM_freeN(paf->keys); /* free as early as possible, for returns */ - paf->keys= NULL; - - //printf("build particles\n"); - - /* fluid sim particle import handling, actual loading of particles from file */ - #ifndef DISABLE_ELBEEM - if( (1) && (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && // broken, disabled for now! - (ob->fluidsimSettings) && - (ob->fluidsimSettings->type == OB_FLUIDSIM_PARTICLE)) { - char *suffix = "fluidsurface_particles_#"; - char *suffix2 = ".gz"; - char filename[256]; - char debugStrBuffer[256]; - int curFrame = G.scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading - int j, numFileParts; - gzFile gzf; - float vel[3]; - - if(ob==G.obedit) { // off... - paf->totpart = 0; // 1 or 0? - return; - } - - // ok, start loading - strcpy(filename, ob->fluidsimSettings->surfdataPath); - strcat(filename, suffix); - BLI_convertstringcode(filename, G.sce, curFrame); // fixed #frame-no - strcat(filename, suffix2); - - gzf = gzopen(filename, "rb"); - if (!gzf) { - snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename); - //elbeemDebugOut(debugStrBuffer); - paf->totpart = 0; - return; - } - - gzread(gzf, &totpart, sizeof(totpart)); - numFileParts = totpart; - totpart = (G.rendering)?totpart:(paf->disp*totpart)/100; - paf->totpart= totpart; - paf->totkey= 1; - /* initialize particles */ - new_particle(paf); - ftime = 0.0; // unused... - - // set up reading mask - readMask = ob->fluidsimSettings->typeFlags; - activeParts=0; - fileParts=0; - - for(a=0; a<totpart; a++) { - int ptype=0; - short shsize=0; - float convertSize=0.0; - gzread(gzf, &ptype, sizeof( ptype )); - if(ptype&readMask) { - activeParts++; - pa= new_particle(paf); - pa->time= ftime; - pa->lifetime= ftime + 10000.; // add large number to make sure they are displayed, G.scene->r.efra +1.0; - pa->co[0] = 0.0; - pa->co[1] = - pa->co[2] = 1.0*(float)a / (float)totpart; - pa->no[0] = pa->no[1] = pa->no[2] = 0.0; - pa->mat_nr= paf->omat; - gzread(gzf, &convertSize, sizeof( float )); - // convert range of 1.0-10.0 to shorts 1000-10000) - shsize = (short)(convertSize*1000.0); - pa->rt = shsize; - - for(j=0; j<3; j++) { - float wrf; - gzread(gzf, &wrf, sizeof( wrf )); - pa->co[j] = wrf; - //fprintf(stderr,"Rj%d ",j); - } - for(j=0; j<3; j++) { - float wrf; - gzread(gzf, &wrf, sizeof( wrf )); - vel[j] = wrf; - } - //if(a<25) fprintf(stderr,"FSPARTICLE debug set %s , a%d = %f,%f,%f , life=%f \n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime ); - } else { - // skip... - for(j=0; j<2*3+1; j++) { - float wrf; gzread(gzf, &wrf, sizeof( wrf )); - } - } - fileParts++; - } - gzclose( gzf ); - - totpart = paf->totpart = activeParts; - snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", paf->totpart,activeParts,fileParts,readMask); - elbeemDebugOut(debugStrBuffer); - return; - } // fluid sim particles done - #endif // DISABLE_ELBEEM - - if(paf->end < paf->sta) return; - - if( (paf->flag & PAF_OFACE) && (paf->flag & PAF_FACE)==0) return; - - if(me->totvert==0) return; - - if(ob==G.obedit) return; - totpart= (G.rendering)?paf->totpart:(paf->disp*paf->totpart)/100; - if(totpart==0) return; - - /* No returns after this line! */ - - /* material */ - ma= give_current_material(ob, paf->omat); - if(ma) { - if(paf->speedtex) - mtexmove= ma->mtex[paf->speedtex-1]; - mtextime= ma->mtex[paf->timetex-1]; - } - - disable_speed_curve(1); /* check this... */ - - /* initialize particles */ - new_particle(paf); - - /* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */ - for(base= G.scene->base.first; base; base= base->next) - base->object->sumohandle= NULL; - - /* all object positions from start to end */ - paf_sta= (int)floor(paf->sta); - paf_end= (int)ceil(paf->end); - if((paf->flag & PAF_STATIC)==0) - mcache= cache_object_matrices(ob, paf_sta, paf_end); - - /* mult generations? */ - for(a=0; a<PAF_MAXMULT; a++) { - if(paf->mult[a]!=0.0) { - /* interesting formula! this way after 'x' generations the total is paf->totpart */ - totpart= (int)(totpart / (1.0+paf->mult[a]*paf->child[a])); - } - else break; - } - - /* for static particles, calculate system on current frame (? ton) */ - if(ma) do_mat_ipo(ma); - - /* matrix invert for static too */ - Mat4Invert(ob->imat, ob->obmat); - Mat4CpyMat4(paf->imat, ob->imat); /* used for duplicators */ - - /* new random generator */ - rng = rng_new(paf->seed); - - /* otherwise it goes way too fast */ - force[0]= paf->force[0]*0.05f; - force[1]= paf->force[1]*0.05f; - force[2]= paf->force[2]*0.05f; - - if( paf->flag & PAF_STATIC ) deform= 0; - else { - Object *parlatt= modifiers_isDeformedByLattice(ob); - if(parlatt) { - deform= 1; - init_latt_deform(parlatt, 0); - } - } - - /* get the effectors */ - effectorbase= pdInitEffectors(ob, paf->group); - - /* init geometry, return is 6 x float * me->totvert in size */ - vertexcosnos= (VeNoCo *)mesh_get_mapped_verts_nors(ob); - facelist= me->mface; - totvert= me->totvert; - totface= me->totface; - - /* if vertexweights or even distribution, it makes weight tables, also checks where it emits from */ - make_weight_tables(paf, me, totpart, vertexcosnos, totvert, facelist, totface, &voweights, &foweights); - - /* vertexweights can define lengths too */ - make_length_tables(paf, me, totvert, facelist, totface, &volengths, &folengths); - - /* now define where to emit from, if there are face weights we skip vertices */ - if(paf->flag & PAF_OFACE) totvert= 0; - if((paf->flag & PAF_FACE)==0) totface= 0; - if(foweights) totvert= 0; - - /* initialize give_mesh_particle_coord */ - if(totface) - give_mesh_particle_coord(paf, vertexcosnos, facelist, totpart, totface, NULL, NULL); - - /* correction for face timing when using weighted average */ - if(totface && foweights) { - maxw= (paf->end-paf->sta)/foweights[0]; - } - else if(totvert && voweights) { - maxw= (paf->end-paf->sta)/voweights[0]; - } - - /* for loop below */ - if (paf->flag & PAF_STATIC) { - ftime = G.scene->r.cfra; - dtime= 0.0f; - } else { - ftime= paf->sta; - dtime= (paf->end - paf->sta)/(float)totpart; - } - - curface= curvert= 0; - for(a=0; a<totpart; a++, ftime+=dtime) { - - /* we set waitcursor only when a half second expired, particles now are realtime updated */ - if(waitcursor_set==0 && (a % 256)==255) { - double seconds= PIL_check_seconds_timer(); - if(seconds - startseconds > 0.5) { - waitcursor(1); - waitcursor_set= 1; - } - } - - pa= new_particle(paf); - pa->time= ftime; - - /* get coordinates from faces, only when vertices set to zero */ - if(totvert==0 && totface) { - int curjit; - - /* use weight table, we have to do faces in order to be able to use jitter table... */ - if(foweights) { - - if(foweights[curface] < 1.0f) { - float remainder= 0.0f; - - while(remainder + foweights[curface] < 1.0f && curface<totface-1) { - remainder += foweights[curface]; - curface++; - } - /* if this is the last face, the foweights[] can be zero, so we don't add a particle extra */ - if(curface!=totface-1) - foweights[curface] += remainder; - - maxw= (paf->end-paf->sta)/foweights[curface]; - } - - if(foweights[curface]==0.0f) - break; /* WARN skips here out of particle generating */ - else { - if(foweights[curface] >= 1.0f) /* note the >= here, this because of the < 1.0f above, it otherwise will stick to 1 face forever */ - foweights[curface] -= 1.0f; - - curjit= (int) foweights[curface]; - give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no); - - /* time correction to make particles appear evenly, maxw does interframe (0-1) */ - pa->time= paf->sta + maxw*foweights[curface]; - } - } - else { - curface= a % totface; - curjit= a/totface; - give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no); - } - } - /* get coordinates from vertices */ - if(totvert) { - /* use weight table */ - if(voweights) { - - if(voweights[curvert] < 1.0f) { - float remainder= 0.0f; - - while(remainder + voweights[curvert] < 1.0f && curvert<totvert-1) { - remainder += voweights[curvert]; - curvert++; - } - voweights[curvert] += remainder; - maxw= (paf->end-paf->sta)/voweights[curvert]; - } - - if(voweights[curvert]==0.0f) - break; /* WARN skips here out of particle generating */ - else { - if(voweights[curvert] > 1.0f) - voweights[curvert] -= 1.0f; - - /* time correction to make particles appear evenly */ - pa->time= paf->sta + maxw*voweights[curvert]; - } - } - else { - curvert= a % totvert; - if(a >= totvert && totface) - totvert= 0; - } - - VECCOPY(co, vertexcosnos[curvert].co); - VECCOPY(no, vertexcosnos[curvert].no); - } - - VECCOPY(pa->co, co); - - /* dynamic options */ - if((paf->flag & PAF_STATIC)==0) { - int cur; - - /* particle retiming with texture */ - if(mtextime && (paf->flag2 & PAF_TEXTIME)) { - float tin, tr, tg, tb, ta, orco[3]; - - /* calculate normalized orco */ - orco[0] = (co[0]-me->loc[0])/me->size[0]; - orco[1] = (co[1]-me->loc[1])/me->size[1]; - orco[2] = (co[2]-me->loc[2])/me->size[2]; - externtex(mtextime, orco, &tin, &tr, &tg, &tb, &ta); - - if(paf->flag2neg & PAF_TEXTIME) - pa->time = paf->sta + (paf->end - paf->sta)*tin; - else - pa->time = paf->sta + (paf->end - paf->sta)*(1.0f-tin); - } - - /* set ob at correct time, we use cached matrices */ - cur= (int)floor(pa->time) + 1 ; /* + 1 has a reason: (obmat/prevobmat) otherwise comet-tails start too late */ - - if(cur <= paf_end) mcnow= mcache + cur - paf_sta; - else mcnow= mcache + paf_end - paf_sta; - - if(cur > paf_sta) mcprev= mcnow-1; - else mcprev= mcache; - - /* move to global space */ - Mat4MulVecfl(mcnow->obmat, pa->co); - - VECCOPY(vec, co); - Mat4MulVecfl(mcprev->obmat, vec); - - /* first start speed: object */ - VECSUB(pa->no, pa->co, vec); - - VecMulf(pa->no, paf->obfac); - - /* calculate the correct inter-frame */ - fac= (pa->time- (float)floor(pa->time)); - pa->co[0]= fac*pa->co[0] + (1.0f-fac)*vec[0]; - pa->co[1]= fac*pa->co[1] + (1.0f-fac)*vec[1]; - pa->co[2]= fac*pa->co[2] + (1.0f-fac)*vec[2]; - - /* start speed: normal */ - if(paf->normfac!=0.0) { - /* imat is transpose ! */ - VECCOPY(vec, no); - Mat3MulVecfl(mcnow->imat, vec); - - Normalize(vec); - VecMulf(vec, paf->normfac); - VECADD(pa->no, pa->no, vec); - } - } - else { - if(paf->normfac!=0.0) { - VECCOPY(pa->no, no); - Normalize(pa->no); - VecMulf(pa->no, paf->normfac); - } - } - - pa->lifetime= paf->lifetime; - if(paf->randlife!=0.0) { - pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f); - } - pa->mat_nr= paf->omat; - - if(folengths) - pa->lifetime*= folengths[curface]; - - make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, effectorbase); - } - - /* free stuff */ - give_mesh_particle_coord(NULL, NULL, NULL, 0, 0, NULL, NULL); - MEM_freeN(vertexcosnos); - if(voweights) MEM_freeN(voweights); - if(foweights) MEM_freeN(foweights); - if(volengths) MEM_freeN(volengths); - if(folengths) MEM_freeN(folengths); - if(mcache) MEM_freeN(mcache); - rng_free(rng); - - if(deform) end_latt_deform(); - - if(effectorbase) - pdEndEffectors(effectorbase); - - /* reset deflector cache */ - for(base= G.scene->base.first; base; base= base->next) { - if(base->object->sumohandle) { - - MEM_freeN(base->object->sumohandle); - base->object->sumohandle= NULL; - } - } - - disable_speed_curve(0); - - if(waitcursor_set) waitcursor(0); -} - diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c index 0f1f8c6078a..fb48c875995 100644 --- a/source/blender/blenkernel/intern/exotic.c +++ b/source/blender/blenkernel/intern/exotic.c @@ -1,14 +1,11 @@ /* exotic.c * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * Added dxf_read_arc, dxf_read_ellipse and dxf_read_lwpolyline * Copyright (C) 2004 by Etheract Software Labs * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** * * eigen videoscape formaat: * @@ -878,7 +875,7 @@ static void read_videoscape_lamp(char *str) Object *ob; Lamp *la; FILE *fp; - float vec[3], *q1; + float vec[3], q1[4]; int tot, val; char s[50]; @@ -906,7 +903,7 @@ static void read_videoscape_lamp(char *str) fscanf(fp, "%f %f %f\n", ob->loc, ob->loc+1, ob->loc+2); val= fscanf(fp, "%f %f %f\n", vec, vec+1, vec+2); - q1= vectoquat(vec, 5, 2); + vectoquat(vec, 5, 2, q1); QuatToEul(q1, ob->rot); if(val<=0) break; diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index fc11b3d234d..09c93962990 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -162,41 +159,61 @@ utf8slen(char *src) return size; } -int utf8towchar_(wchar_t *w, char *c) + +/* Converts Unicode to wchar + +According to RFC 3629 "UTF-8, a transformation format of ISO 10646" +(http://tools.ietf.org/html/rfc3629), the valid UTF-8 encoding are: + + Char. number range | UTF-8 octet sequence + (hexadecimal) | (binary) + --------------------+--------------------------------------------- + 0000 0000-0000 007F | 0xxxxxxx + 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +If the encoding incidated by the first character is incorrect (because the +1 to 3 following characters do not match 10xxxxxx), the output is a '?' and +only a single input character is consumed. + +*/ + +int utf8towchar(wchar_t *w, char *c) { int len=0; + if(w==NULL || c==NULL) return(0); - //printf("%s\n",c); - while(*c) - { - if(*c & 0x80) - { - if(*c & 0x40) - { - if(*c & 0x20) - { - if(*c & 0x10) - { - *w=(c[0] & 0x0f)<<18 | (c[1]&0x1f)<<12 | (c[2]&0x3f)<<6 | (c[3]&0x7f); - c++; - } - else - *w=(c[0] & 0x1f)<<12 | (c[1]&0x3f)<<6 | (c[2]&0x7f); - c++; - } - else - *w=(((c[0] &0x3f)<<6) | (c[1]&0x7f)); + + while(*c) { + if ((*c & 0xe0) == 0xc0) { + if((c[1] & 0x80) && (c[1] & 0x40) == 0x00) { + *w=((c[0] &0x1f)<<6) | (c[1]&0x3f); c++; + } else { + *w = '?'; } - else - *w=(c[0] & 0x7f); + } else if ((*c & 0xf0) == 0xe0) { + if((c[1] & c[2] & 0x80) && ((c[1] | c[2]) & 0x40) == 0x00) { + *w=((c[0] & 0x0f)<<12) | ((c[1]&0x3f)<<6) | (c[2]&0x3f); + c += 2; + } else { + *w = '?'; } - else - *w=(c[0] & 0x7f); - c++; - w++; - len++; - } + } else if ((*c & 0xf8) == 0xf0) { + if((c[1] & c[2] & c[3] & 0x80) && ((c[1] | c[2] | c[3]) & 0x40) == 0x00) { + *w=((c[0] & 0x07)<<18) | ((c[1]&0x1f)<<12) | ((c[2]&0x3f)<<6) | (c[3]&0x3f); + c += 3; + } else { + *w = '?'; + } + } else + *w=(c[0] & 0x7f); + + c++; + w++; + len++; + } return len; } @@ -644,7 +661,7 @@ struct chartrans *text_to_curve(Object *ob, int mode) utf8len = utf8slen(cu->str); tmp = mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem"); - utf8towchar_(mem, cu->str); + utf8towchar(mem, cu->str); // Count the wchar_t string length slen = wcslen(mem); diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index a85f0f52ad2..2ffe8590b59 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -41,6 +41,7 @@ #include "DNA_object_types.h" #include "DNA_nla_types.h" #include "DNA_scene_types.h" +#include "DNA_particle_types.h" #include "BLI_blenlib.h" @@ -77,14 +78,27 @@ void unlink_group(Group *group) { Material *ma; Object *ob; + Scene *sce; + SceneRenderLayer *srl; + ParticleSystem *psys; for(ma= G.main->mat.first; ma; ma= ma->id.next) { if(ma->group==group) ma->group= NULL; } + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->group==group) + ma->group= NULL; + } + for (sce= G.main->scene.first; sce; sce= sce->id.next) { + for(srl= sce->r.layers.first; srl; srl= srl->next) { + if (srl->light_override==group) + srl->light_override= NULL; + } + } + for(ob= G.main->object.first; ob; ob= ob->id.next) { bActionStrip *strip; - PartEff *paf; if(ob->dup_group==group) { ob->dup_group= NULL; @@ -95,11 +109,12 @@ void unlink_group(Group *group) strip->object= NULL; } } - for(paf= ob->effect.first; paf; paf= paf->next) { - if(paf->type==EFF_PARTICLE) { - if(paf->group) - paf->group= NULL; - } + + for(psys=ob->particlesystem.first; psys; psys=psys->next){ + if(psys->part->dup_group==group) + psys->part->dup_group= NULL; + if(psys->part->eff_group==group) + psys->part->eff_group= NULL; } } group->id.us= 0; @@ -134,11 +149,11 @@ void add_to_group(Group *group, Object *ob) } /* also used for ob==NULL */ -void rem_from_group(Group *group, Object *ob) +int rem_from_group(Group *group, Object *ob) { GroupObject *go, *gon; - - if(group==NULL) return; + int removed = 0; + if(group==NULL) return 0; go= group->gobject.first; while(go) { @@ -146,9 +161,12 @@ void rem_from_group(Group *group, Object *ob) if(go->ob==ob) { BLI_remlink(&group->gobject, go); free_group_object(go); + removed = 1; + /* should break here since an object being in a group twice cant happen? */ } go= gon; } + return removed; } int object_in_group(Object *ob, Group *group) diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index f144d2badd1..cab7865c1b6 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -48,6 +48,7 @@ #include "BLI_ghash.h" #include "BKE_icons.h" +#include "BKE_utildefines.h" #define GS(a) (*((short *)(a))) @@ -87,7 +88,7 @@ static int get_next_free_id() return gNextIconId++; /* now we try to find the smallest icon id not stored in the gIcons hash */ - while (BLI_ghash_lookup(gIcons, (void *)startId) && startId>=gFirstIconId) + while (BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(startId)) && startId>=gFirstIconId) startId++; /* if we found a suitable one that isnt used yet, return it */ @@ -216,7 +217,7 @@ void BKE_icon_changed(int id) if (!id) return; - icon = BLI_ghash_lookup(gIcons, (void *)id); + icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id)); if (icon) { @@ -258,7 +259,7 @@ int BKE_icon_getid(struct ID* id) new_icon->drawinfo = 0; new_icon->drawinfo_free = 0; - BLI_ghash_insert(gIcons, (void *)id->icon_id, new_icon); + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon); return id->icon_id; } @@ -267,7 +268,7 @@ Icon* BKE_icon_get(int icon_id) { Icon* icon = 0; - icon = BLI_ghash_lookup(gIcons, (void*)icon_id); + icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id)); if (!icon) { printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id); @@ -281,7 +282,7 @@ void BKE_icon_set(int icon_id, struct Icon* icon) { Icon* old_icon = 0; - old_icon = BLI_ghash_lookup(gIcons, (void*)icon_id); + old_icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id)); if (old_icon) { @@ -289,7 +290,7 @@ void BKE_icon_set(int icon_id, struct Icon* icon) return; } - BLI_ghash_insert(gIcons, (void *)icon_id, icon); + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), icon); } void BKE_icon_delete(struct ID* id) @@ -297,6 +298,6 @@ void BKE_icon_delete(struct ID* id) if (!id->icon_id) return; /* no icon defined for library object */ - BLI_ghash_remove(gIcons, (void*)id->icon_id, 0, icon_free); + BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), 0, icon_free); id->icon_id = 0; } diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index bf2a3aae11a..2ef2f3a1b77 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -1,15 +1,12 @@ /** * $Id: idprop.c * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,7 +22,7 @@ * * Contributor(s): Joseph Eagar * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include "DNA_listBase.h" @@ -212,7 +209,8 @@ void IDP_UnlinkID(IDProperty *prop) IDProperty *IDP_CopyGroup(IDProperty *prop) { IDProperty *newp = idp_generic_copy(prop), *link; - + newp->len = prop->len; + for (link=prop->data.group.first; link; link=link->next) { BLI_addtail(&newp->data.group, IDP_CopyProperty(link)); } @@ -227,10 +225,11 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop) if (BSTR_EQ(loop->name, prop->name)) { if (loop->next) BLI_insertlinkbefore(&group->data.group, loop->next, prop); else BLI_addtail(&group->data.group, prop); + BLI_remlink(&group->data.group, loop); IDP_FreeProperty(loop); MEM_freeN(loop); - group->len++; + return; } } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 0c45356eb0b..ff0b2e6db0a 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -246,7 +246,6 @@ static void image_free_buffers(Image *ima) /* called by library too, do not free ima itself */ void free_image(Image *ima) { - image_free_buffers(ima); if (ima->packedfile) { freePackedFile(ima->packedfile); @@ -257,7 +256,6 @@ void free_image(Image *ima) if (ima->preview) { BKE_previewimg_free(&ima->preview); } - } /* only image block itself */ @@ -283,15 +281,19 @@ static Image *image_alloc(const char *name, short source, short type) /* get the ibuf from an image cache, local use here only */ static ImBuf *image_get_ibuf(Image *ima, int index, int frame) { + /* this function is intended to be thread safe. with IMA_NO_INDEX this + * should be OK, but when iterating over the list this is more tricky + * */ if(index==IMA_NO_INDEX) return ima->ibufs.first; else { ImBuf *ibuf; - + index= IMA_MAKE_INDEX(frame, index); for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next) if(ibuf->index==index) return ibuf; + return NULL; } } @@ -319,19 +321,16 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) for(link= ima->ibufs.first; link; link= link->next) if(link->index>=index) break; - /* now we don't want copies? */ - if(link && ibuf->index==link->index) { - ImBuf *prev= ibuf->prev; - image_remove_ibuf(ima, link); - link= prev; - } - + + ibuf->index= index; + /* this function accepts link==NULL */ BLI_insertlinkbefore(&ima->ibufs, link, ibuf); - - ibuf->index= index; + + /* now we don't want copies? */ + if(link && ibuf->index==link->index) + image_remove_ibuf(ima, link); } - } /* checks if image was already loaded, then returns same image */ @@ -352,7 +351,8 @@ Image *BKE_add_image_file(const char *name) } BLI_strncpy(str, name, sizeof(str)); - BLI_convertstringcode(str, G.sce, G.scene->r.cfra); + BLI_convertstringcode(str, G.sce); + BLI_convertstringframe(str, G.scene->r.cfra); /* TODO - should this realy be here? */ /* exists? */ file= open(str, O_BINARY|O_RDONLY); @@ -363,7 +363,8 @@ Image *BKE_add_image_file(const char *name) for(ima= G.main->image.first; ima; ima= ima->id.next) { if(ima->source!=IMA_SRC_VIEWER && ima->source!=IMA_SRC_GENERATED) { BLI_strncpy(strtest, ima->name, sizeof(ima->name)); - BLI_convertstringcode(strtest, G.sce, G.scene->r.cfra); + BLI_convertstringcode(strtest, G.sce); + BLI_convertstringframe(strtest, G.scene->r.cfra); /* TODO - should this be here? */ if( strcmp(strtest, str)==0 ) { if(ima->anim==NULL || ima->id.us==0) { @@ -629,6 +630,47 @@ void free_old_images() } } +static unsigned long image_mem_size(Image *ima) +{ + ImBuf *ibuf, *ibufm; + int level; + unsigned long size = 0; + + size= 0; + for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next) { + if(ibuf->rect) size += MEM_allocN_len(ibuf->rect); + else if(ibuf->rect_float) size += MEM_allocN_len(ibuf->rect_float); + + for(level=0; level<IB_MIPMAP_LEVELS; level++) { + ibufm= ibuf->mipmap[level]; + if(ibufm) { + if(ibufm->rect) size += MEM_allocN_len(ibufm->rect); + else if(ibufm->rect_float) size += MEM_allocN_len(ibufm->rect_float); + } + } + } + + return size; +} + +void BKE_image_print_memlist(void) +{ + Image *ima; + unsigned long size, totsize= 0; + + for(ima= G.main->image.first; ima; ima= ima->id.next) + totsize += image_mem_size(ima); + + printf("\ntotal image memory len: %.3lf MB\n", (double)totsize/(double)(1024*1024)); + + for(ima= G.main->image.first; ima; ima= ima->id.next) { + size= image_mem_size(ima); + + if(size) + printf("%s len: %.3f MB\n", ima->id.name+2, (double)size/(double)(1024*1024)); + } +} + void BKE_image_free_all_textures(void) { Tex *tex; @@ -865,8 +907,13 @@ static void stampdata(StampData *stamp_data, int do_prefix) #endif /* WIN32 */ if (G.scene->r.stamp & R_STAMP_FILENAME) { - if (do_prefix) sprintf(stamp_data->file, "File %s", G.sce); - else sprintf(stamp_data->file, "%s", G.sce); + if (G.relbase_valid) { + if (do_prefix) sprintf(stamp_data->file, "File %s", G.sce); + else sprintf(stamp_data->file, "%s", G.sce); + } else { + if (do_prefix) strcpy(stamp_data->file, "File <untitled>"); + else strcpy(stamp_data->file, "<untitled>"); + } stamp_data->note[0] = '\0'; } else { stamp_data->file[0] = '\0'; @@ -1136,6 +1183,9 @@ int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quali } else if ((G.have_libtiff) && (imtype==R_TIFF)) { ibuf->ftype= TIF; + + if(subimtype & R_TIFF_16BIT) + ibuf->ftype |= TIF_16BIT; } #ifdef WITH_OPENEXR else if (imtype==R_OPENEXR || imtype==R_MULTILAYER) { @@ -1187,23 +1237,16 @@ int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quali void BKE_makepicstring(char *string, char *base, int frame, int imtype) { - short i, len, digits= 4; /* digits in G.scene? */ - char num[10]; - if (string==NULL) return; BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */ - BLI_convertstringcode(string, G.sce, frame); - - len= strlen(string); - - i= digits - sprintf(num, "%d", frame); - for(; i>0; i--){ - string[len]= '0'; - len++; - } - string[len]= 0; - strcat(string, num); + + /* if we dont have any #'s to insert numbers into, use 4 numbers by default */ + if (strchr(string, '#')==NULL) + strcat(string, "####"); /* 4 numbers */ + + BLI_convertstringcode(string, G.sce); + BLI_convertstringframe(string, frame); if(G.scene->r.scemode & R_EXTENSION) BKE_add_image_extension(string, imtype); @@ -1439,9 +1482,11 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) BLI_strncpy(name, ima->name, sizeof(name)); if(ima->id.lib) - BLI_convertstringcode(name, ima->id.lib->filename, frame); + BLI_convertstringcode(name, ima->id.lib->filename); else - BLI_convertstringcode(name, G.sce, frame); + BLI_convertstringcode(name, G.sce); + + BLI_convertstringframe(name, frame); /* TODO - should this be here? */ /* read ibuf */ ibuf = IMB_loadiffname(name, IB_rect|IB_multilayer); @@ -1457,12 +1502,12 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) ibuf= NULL; } else { - image_assign_ibuf(ima, ibuf, 0, frame); image_initialize_after_load(ima, ibuf); + image_assign_ibuf(ima, ibuf, 0, frame); } #else - image_assign_ibuf(ima, ibuf, 0, frame); image_initialize_after_load(ima, ibuf); + image_assign_ibuf(ima, ibuf, 0, frame); #endif } else @@ -1498,8 +1543,9 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f // if(oldrr) printf("freed previous result %p\n", oldrr); if(oldrr) RE_FreeRenderResult(oldrr); } - else + else { ima->rr= oldrr; + } } if(ima->rr) { @@ -1514,8 +1560,8 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f ibuf->mall= IB_rectfloat; ibuf->channels= rpass->channels; - image_assign_ibuf(ima, ibuf, iuser->multi_index, frame); image_initialize_after_load(ima, ibuf); + image_assign_ibuf(ima, ibuf, iuser->multi_index, frame); } // else printf("pass not found\n"); @@ -1541,9 +1587,9 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) BLI_strncpy(str, ima->name, FILE_MAX); if(ima->id.lib) - BLI_convertstringcode(str, ima->id.lib->filename, 0); + BLI_convertstringcode(str, ima->id.lib->filename); else - BLI_convertstringcode(str, G.sce, 0); + BLI_convertstringcode(str, G.sce); ima->anim = openanim(str, IB_cmap | IB_rect); @@ -1561,8 +1607,8 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame) ibuf = IMB_anim_absolute(ima->anim, fra); if(ibuf) { - image_assign_ibuf(ima, ibuf, 0, frame); image_initialize_after_load(ima, ibuf); + image_assign_ibuf(ima, ibuf, 0, frame); } else ima->ok= 0; @@ -1581,6 +1627,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) { struct ImBuf *ibuf; char str[FILE_MAX]; + int assign = 0; /* always ensure clean ima */ image_free_buffers(ima); @@ -1594,9 +1641,11 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) /* get the right string */ BLI_strncpy(str, ima->name, sizeof(str)); if(ima->id.lib) - BLI_convertstringcode(str, ima->id.lib->filename, cfra); + BLI_convertstringcode(str, ima->id.lib->filename); else - BLI_convertstringcode(str, G.sce, cfra); + BLI_convertstringcode(str, G.sce); + + BLI_convertstringframe(str, cfra); /* read ibuf */ ibuf = IMB_loadiffname(str, IB_rect|IB_multilayer|IB_imginfo); @@ -1611,8 +1660,8 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) ibuf= NULL; } else { - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); image_initialize_after_load(ima, ibuf); + assign= 1; /* check if the image is a font image... */ detectBitmapFont(ibuf); @@ -1628,6 +1677,9 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) else ima->ok= 0; + if(assign) + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + if(iuser) iuser->ok= ima->ok; @@ -1651,12 +1703,13 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) if(rpass) { ibuf= IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0, 0); - image_assign_ibuf(ima, ibuf, iuser?iuser->multi_index:IMA_NO_INDEX, 0); image_initialize_after_load(ima, ibuf); ibuf->rect_float= rpass->rect; ibuf->flags |= IB_rectfloat; ibuf->channels= rpass->channels; + + image_assign_ibuf(ima, ibuf, iuser?iuser->multi_index:IMA_NO_INDEX, 0); } } @@ -1724,6 +1777,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser) ibuf->rect_float= rectf; ibuf->flags |= IB_rectfloat; ibuf->channels= channels; + ibuf->zbuf_float= rres.rectz; + ibuf->flags |= IB_zbuffloat; ima->ok= IMA_OK_LOADED; return ibuf; @@ -1733,118 +1788,171 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser) return NULL; } -/* Checks optional ImageUser and verifies/creates ImBuf. */ -/* returns ibuf */ -ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser) +static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame_r, int *index_r) { - ImBuf *ibuf= NULL; - float color[] = {0, 0, 0, 1}; + ImBuf *ibuf = NULL; + int frame = 0, index = 0; - /* quick reject tests */ - if(ima==NULL) - return NULL; - if(iuser) { - if(iuser->ok==0) - return NULL; - } - else if(ima->ok==0) - return NULL; - - BLI_lock_thread(LOCK_IMAGE); - - /* handle image source and types */ + /* see if we already have an appropriate ibuf, with image source and type */ if(ima->source==IMA_SRC_MOVIE) { - /* source is from single file, use flipbook to store ibuf */ - int frame= iuser?iuser->framenr:ima->lastframe; - + frame= iuser?iuser->framenr:ima->lastframe; ibuf= image_get_ibuf(ima, 0, frame); - if(ibuf==NULL) - ibuf= image_load_movie_file(ima, iuser, frame); } else if(ima->source==IMA_SRC_SEQUENCE) { - if(ima->type==IMA_TYPE_IMAGE) { - /* regular files, ibufs in flipbook, allows saving */ - int frame= iuser?iuser->framenr:ima->lastframe; - + frame= iuser?iuser->framenr:ima->lastframe; ibuf= image_get_ibuf(ima, 0, frame); - if(ibuf==NULL) - ibuf= image_load_sequence_file(ima, iuser, frame); - else - BLI_strncpy(ima->name, ibuf->name, sizeof(ima->name)); } - /* no else; on load the ima type can change */ - if(ima->type==IMA_TYPE_MULTILAYER) { - /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */ - int frame= iuser?iuser->framenr:ima->lastframe; - int index= iuser?iuser->multi_index:IMA_NO_INDEX; - + else if(ima->type==IMA_TYPE_MULTILAYER) { + frame= iuser?iuser->framenr:ima->lastframe; + index= iuser?iuser->multi_index:IMA_NO_INDEX; ibuf= image_get_ibuf(ima, index, frame); - if(G.rt) printf("seq multi fra %d id %d ibuf %p %s\n", frame, index, ibuf, ima->id.name); - if(ibuf==NULL) - ibuf= image_load_sequence_multilayer(ima, iuser, frame); - else - BLI_strncpy(ima->name, ibuf->name, sizeof(ima->name)); } - } else if(ima->source==IMA_SRC_FILE) { - - if(ima->type==IMA_TYPE_IMAGE) { + if(ima->type==IMA_TYPE_IMAGE) ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); - if(ibuf==NULL) - ibuf= image_load_image_file(ima, iuser, G.scene->r.cfra); /* cfra only for '#', this global is OK */ - } - /* no else; on load the ima type can change */ - if(ima->type==IMA_TYPE_MULTILAYER) { - /* keeps render result, stores ibufs in listbase, allows saving */ + else if(ima->type==IMA_TYPE_MULTILAYER) ibuf= image_get_ibuf(ima, iuser?iuser->multi_index:IMA_NO_INDEX, 0); - if(ibuf==NULL) - ibuf= image_get_ibuf_multilayer(ima, iuser); - } - } else if(ima->source == IMA_SRC_GENERATED) { - /* generated is: ibuf is allocated dynamically */ ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); - - if(ibuf==NULL) { - if(ima->type==IMA_TYPE_VERSE) { - /* todo */ - } - else { /* always fall back to IMA_TYPE_UV_TEST */ - /* UV testgrid or black or solid etc */ - if(ima->gen_x==0) ima->gen_x= 256; - if(ima->gen_y==0) ima->gen_y= 256; - ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 0, ima->gen_type, color); - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); - ima->ok= IMA_OK_LOADED; - } - } } else if(ima->source == IMA_SRC_VIEWER) { if(ima->type==IMA_TYPE_R_RESULT) { - /* always verify entirely */ - ibuf= image_get_render_result(ima, iuser); + /* always verify entirely, not that this shouldn't happen + * during render anyway */ } else if(ima->type==IMA_TYPE_COMPOSITE) { - int frame= iuser?iuser->framenr:0; - - /* Composite Viewer, all handled in compositor */ + frame= iuser?iuser->framenr:0; ibuf= image_get_ibuf(ima, 0, frame); - if(ibuf==NULL) { - /* fake ibuf, will be filled in compositor */ - ibuf= IMB_allocImBuf(256, 256, 32, IB_rect, 0); - image_assign_ibuf(ima, ibuf, 0, frame); + } + } + + *frame_r = frame; + *index_r = index; + + return ibuf; +} + +/* Checks optional ImageUser and verifies/creates ImBuf. */ +/* returns ibuf */ +ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser) +{ + ImBuf *ibuf= NULL; + float color[] = {0, 0, 0, 1}; + int frame= 0, index= 0; + + /* This function is intended to be thread-safe. It postpones the mutex lock + * until it needs to load the image, if the image is already there it + * should just get the pointer and return. The reason is that a lot of mutex + * locks appears to be very slow on certain multicore macs, causing a render + * with image textures to actually slow down as more threads are used. + * + * Note that all the image loading functions should also make sure they do + * things in a threadsafe way for image_get_ibuf_threadsafe to work correct. + * That means, the last two steps must be, 1) add the ibuf to the list and + * 2) set ima/iuser->ok to 0 to IMA_OK_LOADED */ + + /* quick reject tests */ + if(ima==NULL) + return NULL; + if(iuser) { + if(iuser->ok==0) + return NULL; + } + else if(ima->ok==0) + return NULL; + + /* try to get the ibuf without locking */ + ibuf= image_get_ibuf_threadsafe(ima, iuser, &frame, &index); + + if(ibuf == NULL) { + /* couldn't get ibuf and image is not ok, so let's lock and try to + * load the image */ + BLI_lock_thread(LOCK_IMAGE); + + /* need to check ok flag and loading ibuf again, because the situation + * might have changed in the meantime */ + if(iuser) { + if(iuser->ok==0) { + BLI_unlock_thread(LOCK_IMAGE); + return NULL; + } + } + else if(ima->ok==0) { + BLI_unlock_thread(LOCK_IMAGE); + return NULL; + } + + ibuf= image_get_ibuf_threadsafe(ima, iuser, &frame, &index); + + if(ibuf == NULL) { + /* we are sure we have to load the ibuf, using source and type */ + if(ima->source==IMA_SRC_MOVIE) { + /* source is from single file, use flipbook to store ibuf */ + ibuf= image_load_movie_file(ima, iuser, frame); + } + else if(ima->source==IMA_SRC_SEQUENCE) { + if(ima->type==IMA_TYPE_IMAGE) { + /* regular files, ibufs in flipbook, allows saving */ + ibuf= image_load_sequence_file(ima, iuser, frame); + } + /* no else; on load the ima type can change */ + if(ima->type==IMA_TYPE_MULTILAYER) { + /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */ + ibuf= image_load_sequence_multilayer(ima, iuser, frame); + } + + if(ibuf) + BLI_strncpy(ima->name, ibuf->name, sizeof(ima->name)); + } + else if(ima->source==IMA_SRC_FILE) { + + if(ima->type==IMA_TYPE_IMAGE) + ibuf= image_load_image_file(ima, iuser, G.scene->r.cfra); /* cfra only for '#', this global is OK */ + /* no else; on load the ima type can change */ + if(ima->type==IMA_TYPE_MULTILAYER) + /* keeps render result, stores ibufs in listbase, allows saving */ + ibuf= image_get_ibuf_multilayer(ima, iuser); + + } + else if(ima->source == IMA_SRC_GENERATED) { + /* generated is: ibuf is allocated dynamically */ + if(ima->type==IMA_TYPE_VERSE) { + /* todo */ + } + else { /* always fall back to IMA_TYPE_UV_TEST */ + /* UV testgrid or black or solid etc */ + if(ima->gen_x==0) ima->gen_x= 256; + if(ima->gen_y==0) ima->gen_y= 256; + ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 0, ima->gen_type, color); + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + ima->ok= IMA_OK_LOADED; + } + } + else if(ima->source == IMA_SRC_VIEWER) { + if(ima->type==IMA_TYPE_R_RESULT) { + /* always verify entirely */ + ibuf= image_get_render_result(ima, iuser); + } + else if(ima->type==IMA_TYPE_COMPOSITE) { + /* Composite Viewer, all handled in compositor */ + /* fake ibuf, will be filled in compositor */ + ibuf= IMB_allocImBuf(256, 256, 32, IB_rect, 0); + image_assign_ibuf(ima, ibuf, 0, frame); + } } } + + BLI_unlock_thread(LOCK_IMAGE); } + /* we assuming that if it is not rendering, it's also not multithreaded + * (a somewhat weak assumption) */ if(G.rendering==0) tag_image_time(ima); - BLI_unlock_thread(LOCK_IMAGE); - return ibuf; } diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index cda56f5b601..808984aaa3c 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1,15 +1,12 @@ /* implicit.c * * -* ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +* ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. The Blender -* Foundation also sells licenses for use in proprietary software under -* the Blender License. See http://www.blender.org/BL/ for information -* about this. +* of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,40 +24,20 @@ * * Contributor(s): none yet. * -* ***** END GPL/BL DUAL LICENSE BLOCK ***** +* ***** END GPL LICENSE BLOCK ***** */ -#include <math.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> + #include "MEM_guardedalloc.h" -/* types */ -#include "DNA_curve_types.h" -#include "DNA_object_types.h" -#include "DNA_object_force.h" + +#include "BKE_cloth.h" + #include "DNA_cloth_types.h" -#include "DNA_key_types.h" -#include "DNA_mesh_types.h" -#include "DNA_modifier_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_lattice_types.h" #include "DNA_scene_types.h" -#include "DNA_modifier_types.h" -#include "BLI_blenlib.h" -#include "BLI_arithb.h" -#include "BLI_threads.h" -#include "BKE_curve.h" -#include "BKE_displist.h" + #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_key.h" -#include "BKE_object.h" #include "BKE_cloth.h" -#include "BKE_modifier.h" #include "BKE_utildefines.h" -#include "BKE_global.h" -#include "BIF_editdeform.h" - #ifdef _WIN32 #include <windows.h> @@ -109,6 +86,10 @@ double itval() return t2-t1; } #endif + +static float I[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; +static float ZERO[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}}; + /* #define C99 #ifdef C99 @@ -126,7 +107,7 @@ struct Cloth; /* DEFINITIONS */ typedef float lfVector[3]; typedef struct fmatrix3x3 { - float m[3][3]; /* 4x4 matrix */ + float m[3][3]; /* 3x3 matrix */ unsigned int c,r; /* column and row number */ int pinned; /* is this vertex allowed to move? */ float n1,n2,n3; /* three normal vectors for collision constrains */ @@ -164,12 +145,15 @@ DO_INLINE void mul_fvectorT_fvector(float to[3][3], float vectorA[3], float vect /* simple v^T * v product with scalar ("outer product") */ /* STATUS: HAS TO BE verified (*should* work) */ DO_INLINE void mul_fvectorT_fvectorS(float to[3][3], float vectorA[3], float vectorB[3], float aS) -{ - mul_fvector_S(to[0], vectorB, vectorA[0]* aS); - mul_fvector_S(to[1], vectorB, vectorA[1]* aS); - mul_fvector_S(to[2], vectorB, vectorA[2]* aS); +{ + mul_fvectorT_fvector(to, vectorA, vectorB); + + mul_fvector_S(to[0], to[0], aS); + mul_fvector_S(to[1], to[1], aS); + mul_fvector_S(to[2], to[2], aS); } + /* printf vector[3] on console: for debug output */ void print_fvector(float m3[3]) { @@ -246,11 +230,11 @@ DO_INLINE void submul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float s /* dot product for big vector */ DO_INLINE float dot_lfvector(float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts) { - unsigned int i = 0; + long i = 0; float temp = 0.0; // schedule(guided, 2) #pragma omp parallel for reduction(+: temp) - for(i = 0; i < verts; i++) + for(i = 0; i < (long)verts; i++) { temp += INPR(fLongVectorA[i], fLongVectorB[i]); } @@ -310,16 +294,17 @@ DO_INLINE void sub_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], f } /////////////////////////// -// 4x4 matrix +// 3x3 matrix /////////////////////////// -/* printf 4x4 matrix on console: for debug output */ +/* printf 3x3 matrix on console: for debug output */ void print_fmatrix(float m3[3][3]) { printf("%f\t%f\t%f\n",m3[0][0],m3[0][1],m3[0][2]); printf("%f\t%f\t%f\n",m3[1][0],m3[1][1],m3[1][2]); printf("%f\t%f\t%f\n\n",m3[2][0],m3[2][1],m3[2][2]); } -/* copy 4x4 matrix */ + +/* copy 3x3 matrix */ DO_INLINE void cp_fmatrix(float to[3][3], float from[3][3]) { // memcpy(to, from, sizeof (float) * 9); @@ -327,12 +312,24 @@ DO_INLINE void cp_fmatrix(float to[3][3], float from[3][3]) VECCOPY(to[1], from[1]); VECCOPY(to[2], from[2]); } -/* calculate determinant of 4x4 matrix */ + +/* copy 3x3 matrix */ +DO_INLINE void initdiag_fmatrixS(float to[3][3], float aS) +{ + cp_fmatrix(to, ZERO); + + to[0][0] = aS; + to[1][1] = aS; + to[2][2] = aS; +} + +/* calculate determinant of 3x3 matrix */ DO_INLINE float det_fmatrix(float m[3][3]) { return m[0][0]*m[1][1]*m[2][2] + m[1][0]*m[2][1]*m[0][2] + m[0][1]*m[1][2]*m[2][0] -m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2] - m[2][0]*m[1][1]*m[0][2]; } + DO_INLINE void inverse_fmatrix(float to[3][3], float from[3][3]) { unsigned int i, j; @@ -364,7 +361,7 @@ DO_INLINE void inverse_fmatrix(float to[3][3], float from[3][3]) } -/* 4x4 matrix multiplied by a scalar */ +/* 3x3 matrix multiplied by a scalar */ /* STATUS: verified */ DO_INLINE void mul_fmatrix_S(float matrix[3][3], float scalar) { @@ -373,7 +370,7 @@ DO_INLINE void mul_fmatrix_S(float matrix[3][3], float scalar) mul_fvector_S(matrix[2], matrix[2],scalar); } -/* a vector multiplied by a 4x4 matrix */ +/* a vector multiplied by a 3x3 matrix */ /* STATUS: verified */ DO_INLINE void mul_fvector_fmatrix(float *to, float *from, float matrix[3][3]) { @@ -382,7 +379,7 @@ DO_INLINE void mul_fvector_fmatrix(float *to, float *from, float matrix[3][3]) to[2] = matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2]; } -/* 4x4 matrix multiplied by a vector */ +/* 3x3 matrix multiplied by a vector */ /* STATUS: verified */ DO_INLINE void mul_fmatrix_fvector(float *to, float matrix[3][3], float *from) { @@ -390,7 +387,7 @@ DO_INLINE void mul_fmatrix_fvector(float *to, float matrix[3][3], float *from) to[1] = INPR(matrix[1],from); to[2] = INPR(matrix[2],from); } -/* 4x4 matrix multiplied by a 4x4 matrix */ +/* 3x3 matrix multiplied by a 3x3 matrix */ /* STATUS: verified */ DO_INLINE void mul_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { @@ -398,49 +395,49 @@ DO_INLINE void mul_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float ma mul_fvector_fmatrix(to[1], matrixA[1],matrixB); mul_fvector_fmatrix(to[2], matrixA[2],matrixB); } -/* 4x4 matrix addition with 4x4 matrix */ +/* 3x3 matrix addition with 3x3 matrix */ DO_INLINE void add_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { VECADD(to[0], matrixA[0], matrixB[0]); VECADD(to[1], matrixA[1], matrixB[1]); VECADD(to[2], matrixA[2], matrixB[2]); } -/* 4x4 matrix add-addition with 4x4 matrix */ +/* 3x3 matrix add-addition with 3x3 matrix */ DO_INLINE void addadd_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { VECADDADD(to[0], matrixA[0], matrixB[0]); VECADDADD(to[1], matrixA[1], matrixB[1]); VECADDADD(to[2], matrixA[2], matrixB[2]); } -/* 4x4 matrix sub-addition with 4x4 matrix */ +/* 3x3 matrix sub-addition with 3x3 matrix */ DO_INLINE void addsub_fmatrixS_fmatrixS(float to[3][3], float matrixA[3][3], float aS, float matrixB[3][3], float bS) { VECADDSUBSS(to[0], matrixA[0], aS, matrixB[0], bS); VECADDSUBSS(to[1], matrixA[1], aS, matrixB[1], bS); VECADDSUBSS(to[2], matrixA[2], aS, matrixB[2], bS); } -/* A -= B + C (4x4 matrix sub-addition with 4x4 matrix) */ +/* A -= B + C (3x3 matrix sub-addition with 3x3 matrix) */ DO_INLINE void subadd_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { VECSUBADD(to[0], matrixA[0], matrixB[0]); VECSUBADD(to[1], matrixA[1], matrixB[1]); VECSUBADD(to[2], matrixA[2], matrixB[2]); } -/* A -= B*x + C*y (4x4 matrix sub-addition with 4x4 matrix) */ +/* A -= B*x + C*y (3x3 matrix sub-addition with 3x3 matrix) */ DO_INLINE void subadd_fmatrixS_fmatrixS(float to[3][3], float matrixA[3][3], float aS, float matrixB[3][3], float bS) { VECSUBADDSS(to[0], matrixA[0], aS, matrixB[0], bS); VECSUBADDSS(to[1], matrixA[1], aS, matrixB[1], bS); VECSUBADDSS(to[2], matrixA[2], aS, matrixB[2], bS); } -/* A = B - C (4x4 matrix subtraction with 4x4 matrix) */ +/* A = B - C (3x3 matrix subtraction with 3x3 matrix) */ DO_INLINE void sub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { VECSUB(to[0], matrixA[0], matrixB[0]); VECSUB(to[1], matrixA[1], matrixB[1]); VECSUB(to[2], matrixA[2], matrixB[2]); } -/* A += B - C (4x4 matrix add-subtraction with 4x4 matrix) */ +/* A += B - C (3x3 matrix add-subtraction with 3x3 matrix) */ DO_INLINE void addsub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { VECADDSUB(to[0], matrixA[0], matrixB[0]); @@ -450,35 +447,35 @@ DO_INLINE void addsub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float ///////////////////////////////////////////////////////////////// // special functions ///////////////////////////////////////////////////////////////// -/* a vector multiplied and added to/by a 4x4 matrix */ +/* a vector multiplied and added to/by a 3x3 matrix */ DO_INLINE void muladd_fvector_fmatrix(float to[3], float from[3], float matrix[3][3]) { to[0] += matrix[0][0]*from[0] + matrix[1][0]*from[1] + matrix[2][0]*from[2]; to[1] += matrix[0][1]*from[0] + matrix[1][1]*from[1] + matrix[2][1]*from[2]; to[2] += matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2]; } -/* 4x4 matrix multiplied and added to/by a 4x4 matrix and added to another 4x4 matrix */ +/* 3x3 matrix multiplied and added to/by a 3x3 matrix and added to another 3x3 matrix */ DO_INLINE void muladd_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { muladd_fvector_fmatrix(to[0], matrixA[0],matrixB); muladd_fvector_fmatrix(to[1], matrixA[1],matrixB); muladd_fvector_fmatrix(to[2], matrixA[2],matrixB); } -/* a vector multiplied and sub'd to/by a 4x4 matrix */ +/* a vector multiplied and sub'd to/by a 3x3 matrix */ DO_INLINE void mulsub_fvector_fmatrix(float to[3], float from[3], float matrix[3][3]) { to[0] -= matrix[0][0]*from[0] + matrix[1][0]*from[1] + matrix[2][0]*from[2]; to[1] -= matrix[0][1]*from[0] + matrix[1][1]*from[1] + matrix[2][1]*from[2]; to[2] -= matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2]; } -/* 4x4 matrix multiplied and sub'd to/by a 4x4 matrix and added to another 4x4 matrix */ +/* 3x3 matrix multiplied and sub'd to/by a 3x3 matrix and added to another 3x3 matrix */ DO_INLINE void mulsub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3]) { mulsub_fvector_fmatrix(to[0], matrixA[0],matrixB); mulsub_fvector_fmatrix(to[1], matrixA[1],matrixB); mulsub_fvector_fmatrix(to[2], matrixA[2],matrixB); } -/* 4x4 matrix multiplied+added by a vector */ +/* 3x3 matrix multiplied+added by a vector */ /* STATUS: verified */ DO_INLINE void muladd_fmatrix_fvector(float to[3], float matrix[3][3], float from[3]) { @@ -486,7 +483,7 @@ DO_INLINE void muladd_fmatrix_fvector(float to[3], float matrix[3][3], float fro to[1] += INPR(matrix[1],from); to[2] += INPR(matrix[2],from); } -/* 4x4 matrix multiplied+sub'ed by a vector */ +/* 3x3 matrix multiplied+sub'ed by a vector */ DO_INLINE void mulsub_fmatrix_fvector(float to[3], float matrix[3][3], float from[3]) { to[0] -= INPR(matrix[0],from); @@ -496,7 +493,7 @@ DO_INLINE void mulsub_fmatrix_fvector(float to[3], float matrix[3][3], float fro ///////////////////////////////////////////////////////////////// /////////////////////////// -// SPARSE SYMMETRIC big matrix with 4x4 matrix entries +// SPARSE SYMMETRIC big matrix with 3x3 matrix entries /////////////////////////// /* printf a big matrix on console: for debug output */ void print_bfmatrix(fmatrix3x3 *m3) @@ -525,12 +522,26 @@ DO_INLINE void del_bfmatrix(fmatrix3x3 *matrix) MEM_freeN (matrix); } } + /* copy big matrix */ DO_INLINE void cp_bfmatrix(fmatrix3x3 *to, fmatrix3x3 *from) { // TODO bounds checking memcpy(to, from, sizeof(fmatrix3x3) * (from[0].vcount+from[0].scount) ); } + +/* init big matrix */ +// slow in parallel +DO_INLINE void init_bfmatrix(fmatrix3x3 *matrix, float m3[3][3]) +{ + unsigned int i; + + for(i = 0; i < matrix[0].vcount+matrix[0].scount; i++) + { + cp_fmatrix(matrix[i].m, m3); + } +} + /* init the diagonal of big matrix */ // slow in parallel DO_INLINE void initdiag_bfmatrix(fmatrix3x3 *matrix, float m3[3][3]) @@ -547,16 +558,7 @@ DO_INLINE void initdiag_bfmatrix(fmatrix3x3 *matrix, float m3[3][3]) cp_fmatrix(matrix[j].m, tmatrix); } } -/* init big matrix */ -DO_INLINE void init_bfmatrix(fmatrix3x3 *matrix, float m3[3][3]) -{ - unsigned int i; - for(i = 0; i < matrix[0].vcount+matrix[0].scount; i++) - { - cp_fmatrix(matrix[i].m, m3); - } -} /* multiply big matrix with scalar*/ DO_INLINE void mul_bfmatrix_S(fmatrix3x3 *matrix, float scalar) { @@ -702,12 +704,10 @@ DO_INLINE void subadd_bfmatrixS_bfmatrixS( fmatrix3x3 *to, fmatrix3x3 *from, flo /////////////////////////////////////////////////////////////////// // simulator start /////////////////////////////////////////////////////////////////// -static float I[3][3] = {{1,0,0},{0,1,0},{0,0,1}}; -static float ZERO[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}}; typedef struct Implicit_Data { lfVector *X, *V, *Xnew, *Vnew, *olddV, *F, *B, *dV, *z; - fmatrix3x3 *A, *dFdV, *dFdX, *S, *P, *Pinv, *bigI; + fmatrix3x3 *A, *dFdV, *dFdX, *S, *P, *Pinv, *bigI, *M; } Implicit_Data; int implicit_init (Object *ob, ClothModifierData *clmd) @@ -721,7 +721,7 @@ int implicit_init (Object *ob, ClothModifierData *clmd) LinkNode *search = NULL; if(G.rt > 0) - printf("implicit_init\n"); + printf("implicit_init\n"); // init memory guard // MEMORY_BASE.first = MEMORY_BASE.last = NULL; @@ -741,6 +741,7 @@ int implicit_init (Object *ob, ClothModifierData *clmd) id->Pinv = create_bfmatrix(cloth->numverts, cloth->numsprings); id->P = create_bfmatrix(cloth->numverts, cloth->numsprings); id->bigI = create_bfmatrix(cloth->numverts, cloth->numsprings); // TODO 0 springs + id->M = create_bfmatrix(cloth->numverts, cloth->numsprings); id->X = create_lfvector(cloth->numverts); id->Xnew = create_lfvector(cloth->numverts); id->V = create_lfvector(cloth->numverts); @@ -754,20 +755,22 @@ int implicit_init (Object *ob, ClothModifierData *clmd) for(i=0;i<cloth->numverts;i++) { - id->A[i].r = id->A[i].c = id->dFdV[i].r = id->dFdV[i].c = id->dFdX[i].r = id->dFdX[i].c = id->P[i].c = id->P[i].r = id->Pinv[i].c = id->Pinv[i].r = id->bigI[i].c = id->bigI[i].r = i; + id->A[i].r = id->A[i].c = id->dFdV[i].r = id->dFdV[i].c = id->dFdX[i].r = id->dFdX[i].c = id->P[i].c = id->P[i].r = id->Pinv[i].c = id->Pinv[i].r = id->bigI[i].c = id->bigI[i].r = id->M[i].r = id->M[i].c = i; - if(verts [i].goal >= SOFTGOALSNAP) + if(verts [i].flags & CLOTH_VERT_FLAG_PINNED) { id->S[pinned].pinned = 1; id->S[pinned].c = id->S[pinned].r = i; pinned++; } + + initdiag_fmatrixS(id->M[i].m, verts[i].mass); } // S is special and needs specific vcount and scount id->S[0].vcount = pinned; id->S[0].scount = 0; - // init springs */ + // init springs search = cloth->springs; for(i=0;i<cloth->numsprings;i++) { @@ -775,16 +778,18 @@ int implicit_init (Object *ob, ClothModifierData *clmd) // dFdV_start[i].r = big_I[i].r = big_zero[i].r = id->A[i+cloth->numverts].r = id->dFdV[i+cloth->numverts].r = id->dFdX[i+cloth->numverts].r = - id->P[i+cloth->numverts].r = id->Pinv[i+cloth->numverts].r = id->bigI[i+cloth->numverts].r = spring->ij; + id->P[i+cloth->numverts].r = id->Pinv[i+cloth->numverts].r = id->bigI[i+cloth->numverts].r = id->M[i+cloth->numverts].r = spring->ij; // dFdV_start[i].c = big_I[i].c = big_zero[i].c = id->A[i+cloth->numverts].c = id->dFdV[i+cloth->numverts].c = id->dFdX[i+cloth->numverts].c = - id->P[i+cloth->numverts].c = id->Pinv[i+cloth->numverts].c = id->bigI[i+cloth->numverts].c = spring->kl; + id->P[i+cloth->numverts].c = id->Pinv[i+cloth->numverts].c = id->bigI[i+cloth->numverts].c = id->M[i+cloth->numverts].c = spring->kl; spring->matrix_index = i + cloth->numverts; search = search->next; } + + initdiag_bfmatrix(id->bigI, I); for(i = 0; i < cloth->numverts; i++) { @@ -812,6 +817,7 @@ int implicit_free (ClothModifierData *clmd) del_bfmatrix(id->P); del_bfmatrix(id->Pinv); del_bfmatrix(id->bigI); + del_bfmatrix(id->M); del_lfvector(id->X); del_lfvector(id->Xnew); @@ -848,7 +854,7 @@ DO_INLINE float fbstar(float length, float L, float kb, float cb) float tempfb = kb * fb(length, L); float fbstar = cb * (length - L); - + if(tempfb < fbstar) return fbstar; else @@ -962,7 +968,7 @@ DO_INLINE void BuildPPinv(fmatrix3x3 *lA, fmatrix3x3 *P, fmatrix3x3 *Pinv) } } - +/* // version 1.3 int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv) { @@ -1030,21 +1036,135 @@ int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fma return iterations<conjgrad_looplimit; } +*/ +// version 1.4 +int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *bigI) +{ + unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100; + float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0, tol = 0; + lfVector *r = create_lfvector(numverts); + lfVector *p = create_lfvector(numverts); + lfVector *s = create_lfvector(numverts); + lfVector *h = create_lfvector(numverts); + lfVector *bhat = create_lfvector(numverts); + lfVector *btemp = create_lfvector(numverts); + + BuildPPinv(lA, P, Pinv); + + initdiag_bfmatrix(bigI, I); + sub_bfmatrix_Smatrix(bigI, bigI, S); + + // x = Sx_0+(I-S)z + filter(dv, S); + add_lfvector_lfvector(dv, dv, z, numverts); + + // b_hat = S(b-A(I-S)z) + mul_bfmatrix_lfvector(r, lA, z); + mul_bfmatrix_lfvector(bhat, bigI, r); + sub_lfvector_lfvector(bhat, lB, bhat, numverts); + + // r = S(b-Ax) + mul_bfmatrix_lfvector(r, lA, dv); + sub_lfvector_lfvector(r, lB, r, numverts); + filter(r, S); + + // p = SP^-1r + mul_prevfmatrix_lfvector(p, Pinv, r); + filter(p, S); + + // delta0 = bhat^TP^-1bhat + mul_prevfmatrix_lfvector(btemp, Pinv, bhat); + delta0 = dot_lfvector(bhat, btemp, numverts); + + // deltaNew = r^TP + deltaNew = dot_lfvector(r, p, numverts); + + /* + filter(dv, S); + add_lfvector_lfvector(dv, dv, z, numverts); + + mul_bfmatrix_lfvector(r, lA, dv); + sub_lfvector_lfvector(r, lB, r, numverts); + filter(r, S); + + mul_prevfmatrix_lfvector(p, Pinv, r); + filter(p, S); + + deltaNew = dot_lfvector(r, p, numverts); + + delta0 = deltaNew * sqrt(conjgrad_epsilon); + */ + + // itstart(); + + tol = (0.01*0.2); + + while ((deltaNew > delta0*tol*tol) && (iterations < conjgrad_looplimit)) + { + iterations++; + + mul_bfmatrix_lfvector(s, lA, p); + filter(s, S); + + alpha = deltaNew / dot_lfvector(p, s, numverts); + + add_lfvector_lfvectorS(dv, dv, p, alpha, numverts); + + add_lfvector_lfvectorS(r, r, s, -alpha, numverts); + + mul_prevfmatrix_lfvector(h, Pinv, r); + filter(h, S); + + deltaOld = deltaNew; + + deltaNew = dot_lfvector(r, h, numverts); + + add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts); + + filter(p, S); + + } + + // itend(); + // printf("cg_filtered_pre time: %f\n", (float)itval()); + + del_lfvector(btemp); + del_lfvector(bhat); + del_lfvector(h); + del_lfvector(s); + del_lfvector(p); + del_lfvector(r); + + // printf("iterations: %d\n", iterations); + + return iterations<conjgrad_looplimit; +} // outer product is NOT cross product!!! -DO_INLINE void dfdx_spring_type1(float to[3][3], float dir[3],float length,float L,float k) +DO_INLINE void dfdx_spring_type1(float to[3][3], float extent[3], float length, float L, float dot, float k) { // dir is unit length direction, rest is spring's restlength, k is spring constant. // return (outerprod(dir,dir)*k + (I - outerprod(dir,dir))*(k - ((k*L)/length))); float temp[3][3]; + float temp1 = k*(1.0 - (L/length)); + + mul_fvectorT_fvectorS(temp, extent, extent, 1.0 / dot); + sub_fmatrix_fmatrix(to, I, temp); + mul_fmatrix_S(to, temp1); + + mul_fvectorT_fvectorS(temp, extent, extent, k/ dot); + add_fmatrix_fmatrix(to, to, temp); + + /* mul_fvectorT_fvector(temp, dir, dir); sub_fmatrix_fmatrix(to, I, temp); mul_fmatrix_S(to, k* (1.0f-(L/length))); mul_fmatrix_S(temp, k); add_fmatrix_fmatrix(to, temp, to); + */ } -DO_INLINE void dfdx_spring_type2(float to[3][3], float dir[3],float length,float L,float k, float cb) +DO_INLINE void dfdx_spring_type2(float to[3][3], float dir[3], float length, float L, float k, float cb) { // return outerprod(dir,dir)*fbstar_jacobi(length, L, k, cb); mul_fvectorT_fvectorS(to, dir, dir, fbstar_jacobi(length, L, k, cb)); @@ -1053,8 +1173,8 @@ DO_INLINE void dfdx_spring_type2(float to[3][3], float dir[3],float length,float DO_INLINE void dfdv_damp(float to[3][3], float dir[3], float damping) { // derivative of force wrt velocity. - // return outerprod(dir,dir) * damping; mul_fvectorT_fvectorS(to, dir, dir, damping); + } DO_INLINE void dfdx_spring(float to[3][3], float dir[3],float length,float L,float k) @@ -1068,6 +1188,7 @@ DO_INLINE void dfdx_spring(float to[3][3], float dir[3],float length,float L,fl mul_fmatrix_S(to, -k); } +// unused atm DO_INLINE void dfdx_damp(float to[3][3], float dir[3],float length,const float vel[3],float rest,float damping) { // inner spring damping vel is the relative velocity of the endpoints. @@ -1078,10 +1199,12 @@ DO_INLINE void dfdx_damp(float to[3][3], float dir[3],float length,const float } -DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, lfVector *lF, lfVector *X, lfVector *V, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX) +DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, lfVector *lF, lfVector *X, lfVector *V, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float time) { + Cloth *cloth = clmd->clothObject; + ClothVertex *verts = cloth->verts; float extent[3]; - float length = 0; + float length = 0, dot = 0; float dir[3] = {0,0,0}; float vel[3]; float k = 0.0f; @@ -1103,11 +1226,12 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, // calculate elonglation VECSUB(extent, X[s->kl], X[s->ij]); VECSUB(vel, V[s->kl], V[s->ij]); - length = sqrt(INPR(extent, extent)); + dot = INPR(extent, extent); + length = sqrt(dot); s->flags &= ~CLOTH_SPRING_FLAG_NEEDED; - if(length > ABS(ALMOST_ZERO)) + if(length > ALMOST_ZERO) { /* if(length>L) @@ -1128,7 +1252,7 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, } // calculate force of structural + shear springs - if(s->type != CLOTH_SPRING_TYPE_BENDING) + if((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR)) { if(length > L) // only on elonglation { @@ -1137,31 +1261,58 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, k = clmd->sim_parms->structural; scaling = k + s->stiffness * ABS(clmd->sim_parms->max_struct-k); - k = scaling; - // printf("scaling: %f, stiffness: %f\n", k, s->stiffness); - /* - if((s->ij == 109) || (s->kl == 109)) - { - printf("length-L: %f, f: %f, len: %f, L: %f\n", length-L, (k*(length-L)), length, L); - printf("kl X-x: %f, f-y: %f, f-z: %f\n", X[s->kl][0], X[s->kl][1], X[s->kl][2]); - printf("ij X-x: %f, f-y: %f, f-z: %f\n\n", X[s->ij][0], X[s->ij][1], X[s->ij][2]); - } - */ - - mul_fvector_S(stretch_force, dir, (k*(length-L))); + k = scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON); + + // TODO: verify, half verified (couldn't see error) + mul_fvector_S(stretch_force, dir, k*(length-L)); VECADD(s->f, s->f, stretch_force); // Ascher & Boxman, p.21: Damping only during elonglation - mul_fvector_S(damping_force, extent, clmd->sim_parms->Cdis * ((INPR(vel,extent)/length))); + // something wrong with it... + mul_fvector_S(damping_force, dir, clmd->sim_parms->Cdis * INPR(vel,dir)); VECADD(s->f, s->f, damping_force); - - dfdx_spring_type1(s->dfdx, dir,length,L,k); - - dfdv_damp(s->dfdv, dir,clmd->sim_parms->Cdis); + + /* VERIFIED */ + dfdx_spring(s->dfdx, dir, length, L, k); + + /* VERIFIED */ + dfdv_damp(s->dfdv, dir, clmd->sim_parms->Cdis); + } } + else if(s->type & CLOTH_SPRING_TYPE_GOAL) + { + float tvect[3]; + + s->flags |= CLOTH_SPRING_FLAG_NEEDED; + + // current_position = xold + t * (newposition - xold) + VECSUB(tvect, verts[s->ij].xconst, verts[s->ij].xold); + mul_fvector_S(tvect, tvect, time); + VECADD(tvect, tvect, verts[s->ij].xold); + + VECSUB(extent, X[s->ij], tvect); + + dot = INPR(extent, extent); + length = sqrt(dot); + + k = clmd->sim_parms->goalspring; + + scaling = k + s->stiffness * ABS(clmd->sim_parms->max_struct-k); + + k = verts [s->ij].goal * scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON); + + VECADDS(s->f, s->f, extent, -k); + + mul_fvector_S(damping_force, dir, clmd->sim_parms->goalfrict * 0.01 * INPR(vel,dir)); + VECADD(s->f, s->f, damping_force); + + // HERE IS THE PROBLEM!!!! + // dfdx_spring(s->dfdx, dir, length, 0.0, k); + // dfdv_damp(s->dfdv, dir, MIN2(1.0, (clmd->sim_parms->goalfrict/100.0))); + } else // calculate force of bending springs { if(length < L) @@ -1170,28 +1321,22 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, k = clmd->sim_parms->bending; - scaling = k + s->stiffness * ABS(clmd->sim_parms->max_bend-k); - cb = k = scaling; + scaling = k + s->stiffness * ABS(clmd->sim_parms->max_bend-k); + cb = k = scaling / (20.0*(clmd->sim_parms->avg_spring_len + FLT_EPSILON)); mul_fvector_S(bending_force, dir, fbstar(length, L, k, cb)); VECADD(s->f, s->f, bending_force); - dfdx_spring_type2(s->dfdx, dir,length,L,k, cb); + dfdx_spring_type2(s->dfdx, dir, length,L, k, cb); } } - /* - if((s->ij == 109) || (s->kl == 109)) - { - printf("type: %d, f-x: %f, f-y: %f, f-z: %f\n", s->type, s->f[0], s->f[1], s->f[2]); -} - */ } DO_INLINE void cloth_apply_spring_force(ClothModifierData *clmd, ClothSpring *s, lfVector *lF, lfVector *X, lfVector *V, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX) { if(s->flags & CLOTH_SPRING_FLAG_NEEDED) { - if(s->type != CLOTH_SPRING_TYPE_BENDING) + if(!(s->type & CLOTH_SPRING_TYPE_BENDING)) { sub_fmatrix_fmatrix(dFdV[s->ij].m, dFdV[s->ij].m, s->dfdv); sub_fmatrix_fmatrix(dFdV[s->kl].m, dFdV[s->kl].m, s->dfdv); @@ -1199,70 +1344,33 @@ DO_INLINE void cloth_apply_spring_force(ClothModifierData *clmd, ClothSpring *s, } VECADD(lF[s->ij], lF[s->ij], s->f); - VECSUB(lF[s->kl], lF[s->kl], s->f); - - sub_fmatrix_fmatrix(dFdX[s->ij].m, dFdX[s->ij].m, s->dfdx); + + if(!(s->type & CLOTH_SPRING_TYPE_GOAL)) + VECSUB(lF[s->kl], lF[s->kl], s->f); + sub_fmatrix_fmatrix(dFdX[s->kl].m, dFdX[s->kl].m, s->dfdx); - + sub_fmatrix_fmatrix(dFdX[s->ij].m, dFdX[s->ij].m, s->dfdx); add_fmatrix_fmatrix(dFdX[s->matrix_index].m, dFdX[s->matrix_index].m, s->dfdx); } } -DO_INLINE void calculateTriangleNormal(float to[3], lfVector *X, MFace mface) -{ - float v1[3], v2[3]; - - VECSUB(v1, X[mface.v2], X[mface.v1]); - VECSUB(v2, X[mface.v3], X[mface.v1]); - cross_fvector(to, v1, v2); -} - -DO_INLINE void calculatQuadNormal(float to[3], lfVector *X, MFace mface) -{ - float temp = CalcNormFloat4(X[mface.v1],X[mface.v2],X[mface.v3],X[mface.v4],to); - mul_fvector_S(to, to, temp); -} - -void calculateWeightedVertexNormal(ClothModifierData *clmd, MFace *mfaces, float to[3], int index, lfVector *X) -{ - float temp[3]; - int i; - Cloth *cloth = clmd->clothObject; - - for(i = 0; i < cloth->numfaces; i++) - { - // check if this triangle contains the selected vertex - if(mfaces[i].v1 == index || mfaces[i].v2 == index || mfaces[i].v3 == index || mfaces[i].v4 == index) - { - calculatQuadNormal(temp, X, mfaces[i]); - VECADD(to, to, temp); - } - } -} float calculateVertexWindForce(float wind[3], float vertexnormal[3]) { - return fabs(INPR(wind, vertexnormal) * 0.5f); + return fabs(INPR(wind, vertexnormal)); } -DO_INLINE void calc_triangle_force(ClothModifierData *clmd, MFace mface, lfVector *F, lfVector *X, lfVector *V, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors) -{ - -} - -void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time) +void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M) { /* Collect forces and derivatives: F,dFdX,dFdV */ Cloth *cloth = clmd->clothObject; - unsigned int i = 0; + long i = 0; float spring_air = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */ float gravity[3]; float tm2[3][3] = {{-spring_air,0,0}, {0,-spring_air,0},{0,0,-spring_air}}; - ClothVertex *verts = cloth->verts; MFace *mfaces = cloth->mfaces; + //ClothVertex *verts = cloth->verts; float wind_normalized[3]; unsigned int numverts = cloth->numverts; - float auxvect[3], velgoal[3], tvect[3]; - float kd, ks; LinkNode *search = cloth->springs; @@ -1275,58 +1383,85 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec initdiag_bfmatrix(dFdV, tm2); init_lfvector(lF, gravity, numverts); + + /* multiply lF with mass matrix + // force = mass * acceleration (in this case: gravity) + */ + for(i = 0; i < (long)numverts; i++) + { + float temp[3]; + VECCOPY(temp, lF[i]); + mul_fmatrix_fvector(lF[i], M[i].m, temp); + } submul_lfvectorS(lF, lV, spring_air, numverts); - - /* do goal stuff */ - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) - { - for(i = 0; i < numverts; i++) - { - if(verts [i].goal < SOFTGOALSNAP) - { - // current_position = xold + t * (newposition - xold) - VECSUB(tvect, verts[i].xconst, verts[i].xold); - mul_fvector_S(tvect, tvect, time); - VECADD(tvect, tvect, verts[i].xold); - - VECSUB(auxvect, tvect, lX[i]); - ks = 1.0f/(1.0f- verts [i].goal*clmd->sim_parms->goalspring)-1.0f ; - VECADDS(lF[i], lF[i], auxvect, -ks); - - // calulate damping forces generated by goals - - VECSUB(velgoal,verts[i].xold, verts[i].xconst); - kd = clmd->sim_parms->goalfrict * 0.01f; // friction force scale taken from SB - VECSUBADDSS(lF[i], velgoal, kd, lV[i], kd); - - - } - } - } /* handle external forces like wind */ if(effectors) - { - float speed[3] = {0.0f, 0.0f,0.0f}; - float force[3]= {0.0f, 0.0f, 0.0f}; - -#pragma omp parallel for private (i) shared(lF) - for(i = 0; i < cloth->numverts; i++) + { + for(i = 0; i < cloth->numfaces; i++) { float vertexnormal[3]={0,0,0}; - float fieldfactor = 1000.0f; // windfactor = 250.0f; // from sb + float speed[3] = {0.0f, 0.0f,0.0f}; + float force[3]= {0.0f, 0.0f, 0.0f}; - pdDoEffectors(effectors, lX[i], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + if(mfaces[i].v4) + CalcNormFloat4(lX[mfaces[i].v1],lX[mfaces[i].v2],lX[mfaces[i].v3],lX[mfaces[i].v4],vertexnormal); + else + CalcNormFloat(lX[mfaces[i].v1],lX[mfaces[i].v2],lX[mfaces[i].v3],vertexnormal); - // TODO apply forcefields here - VECADDS(lF[i], lF[i], force, fieldfactor*0.01f); - + pdDoEffectors(effectors, lX[mfaces[i].v1], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + VECCOPY(wind_normalized, speed); + Normalize(wind_normalized); + VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); + + if(mfaces[i].v4) + { + VECADDS(lF[mfaces[i].v1], lF[mfaces[i].v1], wind_normalized, 0.25); + } + else + { + VECADDS(lF[mfaces[i].v1], lF[mfaces[i].v1], wind_normalized, 1.0 / 3.0); + } + + speed[0] = speed[1] = speed[2] = 0.0; + pdDoEffectors(effectors, lX[mfaces[i].v2], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + VECCOPY(wind_normalized, speed); + Normalize(wind_normalized); + VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); + if(mfaces[i].v4) + { + VECADDS(lF[mfaces[i].v2], lF[mfaces[i].v2], wind_normalized, 0.25); + } + else + { + VECADDS(lF[mfaces[i].v2], lF[mfaces[i].v2], wind_normalized, 1.0 / 3.0); + } + + speed[0] = speed[1] = speed[2] = 0.0; + pdDoEffectors(effectors, lX[mfaces[i].v3], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); VECCOPY(wind_normalized, speed); Normalize(wind_normalized); + VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); + if(mfaces[i].v4) + { + VECADDS(lF[mfaces[i].v3], lF[mfaces[i].v3], wind_normalized, 0.25); + } + else + { + VECADDS(lF[mfaces[i].v3], lF[mfaces[i].v3], wind_normalized, 1.0 / 3.0); + } + + speed[0] = speed[1] = speed[2] = 0.0; + if(mfaces[i].v4) + { + pdDoEffectors(effectors, lX[mfaces[i].v4], force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + VECCOPY(wind_normalized, speed); + Normalize(wind_normalized); + VecMulf(wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); + VECADDS(lF[mfaces[i].v4], lF[mfaces[i].v4], wind_normalized, 0.25); + } - calculateWeightedVertexNormal(clmd, mfaces, vertexnormal, i, lX); - VECADDS(lF[i], lF[i], wind_normalized, -calculateVertexWindForce(speed, vertexnormal)); } } @@ -1336,7 +1471,7 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec { // only handle active springs // if(((clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED) && !(springs[i].flags & CSPRING_FLAG_DEACTIVATE))|| !(clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED)){} - cloth_calc_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX); + cloth_calc_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX, time); search = search->next; } @@ -1353,14 +1488,15 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec // printf("\n"); } -void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, lfVector *olddV, fmatrix3x3 *P, fmatrix3x3 *Pinv) +void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, lfVector *olddV, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *M, fmatrix3x3 *bigI) { unsigned int numverts = dFdV[0].vcount; lfVector *dFdXmV = create_lfvector(numverts); - initdiag_bfmatrix(A, I); zero_lfvector(dV, numverts); - + + cp_bfmatrix(A, M); + subadd_bfmatrixS_bfmatrixS(A, dFdV, dt, dFdX, (dt*dt)); mul_bfmatrix_lfvector(dFdXmV, dFdX, lV); @@ -1370,7 +1506,7 @@ void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVecto itstart(); cg_filtered(dV, A, B, z, S); /* conjugate gradient algorithm to solve Ax=b */ - // cg_filtered_pre(dV, A, B, z, olddV, P, Pinv, dt); + // cg_filtered_pre(dV, A, B, z, S, P, Pinv, bigI); itend(); // printf("cg_filtered calc time: %f\n", (float)itval()); @@ -1387,11 +1523,11 @@ void simulate_implicit_euler(lfVector *Vnew, lfVector *lX, lfVector *lV, lfVecto int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors) { unsigned int i=0; - float step=0.0f, tf=1.0f; + float step=0.0f, tf=clmd->sim_parms->timescale; Cloth *cloth = clmd->clothObject; ClothVertex *verts = cloth->verts; unsigned int numverts = cloth->numverts; - float dt = 1.0f / clmd->sim_parms->stepsPerFrame; + float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame; Implicit_Data *id = cloth->implicit; int result = 0; @@ -1400,35 +1536,44 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase for(i = 0; i < numverts; i++) { // update velocities with constrained velocities from pinned verts - if(verts [i].goal >= SOFTGOALSNAP) + if(verts [i].flags & CLOTH_VERT_FLAG_PINNED) { VECSUB(id->V[i], verts[i].xconst, verts[i].xold); - // VecMulf(id->V[i], 1.0 / dt); + // VecMulf(id->V[i], clmd->sim_parms->stepsPerFrame); } } } - + while(step < tf) - { + { + // calculate forces effectors= pdInitEffectors(ob,NULL); + cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step, id->M); + if(effectors) pdEndEffectors(effectors); - // calculate - cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step ); - - // printf("F -> x: %f, y: %f; z: %f\n\n", id->F[109][0], id->F[109][1], id->F[109][2]); - - simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv); + // calculate new velocity + simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI); + // advance positions add_lfvector_lfvectorS(id->Xnew, id->X, id->Vnew, dt, numverts); - /* - printf("dt: %f\n", dt); - printf("Xnew -> x: %f, y: %f; z: %f\n", id->Xnew[109][0], id->Xnew[109][1], id->Xnew[109][2]); - printf("X -> x: %f, y: %f; z: %f\n", id->X[109][0], id->X[109][1], id->X[109][2]); - printf("Vnew -> x: %f, y: %f; z: %f\n\n", id->Vnew[109][0], id->Vnew[109][1], id->Vnew[109][2]); - */ - - // clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_ENABLED; + /* move pinned verts to correct position */ + for(i = 0; i < numverts; i++) + { + if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) + { + if(verts [i].flags & CLOTH_VERT_FLAG_PINNED) + { + float tvect[3] = {.0,.0,.0}; + VECSUB(tvect, verts[i].xconst, verts[i].xold); + mul_fvector_S(tvect, tvect, step+dt); + VECADD(tvect, tvect, verts[i].xold); + VECCOPY(id->Xnew[i], tvect); + } + } + + VECCOPY(verts[i].txold, id->X[i]); + } if(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { @@ -1437,21 +1582,7 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase // update verts to current positions for(i = 0; i < numverts; i++) - { - - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) - { - if(verts [i].goal >= SOFTGOALSNAP) - { - float tvect[3] = {.0,.0,.0}; - // VECSUB(tvect, id->Xnew[i], verts[i].xold); - mul_fvector_S(tvect, id->V[i], step+dt); - VECADD(tvect, tvect, verts[i].xold); - VECCOPY(id->Xnew[i], tvect); - } - - } - + { VECCOPY(verts[i].tx, id->Xnew[i]); VECSUB(verts[i].tv, verts[i].tx, verts[i].txold); @@ -1467,27 +1598,12 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase if(result) { - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) - { - if(verts [i].goal >= SOFTGOALSNAP) - { - continue; - } - } - - - // VECADD(verts[i].tx, verts[i].txold, verts[i].tv); - - VECCOPY(verts[i].txold, verts[i].tx); + if((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED)) + continue; VECCOPY(id->Xnew[i], verts[i].tx); - VECCOPY(id->Vnew[i], verts[i].tv); - VecMulf(id->Vnew[i], 1.0f / dt); - } - else - { - VECCOPY(verts[i].txold, id->Xnew[i]); + VecMulf(id->Vnew[i], clmd->sim_parms->stepsPerFrame); } } @@ -1495,15 +1611,20 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase cp_lfvector(id->X, id->Xnew, numverts); // if there were collisions, advance the velocity from v_n+1/2 to v_n+1 + if(result) { // V = Vnew; cp_lfvector(id->V, id->Vnew, numverts); // calculate - cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step); - simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt / 2.0f, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv); + effectors= pdInitEffectors(ob,NULL); + cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step+dt, id->M); + if(effectors) pdEndEffectors(effectors); + + simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt / 2.0f, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI); } + } else { @@ -1516,28 +1637,18 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase // V = Vnew; cp_lfvector(id->V, id->Vnew, numverts); - + step += dt; - - if(effectors) pdEndEffectors(effectors); + } for(i = 0; i < numverts; i++) { - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) + if((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED)) { - if(verts [i].goal < SOFTGOALSNAP) - { - VECCOPY(verts[i].txold, id->X[i]); - VECCOPY(verts[i].x, id->X[i]); - VECCOPY(verts[i].v, id->V[i]); - } - else - { - VECCOPY(verts[i].txold, verts[i].xconst); - VECCOPY(verts[i].x, verts[i].xconst); - VECCOPY(verts[i].v, id->V[i]); - } + VECCOPY(verts[i].txold, verts[i].xconst); // TODO: test --> should be .x + VECCOPY(verts[i].x, verts[i].xconst); + VECCOPY(verts[i].v, id->V[i]); } else { @@ -1546,6 +1657,7 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase VECCOPY(verts[i].v, id->V[i]); } } + return 1; } @@ -1562,5 +1674,6 @@ void implicit_set_positions (ClothModifierData *clmd) VECCOPY(id->V[i], verts[i].v); } if(G.rt > 0) - printf("implicit_set_positions\n"); + printf("implicit_set_positions\n"); } + diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 4af310913d6..0b9f7615bfa 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -2,15 +2,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -28,7 +25,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> diff --git a/source/blender/blenkernel/intern/kdop.c b/source/blender/blenkernel/intern/kdop.c index 736ffcf0965..3189fe960ad 100644 --- a/source/blender/blenkernel/intern/kdop.c +++ b/source/blender/blenkernel/intern/kdop.c @@ -1,15 +1,12 @@ /* kdop.c * * -* ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** +* ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. The Blender -* Foundation also sells licenses for use in proprietary software under -* the Blender License. See http://www.blender.org/BL/ for information -* about this. +* of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,49 +24,29 @@ * * Contributor(s): none yet. * -* ***** END GPL/BL DUAL LICENSE BLOCK ***** +* ***** END GPL LICENSE BLOCK ***** */ -#include <math.h> -#include <stdlib.h> -#include <string.h> #include "MEM_guardedalloc.h" -/* types */ -#include "DNA_curve_types.h" -#include "DNA_object_types.h" -#include "DNA_object_force.h" -#include "DNA_cloth_types.h" -#include "DNA_key_types.h" + +#include "BKE_cloth.h" + +#include "DNA_cloth_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_lattice_types.h" #include "DNA_scene_types.h" -#include "DNA_modifier_types.h" -#include "BLI_blenlib.h" -#include "BLI_arithb.h" -#include "BLI_edgehash.h" -#include "BLI_linklist.h" -#include "BKE_curve.h" + #include "BKE_deform.h" #include "BKE_DerivedMesh.h" #include "BKE_cdderivedmesh.h" -#include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_global.h" -#include "BKE_key.h" -#include "BKE_mesh.h" #include "BKE_object.h" -#include "BKE_cloth.h" #include "BKE_modifier.h" #include "BKE_utildefines.h" -#include "BKE_DerivedMesh.h" -#include "BIF_editdeform.h" -#include "BIF_editkey.h" -#include "DNA_screen_types.h" -#include "BSE_headerbuttons.h" -#include "BIF_screen.h" -#include "BIF_space.h" -#include "mydevice.h" + +#ifdef _OPENMP +#include <omp.h> +#endif //////////////////////////////////////////////////////////////////////// @@ -108,22 +85,14 @@ LinkNode *BLI_linklist_append_fast(LinkNode **listp, void *ptr) { //////////////////////////////////////////////////////////////////////// static float KDOP_AXES[13][3] = -{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {1, 1, 1}, {1, -1, 1}, {1, 1, -1}, -{1, -1, -1}, {1, 1, 0}, {1, 0, 1}, {0, 1, 1}, {1, -1, 0}, {1, 0, -1}, -{0, 1, -1} +{ {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0}, +{1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0}, +{0, 1.0, -1.0} }; ///////////// choose bounding volume here! ///////////// -// #define KDOP_26 - -// #define KDOP_14 - -// AABB: -// #define KDOP_8 - -// OBB: -#define KDOP_6 +#define KDOP_26 @@ -132,10 +101,9 @@ static float KDOP_AXES[13][3] = #define KDOP_START 0 #endif -// I didn't test this one! #ifdef KDOP_18 -#define KDOP_END 7 -#define KDOP_START 13 +#define KDOP_END 13 +#define KDOP_START 7 #endif #ifdef KDOP_14 @@ -179,7 +147,7 @@ DO_INLINE int floor_lg(int a) /* * Insertion sort algorithm */ -static void bvh_insertionsort(CollisionTree **a, int lo, int hi, int axis) +void bvh_insertionsort(CollisionTree **a, int lo, int hi, int axis) { int i,j; CollisionTree *t; @@ -276,7 +244,7 @@ static CollisionTree *bvh_medianof3(CollisionTree **a, int lo, int mid, int hi, /* * Quicksort algorithm modified for Introsort */ -static void bvh_introsort_loop (CollisionTree **a, int lo, int hi, int depth_limit, int axis) +void bvh_introsort_loop (CollisionTree **a, int lo, int hi, int depth_limit, int axis) { int p; @@ -371,19 +339,30 @@ DO_INLINE void bvh_calc_DOP_hull_from_faces(BVH * bvh, CollisionTree **tri, int { float newmin,newmax; int i, j; + + if(numfaces >0) + { + // for all Axes. + for (i = KDOP_START; i < KDOP_END; i++) + { + bv[(2 * i)] = (tri [0])->bv[(2 * i)]; + bv[(2 * i) + 1] = (tri [0])->bv[(2 * i) + 1]; + } + } + for (j = 0; j < numfaces; j++) { // for all Axes. for (i = KDOP_START; i < KDOP_END; i++) { newmin = (tri [j])->bv[(2 * i)]; - if ((newmin < bv[(2 * i)]) || (j == 0)) + if ((newmin < bv[(2 * i)])) { bv[(2 * i)] = newmin; } newmax = (tri [j])->bv[(2 * i) + 1]; - if ((newmax > bv[(2 * i) + 1]) || (j == 0)) + if ((newmax > bv[(2 * i) + 1])) { bv[(2 * i) + 1] = newmax; } @@ -391,12 +370,13 @@ DO_INLINE void bvh_calc_DOP_hull_from_faces(BVH * bvh, CollisionTree **tri, int } } -DO_INLINE void bvh_calc_DOP_hull_static(BVH * bvh, CollisionTree **tri, int numfaces, float *bv) +DO_INLINE void bvh_calc_DOP_hull_static(BVH * bvh, CollisionTree **tri, int numfaces, float *bv, CollisionTree *tree) { MFace *tempMFace = bvh->mfaces; float *tempBV = bv; float newminmax; int i, j, k; + for (j = 0; j < numfaces; j++) { tempMFace = bvh->mfaces + (tri [j])->tri_index; @@ -426,15 +406,31 @@ DO_INLINE void bvh_calc_DOP_hull_static(BVH * bvh, CollisionTree **tri, int numf tempBV[(2 * i) + 1] = newminmax; } } + + /* calculate normal of this face */ + /* (code copied from cdderivedmesh.c) */ + /* + if(tempMFace->v4) + CalcNormFloat4(bvh->current_xold[tempMFace->v1].co, bvh->current_xold[tempMFace->v2].co, + bvh->current_xold[tempMFace->v3].co, bvh->current_xold[tempMFace->v4].co, tree->normal); + else + CalcNormFloat(bvh->current_xold[tempMFace->v1].co, bvh->current_xold[tempMFace->v2].co, + bvh->current_xold[tempMFace->v3].co, tree->normal); + + tree->alpha = 0; + */ } } -DO_INLINE void bvh_calc_DOP_hull_moving(BVH * bvh, CollisionTree **tri, int numfaces, float *bv) +DO_INLINE void bvh_calc_DOP_hull_moving(BVH * bvh, CollisionTree **tri, int numfaces, float *bv, CollisionTree *tree) { MFace *tempMFace = bvh->mfaces; float *tempBV = bv; float newminmax; int i, j, k; + + /* TODO: calculate normals */ + for (j = 0; j < numfaces; j++) { tempMFace = bvh->mfaces + (tri [j])->tri_index; @@ -488,14 +484,15 @@ static void bvh_div_env_node(BVH *bvh, CollisionTree *tree, CollisionTree **face // Sort along longest axis if(laxis!=lastaxis) bvh_sort_along_axis(face_list, start, end, laxis); - + + // maximum is 4 since we have a quad tree max_nodes = MIN2((end-start + 1 ),4); for (i = 0; i < max_nodes; i++) { tree->count_nodes++; - if(end-start > 4) + if(end-start+1 > 4) { int quarter = ((float)((float)(end - start + 1) / 4.0f)); tstart = start + i * quarter; @@ -549,18 +546,32 @@ void bvh_build (BVH *bvh) CollisionTree *tree=NULL; LinkNode *nlink = NULL; + bvh->flags = 0; + bvh->leaf_tree = NULL; + bvh->leaf_root = NULL; + bvh->tree = NULL; + + if(!bvh->current_x) + { + bvh_free(bvh); + return; + } + + bvh->current_xold = MEM_dupallocN(bvh->current_x); + tree = (CollisionTree *)MEM_callocN(sizeof(CollisionTree), "CollisionTree"); - // TODO: check succesfull alloc - BLI_linklist_append(&bvh->tree, tree); - - nlink = bvh->tree; - + if (tree == NULL) { printf("bvh_build: Out of memory for nodes.\n"); bvh_free(bvh); return; } + + BLI_linklist_append(&bvh->tree, tree); + + nlink = bvh->tree; + bvh->root = bvh->tree->link; bvh->root->isleaf = 0; bvh->root->parent = NULL; @@ -618,7 +629,7 @@ void bvh_build (BVH *bvh) tree->nodes[0] = tree->nodes[1] = tree->nodes[2] = tree->nodes[3] = NULL; - bvh_calc_DOP_hull_static(bvh, &face_list[i], 1, tree->bv); + bvh_calc_DOP_hull_static(bvh, &face_list[i], 1, tree->bv, tree); // inflate the bv with some epsilon for (j = KDOP_START; j < KDOP_END; j++) @@ -663,6 +674,19 @@ DO_INLINE int bvh_overlap(float *bv1, float *bv2) return 1; } +// bvh_overlap_self - is it possbile for 2 bv's to selfcollide ? +DO_INLINE int bvh_overlap_self(CollisionTree * tree1, CollisionTree * tree2) +{ + // printf("overlap: %f, q: %f\n", (saacos(INPR(tree1->normal, tree2->normal)) / 2.0)+MAX2(tree1->alpha, tree2->alpha), saacos(INPR(tree1->normal, tree2->normal))); + + if((saacos(INPR(tree1->normal, tree2->normal)) / 2.0)+MAX2(tree1->alpha, tree2->alpha) > M_PI) + { + return 1; + } + else + return 0; +} + /** * bvh_traverse - traverse two bvh trees looking for potential collisions. * @@ -670,9 +694,9 @@ DO_INLINE int bvh_overlap(float *bv1, float *bv2) * every other triangle that doesn't require any realloc, but uses * much memory */ -int bvh_traverse ( ClothModifierData * clmd, CollisionModifierData * collmd, CollisionTree * tree1, CollisionTree * tree2, float step, CM_COLLISION_RESPONSE collision_response) +int bvh_traverse ( ModifierData * md1, ModifierData * md2, CollisionTree * tree1, CollisionTree * tree2, float step, CM_COLLISION_RESPONSE collision_response, int selfcollision) { - int i = 0, ret=0; + int i = 0, ret=0, overlap = 0; /* // Shouldn't be possible @@ -680,9 +704,15 @@ int bvh_traverse ( ClothModifierData * clmd, CollisionModifierData * collmd, Col { printf("Error: no tree there\n"); return 0; - } +} */ - if (bvh_overlap(tree1->bv, tree2->bv)) + + if(selfcollision) + overlap = bvh_overlap_self(tree1, tree2); + else + overlap = bvh_overlap(tree1->bv, tree2->bv); + + if (overlap) { // Check if this node in the first tree is a leaf if (tree1->isleaf) @@ -693,7 +723,7 @@ int bvh_traverse ( ClothModifierData * clmd, CollisionModifierData * collmd, Col // Provide the collision response. if(collision_response) - collision_response (clmd, collmd, tree1, tree2); + collision_response (md1, md2, tree1, tree2); return 1; } else @@ -702,7 +732,7 @@ int bvh_traverse ( ClothModifierData * clmd, CollisionModifierData * collmd, Col for (i = 0; i < 4; i++) { // Only traverse nodes that exist. - if (tree2->nodes[i] && bvh_traverse (clmd, collmd, tree1, tree2->nodes[i], step, collision_response)) + if (tree2->nodes[i] && bvh_traverse (md1, md2, tree1, tree2->nodes[i], step, collision_response, selfcollision)) ret = 1; } } @@ -713,7 +743,7 @@ int bvh_traverse ( ClothModifierData * clmd, CollisionModifierData * collmd, Col for (i = 0; i < 4; i++) { // Only traverse nodes that exist. - if (tree1->nodes [i] && bvh_traverse (clmd, collmd, tree1->nodes[i], tree2, step, collision_response)) + if (tree1->nodes [i] && bvh_traverse (md1, md2, tree1->nodes[i], tree2, step, collision_response, selfcollision)) ret = 1; } } @@ -721,12 +751,13 @@ int bvh_traverse ( ClothModifierData * clmd, CollisionModifierData * collmd, Col return ret; } - // bottom up update of bvh tree: // join the 4 children here -void bvh_join(CollisionTree * tree) +void bvh_join(CollisionTree *tree) { int i = 0, j = 0; + float max = 0; + if (!tree) return; @@ -747,10 +778,29 @@ void bvh_join(CollisionTree * tree) tree->bv[(2 * j) + 1] = tree->nodes[i]->bv[(2 * j) + 1]; } } + + /* for selfcollisions */ + /* + if(!i) + { + tree->alpha = tree->nodes[i]->alpha; + VECCOPY(tree->normal, tree->nodes[i]->normal); + } + else + { + tree->alpha += saacos(INPR(tree->normal, tree->nodes[i]->normal)) / 2.0; + VECADD(tree->normal, tree->normal, tree->nodes[i]->normal); + VecMulf(tree->normal, 0.5); + max = MAX2(max, tree->nodes[i]->alpha); + } + */ + } else break; } + + tree->alpha += max; } // update static bvh @@ -769,9 +819,9 @@ void bvh_update(BVH * bvh, int moving) leaf->parent->traversed = 0; } if(!moving) - bvh_calc_DOP_hull_static(bvh, &leaf, 1, leaf->bv); + bvh_calc_DOP_hull_static(bvh, &leaf, 1, leaf->bv, leaf); else - bvh_calc_DOP_hull_moving(bvh, &leaf, 1, leaf->bv); + bvh_calc_DOP_hull_moving(bvh, &leaf, 1, leaf->bv, leaf); // inflate the bv with some epsilon for (j = KDOP_START; j < KDOP_END; j++) diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index b57b799001a..3b4e562a87a 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -4,15 +4,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <math.h> @@ -545,26 +542,26 @@ static void cp_key(int start, int end, int tot, char *poin, Key *key, KeyBlock * case IPO_FLOAT: if(weights) { - memcpy(poin, kref, 4*cp[0]); + memcpy(poin, kref, sizeof(float)*cp[0]); if(*weights!=0.0f) rel_flerp(cp[0], (float *)poin, (float *)kref, (float *)k1, *weights); weights++; } else - memcpy(poin, k1, 4*cp[0]); + memcpy(poin, k1, sizeof(float)*cp[0]); poin+= ofsp[0]; break; case IPO_BPOINT: - memcpy(poin, k1, 3*4); - memcpy(poin+16, k1+12, 4); + memcpy(poin, k1, 3*sizeof(float)); + memcpy(poin+4*sizeof(float), k1+3*sizeof(float), sizeof(float)); poin+= ofsp[0]; break; case IPO_BEZTRIPLE: - memcpy(poin, k1, 4*12); + memcpy(poin, k1, sizeof(float)*10); poin+= ofsp[0]; break; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 2b815c28cc5..e8bcae42d5a 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -4,15 +4,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -519,7 +516,7 @@ static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir) /* co: local coord, result local too */ /* returns quaternion for rotation, using cd->no_rot_axis */ /* axis is using another define!!! */ -static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd) +static int calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd, float *quatp) { Curve *cu= par->data; float fac, loc[4], dir[3], cent[3]; @@ -549,7 +546,7 @@ static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform /* to be sure, mostly after file load */ if(cu->path==NULL) { makeDispListCurveTypes(par, 0); - if(cu->path==NULL) return NULL; // happens on append... + if(cu->path==NULL) return 0; // happens on append... } /* options */ @@ -575,14 +572,13 @@ static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform } if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */ - float q[4], mat[3][3]; - float *quat; + float q[4], mat[3][3], quat[4]; if(cd->no_rot_axis) /* set by caller */ dir[cd->no_rot_axis-1]= 0.0f; /* -1 for compatibility with old track defines */ - quat= vectoquat(dir, axis-1, upflag); /* gives static quat */ + vectoquat(dir, axis-1, upflag, quat); /* the tilt */ if(loc[3]!=0.0) { @@ -602,18 +598,26 @@ static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform /* translation */ VECADD(co, cent, loc); - return quat; + if(quatp) + QUATCOPY(quatp, quat); + + return 1; } - return NULL; + return 0; } void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis) { - Curve *cu = cuOb->data; - int a, flag = cu->flag; + Curve *cu; + int a, flag; CurveDeform cd; int use_vgroups; - + + if(cuOb->type != OB_CURVE) + return; + + cu = cuOb->data; + flag = cu->flag; cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist init_curve_deform(cuOb, target, &cd, (cu->flag & CU_STRETCH)==0); @@ -668,7 +672,7 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v for(j = 0; j < dvert->totweight; j++) { if(dvert->dw[j].def_nr == index) { VECCOPY(vec, vertexCos[a]); - calc_curve_deform(cuOb, vec, defaxis, &cd); + calc_curve_deform(cuOb, vec, defaxis, &cd, NULL); VecLerpf(vertexCos[a], vertexCos[a], vec, dvert->dw[j].weight); Mat4MulVecfl(cd.objectspace, vertexCos[a]); @@ -686,7 +690,7 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v } for(a = 0; a < numVerts; a++) { - calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd); + calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL); Mat4MulVecfl(cd.objectspace, vertexCos[a]); } } @@ -699,8 +703,13 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis) { CurveDeform cd; - float *quat; + float quat[4]; + if(cuOb->type != OB_CURVE) { + Mat3One(mat); + return; + } + init_curve_deform(cuOb, target, &cd, 0); /* 0 no dloc */ cd.no_rot_axis= no_rot_axis; /* option to only rotate for XY, for example */ @@ -709,8 +718,7 @@ void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, Mat4MulVecfl(cd.curvespace, vec); - quat= calc_curve_deform(cuOb, vec, target->trackflag+1, &cd); - if(quat) { + if(calc_curve_deform(cuOb, vec, target->trackflag+1, &cd, quat)) { float qmat[3][3]; QuatToMat3(quat, qmat); @@ -729,6 +737,9 @@ void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, int a; int use_vgroups; + if(laOb->type != OB_LATTICE) + return; + init_latt_deform(laOb, target); /* check whether to use vertex groups (only possible if target is a Mesh) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index e81d3bac655..cc3f3f211a4 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ /* @@ -114,7 +111,7 @@ #include "BKE_brush.h" #include "BKE_idprop.h" -#include "BPI_script.h" +#include "DNA_space_types.h" #define MAX_IDPUP 60 /* was 24 */ @@ -977,7 +974,7 @@ static void image_fix_relative_path(Image *ima) { if(ima->id.lib==NULL) return; if(strncmp(ima->name, "//", 2)==0) { - BLI_convertstringcode(ima->name, ima->id.lib->filename, 0); + BLI_convertstringcode(ima->name, ima->id.lib->filename); BLI_makestringcode(G.sce, ima->name); } } @@ -994,7 +991,7 @@ static void lib_indirect_test_id(ID *id) Object *ob= (Object *)id; bActionStrip *strip; Mesh *me; - PartEff *paf; + int a; for (strip=ob->nlastrips.first; strip; strip=strip->next){ @@ -1006,10 +1003,6 @@ static void lib_indirect_test_id(ID *id) for(a=0; a<ob->totcol; a++) { LIBTAG(ob->mat[a]); } - - paf = give_parteff(ob); - if (paf) - LIBTAG(paf->group); LIBTAG(ob->dup_group); LIBTAG(ob->proxy); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 42cac46c241..3983eecdaba 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -4,15 +4,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <string.h> @@ -633,9 +630,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) if(ma->flarec==0) ma->flarec= 1; - /* add all texcoflags from mtex */ - ma->texco= 0; - ma->mapto= 0; + /* add all texcoflags from mtex, texco and mapto were cleared in advance */ for(a=0; a<MAX_MTEX; a++) { /* separate tex switching */ @@ -730,6 +725,16 @@ void init_render_materials(int r_mode, float *amb) { Material *ma; + /* clear these flags before going over materials, to make sure they + * are cleared only once, otherwise node materials contained in other + * node materials can go wrong */ + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->id.us) { + ma->texco= 0; + ma->mapto= 0; + } + } + /* two steps, first initialize, then or the flags for layers */ for(ma= G.main->mat.first; ma; ma= ma->id.next) { /* is_used flag comes back in convertblender.c */ diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index e731f0fdfe0..16916381c95 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -8,15 +8,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -32,7 +29,7 @@ * * Contributor(s): Jiri Hnidek <jiri.hnidek@vslib.cz>. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -233,14 +230,14 @@ void tex_space_mball(Object *ob) boundbox_set_from_min_max(bb, min, max); } -void make_orco_mball(Object *ob) +float *make_orco_mball(Object *ob) { BoundBox *bb; DispList *dl; - float *data; + float *data, *orco, *orcodata; float loc[3], size[3]; int a; - + /* restore size and loc */ bb= ob->bb; loc[0]= (bb->vec[0][0]+bb->vec[4][0])/2.0f; @@ -251,15 +248,21 @@ void make_orco_mball(Object *ob) size[2]= bb->vec[1][2]-loc[2]; dl= ob->disp.first; + orcodata= MEM_mallocN(sizeof(float)*3*dl->nr, "MballOrco"); + data= dl->verts; + orco= orcodata; a= dl->nr; while(a--) { - data[0]= (data[0]-loc[0])/size[0]; - data[1]= (data[1]-loc[1])/size[1]; - data[2]= (data[2]-loc[2])/size[2]; + orco[0]= (data[0]-loc[0])/size[0]; + orco[1]= (data[1]-loc[1])/size[1]; + orco[2]= (data[2]-loc[2])/size[2]; data+= 3; + orco+= 3; } + + return orcodata; } /** \brief Test, if Object *ob is basic MetaBall. * @@ -1211,8 +1214,8 @@ void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2, p->y = neg.y; p->z = neg.z; while (1) { - p->x = 0.5f*(pos.x + neg.x); if (i++ == RES) return; + p->x = 0.5f*(pos.x + neg.x); if ((function(p->x,p->y,p->z)) > 0.0) pos.x = p->x; else neg.x = p->x; } } @@ -1221,8 +1224,8 @@ void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2, p->x = neg.x; p->z = neg.z; while (1) { - p->y = 0.5f*(pos.y + neg.y); if (i++ == RES) return; + p->y = 0.5f*(pos.y + neg.y); if ((function(p->x,p->y,p->z)) > 0.0) pos.y = p->y; else neg.y = p->y; } } @@ -1231,8 +1234,8 @@ void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2, p->x = neg.x; p->y = neg.y; while (1) { - p->z = 0.5f*(pos.z + neg.z); if (i++ == RES) return; + p->z = 0.5f*(pos.z + neg.z); if ((function(p->x,p->y,p->z)) > 0.0) pos.z = p->z; else neg.z = p->z; } } @@ -1297,6 +1300,8 @@ void find_first_points(PROCESS *mbproc, MetaBall *mb, int a) int index[3]={1,0,-1}; float f =0.0f; float in_v, out_v; + MB_POINT workp; + float tmp_v, workp_v, max_len, len, dx, dy, dz, nx, ny, nz, MAXN; ml = mainb[a]; @@ -1357,23 +1362,49 @@ void find_first_points(PROCESS *mbproc, MetaBall *mb, int a) out_v = mbproc->function(out.x, out.y, out.z); - /* find "first point" on Implicit Surface of MetaElemnt ml */ - converge(&in, &out, in_v, out_v, mbproc->function, &mbproc->start, mb, 0); - - /* indexes of CUBE, which includes "first point" */ - c_i= (int)floor(mbproc->start.x/mbproc->size ); - c_j= (int)floor(mbproc->start.y/mbproc->size ); - c_k= (int)floor(mbproc->start.z/mbproc->size ); - - mbproc->start.x= mbproc->start.y= mbproc->start.z= 0.0; + /* find "first points" on Implicit Surface of MetaElemnt ml */ + //converge(&in, &out, in_v, out_v, mbproc->function, &mbproc->start, mb, 0); + workp = in; + workp_v = in_v; + max_len = sqrt((out.x-in.x)*(out.x-in.x) + (out.y-in.y)*(out.y-in.y) + (out.z-in.z)*(out.z-in.z)); - /* add CUBE (with indexes c_i, c_j, c_k) to the stack, - * this cube includes found point of Implicit Surface */ - if (ml->flag & MB_NEGATIVE) - add_cube(mbproc, c_i, c_j, c_k, 2); - else - add_cube(mbproc, c_i, c_j, c_k, 1); + nx = abs((out.x - in.x)/mbproc->size); + ny = abs((out.y - in.y)/mbproc->size); + nz = abs((out.z - in.z)/mbproc->size); + + MAXN = MAX3(nx,ny,nz); + + dx = (out.x - in.x)/MAXN; + dy = (out.y - in.y)/MAXN; + dz = (out.z - in.z)/MAXN; + + len = 0.0; + while(len<=max_len) { + workp.x += dx; + workp.y += dy; + workp.z += dz; + /* compute value of implicite function */ + tmp_v = mbproc->function(workp.x, workp.y, workp.z); + /* add cube to the stack, when value of implicite function crosses zero value */ + if((tmp_v<0.0 && workp_v>=0.0)||(tmp_v>0.0 && workp_v<=0.0)) { + + /* indexes of CUBE, which includes "first point" */ + c_i= (int)floor(workp.x/mbproc->size); + c_j= (int)floor(workp.y/mbproc->size); + c_k= (int)floor(workp.z/mbproc->size); + + /* add CUBE (with indexes c_i, c_j, c_k) to the stack, + * this cube includes found point of Implicit Surface */ + if (ml->flag & MB_NEGATIVE) + add_cube(mbproc, c_i, c_j, c_k, 2); + else + add_cube(mbproc, c_i, c_j, c_k, 1); + } + len = sqrt((workp.x-in.x)*(workp.x-in.x) + (workp.y-in.y)*(workp.y-in.y) + (workp.z-in.z)*(workp.z-in.z)); + workp_v = tmp_v; + } + mbproc->start.x= mbproc->start.y= mbproc->start.z= 0.0; } } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 25a391be566..43e48c3bacd 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -5,15 +5,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,7 +28,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef HAVE_CONFIG_H @@ -530,7 +527,7 @@ void transform_mesh_orco_verts(Mesh *me, float (*orco)[3], int totvert, int inve /* rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0. this is necessary to make the if(mface->v4) check for quads work */ -void test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr) +int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr) { /* first test if the face is legal */ if(mface->v3 && mface->v3==mface->v4) { @@ -572,6 +569,8 @@ void test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr) CustomData_swap(fdata, mfindex, corner_indices); } } + + return nr; } Mesh *get_mesh(Object *ob) @@ -768,8 +767,7 @@ void mball_to_mesh(ListBase *lb, Mesh *me) mface->v4= index[3]; mface->flag= ME_SMOOTH; - if(mface->v3==mface->v4) - mface->v4= 0; + test_index_face(mface, NULL, 0, (mface->v3==mface->v4)? 3: 4); mface++; index+= 4; @@ -1108,9 +1106,13 @@ float (*mesh_getRefKeyCos(Mesh *me, int *numVerts_r))[3] if(me->key && me->key->refkey) { if(numVerts_r) *numVerts_r= me->totvert; - cos= MEM_mallocN(sizeof(*cos)*me->totvert, "vertexcos1"); - + kb= me->key->refkey; + + /* prevent accessing invalid memory */ + if (me->totvert > kb->totelem) cos= MEM_callocN(sizeof(*cos)*me->totvert, "vertexcos1"); + else cos= MEM_mallocN(sizeof(*cos)*me->totvert, "vertexcos1"); + totvert= MIN2(kb->totelem, me->totvert); memcpy(cos, kb->data, sizeof(*cos)*totvert); @@ -1140,12 +1142,12 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned if(totuv==0) return NULL; - vmap= (UvVertMap*)MEM_mallocN(sizeof(*vmap), "UvVertMap"); + vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap"); if (!vmap) return NULL; vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totvert, "UvMapVert*"); - buf= vmap->buf= (UvMapVert*)MEM_mallocN(sizeof(*vmap->buf)*totuv, "UvMapVert"); + buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert"); if (!vmap->vert || !vmap->buf) { free_uv_vert_map(vmap); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 7f378f136b6..2a8ba878c41 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -96,6 +96,7 @@ #include "BKE_pointcache.h" #include "BKE_utildefines.h" #include "depsgraph_private.h" +#include "BKE_bmesh.h" #include "LOD_DependKludge.h" #include "LOD_decimation.h" @@ -149,9 +150,9 @@ static int curveModifier_isDisabled(ModifierData *md) } static void curveModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { CurveModifierData *cmd = (CurveModifierData*) md; @@ -159,8 +160,8 @@ static void curveModifier_foreachObjectLink( } static void curveModifier_updateDepgraph( - ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) { CurveModifierData *cmd = (CurveModifierData*) md; @@ -168,23 +169,23 @@ static void curveModifier_updateDepgraph( DagNode *curNode = dag_get_node(forest, cmd->object); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Modifier"); } } static void curveModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { CurveModifierData *cmd = (CurveModifierData*) md; curve_deform_verts(cmd->object, ob, derivedData, vertexCos, numVerts, - cmd->name, cmd->defaxis); + cmd->name, cmd->defaxis); } static void curveModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; @@ -225,9 +226,9 @@ static int latticeModifier_isDisabled(ModifierData *md) } static void latticeModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { LatticeModifierData *lmd = (LatticeModifierData*) md; @@ -235,7 +236,7 @@ static void latticeModifier_foreachObjectLink( } static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + Object *ob, DagNode *obNode) { LatticeModifierData *lmd = (LatticeModifierData*) md; @@ -243,7 +244,7 @@ static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, DagNode *latNode = dag_get_node(forest, lmd->object); dag_add_relation(forest, latNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Lattice Modifier"); } } @@ -262,8 +263,8 @@ static void modifier_vgroup_cache(ModifierData *md, float (*vertexCos)[3]) static void latticeModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { LatticeModifierData *lmd = (LatticeModifierData*) md; @@ -271,12 +272,12 @@ static void latticeModifier_deformVerts( modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */ lattice_deform_verts(lmd->object, ob, derivedData, - vertexCos, numVerts, lmd->name); + vertexCos, numVerts, lmd->name); } static void latticeModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; @@ -322,28 +323,28 @@ static void subsurfModifier_freeData(ModifierData *md) } static DerivedMesh *subsurfModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { SubsurfModifierData *smd = (SubsurfModifierData*) md; DerivedMesh *result; result = subsurf_make_derived_from_derived(derivedData, smd, - useRenderParams, NULL, - isFinalCalc, 0); + useRenderParams, NULL, + isFinalCalc, 0); return result; } static DerivedMesh *subsurfModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { SubsurfModifierData *smd = (SubsurfModifierData*) md; DerivedMesh *result; result = subsurf_make_derived_from_derived(derivedData, smd, 0, - NULL, 0, 1); + NULL, 0, 1); return result; } @@ -375,8 +376,8 @@ static int buildModifier_dependsOnTime(ModifierData *md) } static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, - DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *dm = derivedData; DerivedMesh *result; @@ -389,29 +390,29 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, GHashIterator *hashIter; /* maps vert indices in old mesh to indices in new mesh */ GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash, - BLI_ghashutil_intcmp); + BLI_ghashutil_intcmp); /* maps edge indices in new mesh to indices in old mesh */ GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, - BLI_ghashutil_intcmp); + BLI_ghashutil_intcmp); maxVerts = dm->getNumVerts(dm); vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts, - "build modifier vertMap"); + "build modifier vertMap"); for(i = 0; i < maxVerts; ++i) vertMap[i] = i; maxEdges = dm->getNumEdges(dm); edgeMap = MEM_callocN(sizeof(*edgeMap) * maxEdges, - "build modifier edgeMap"); + "build modifier edgeMap"); for(i = 0; i < maxEdges; ++i) edgeMap[i] = i; maxFaces = dm->getNumFaces(dm); faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces, - "build modifier faceMap"); + "build modifier faceMap"); for(i = 0; i < maxFaces; ++i) faceMap[i] = i; if (ob) { frac = bsystem_time(ob, (float)G.scene->r.cfra, - bmd->start - 1.0f) / bmd->length; + bmd->start - 1.0f) / bmd->length; } else { frac = G.scene->r.cfra - bmd->start / bmd->length; } @@ -426,157 +427,157 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, if(bmd->randomize) BLI_array_randomize(faceMap, sizeof(*faceMap), - maxFaces, bmd->seed); + maxFaces, bmd->seed); /* get the set of all vert indices that will be in the final mesh, - * mapped to the new indices - */ + * mapped to the new indices + */ for(i = 0; i < numFaces; ++i) { MFace mf; dm->getFace(dm, faceMap[i], &mf); - if(!BLI_ghash_haskey(vertHash, (void *)mf.v1)) - BLI_ghash_insert(vertHash, (void *)mf.v1, - (void *)BLI_ghash_size(vertHash)); - if(!BLI_ghash_haskey(vertHash, (void *)mf.v2)) - BLI_ghash_insert(vertHash, (void *)mf.v2, - (void *)BLI_ghash_size(vertHash)); - if(!BLI_ghash_haskey(vertHash, (void *)mf.v3)) - BLI_ghash_insert(vertHash, (void *)mf.v3, - (void *)BLI_ghash_size(vertHash)); - if(mf.v4 && !BLI_ghash_haskey(vertHash, (void *)mf.v4)) - BLI_ghash_insert(vertHash, (void *)mf.v4, - (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1))) + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v1), + SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); + if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v2))) + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v2), + SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); + if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v3))) + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v3), + SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); + if(mf.v4 && !BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v4))) + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v4), + SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); } /* get the set of edges that will be in the new mesh (i.e. all edges - * that have both verts in the new mesh) - */ + * that have both verts in the new mesh) + */ maxEdges = dm->getNumEdges(dm); for(i = 0; i < maxEdges; ++i) { MEdge me; dm->getEdge(dm, i, &me); - if(BLI_ghash_haskey(vertHash, (void *)me.v1) - && BLI_ghash_haskey(vertHash, (void *)me.v2)) + if(BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1)) + && BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) BLI_ghash_insert(edgeHash, - (void *)BLI_ghash_size(edgeHash), (void *)i); + SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)), SET_INT_IN_POINTER(i)); } } else if(numEdges) { if(bmd->randomize) BLI_array_randomize(edgeMap, sizeof(*edgeMap), - maxEdges, bmd->seed); + maxEdges, bmd->seed); /* get the set of all vert indices that will be in the final mesh, - * mapped to the new indices - */ + * mapped to the new indices + */ for(i = 0; i < numEdges; ++i) { MEdge me; dm->getEdge(dm, edgeMap[i], &me); - if(!BLI_ghash_haskey(vertHash, (void *)me.v1)) - BLI_ghash_insert(vertHash, (void *)me.v1, - (void *)BLI_ghash_size(vertHash)); - if(!BLI_ghash_haskey(vertHash, (void *)me.v2)) - BLI_ghash_insert(vertHash, (void *)me.v2, - (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v1))) + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v1), + SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); + if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(me.v2))) + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(me.v2), + SET_INT_IN_POINTER(BLI_ghash_size(vertHash))); } /* get the set of edges that will be in the new mesh - */ + */ for(i = 0; i < numEdges; ++i) { MEdge me; dm->getEdge(dm, edgeMap[i], &me); - BLI_ghash_insert(edgeHash, (void *)BLI_ghash_size(edgeHash), - (void *)edgeMap[i]); + BLI_ghash_insert(edgeHash, SET_INT_IN_POINTER(BLI_ghash_size(edgeHash)), + SET_INT_IN_POINTER(edgeMap[i])); } } else { int numVerts = dm->getNumVerts(dm) * frac; if(bmd->randomize) BLI_array_randomize(vertMap, sizeof(*vertMap), - maxVerts, bmd->seed); + maxVerts, bmd->seed); /* get the set of all vert indices that will be in the final mesh, - * mapped to the new indices - */ + * mapped to the new indices + */ for(i = 0; i < numVerts; ++i) - BLI_ghash_insert(vertHash, (void *)vertMap[i], (void *)i); + BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(vertMap[i]), SET_INT_IN_POINTER(i)); } /* now we know the number of verts, edges and faces, we can create - * the mesh - */ + * the mesh + */ result = CDDM_from_template(dm, BLI_ghash_size(vertHash), - BLI_ghash_size(edgeHash), numFaces); + BLI_ghash_size(edgeHash), numFaces); /* copy the vertices across */ for(hashIter = BLI_ghashIterator_new(vertHash); - !BLI_ghashIterator_isDone(hashIter); - BLI_ghashIterator_step(hashIter)) { - MVert source; - MVert *dest; - int oldIndex = (int)BLI_ghashIterator_getKey(hashIter); - int newIndex = (int)BLI_ghashIterator_getValue(hashIter); + !BLI_ghashIterator_isDone(hashIter); + BLI_ghashIterator_step(hashIter)) { + MVert source; + MVert *dest; + int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter)); + int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); - dm->getVert(dm, oldIndex, &source); - dest = CDDM_get_vert(result, newIndex); + dm->getVert(dm, oldIndex, &source); + dest = CDDM_get_vert(result, newIndex); - DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); - *dest = source; - } - BLI_ghashIterator_free(hashIter); + DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); + *dest = source; + } + BLI_ghashIterator_free(hashIter); - /* copy the edges across, remapping indices */ - for(i = 0; i < BLI_ghash_size(edgeHash); ++i) { - MEdge source; - MEdge *dest; - int oldIndex = (int)BLI_ghash_lookup(edgeHash, (void *)i); + /* copy the edges across, remapping indices */ + for(i = 0; i < BLI_ghash_size(edgeHash); ++i) { + MEdge source; + MEdge *dest; + int oldIndex = GET_INT_FROM_POINTER(BLI_ghash_lookup(edgeHash, SET_INT_IN_POINTER(i))); - dm->getEdge(dm, oldIndex, &source); - dest = CDDM_get_edge(result, i); + dm->getEdge(dm, oldIndex, &source); + dest = CDDM_get_edge(result, i); - source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1); - source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2); + source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); + source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); - DM_copy_edge_data(dm, result, oldIndex, i, 1); - *dest = source; - } + DM_copy_edge_data(dm, result, oldIndex, i, 1); + *dest = source; + } - /* copy the faces across, remapping indices */ - for(i = 0; i < numFaces; ++i) { - MFace source; - MFace *dest; - int orig_v4; + /* copy the faces across, remapping indices */ + for(i = 0; i < numFaces; ++i) { + MFace source; + MFace *dest; + int orig_v4; - dm->getFace(dm, faceMap[i], &source); - dest = CDDM_get_face(result, i); + dm->getFace(dm, faceMap[i], &source); + dest = CDDM_get_face(result, i); - orig_v4 = source.v4; + orig_v4 = source.v4; - source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1); - source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2); - source.v3 = (int)BLI_ghash_lookup(vertHash, (void *)source.v3); - if(source.v4) - source.v4 = (int)BLI_ghash_lookup(vertHash, (void *)source.v4); + source.v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v1))); + source.v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v2))); + source.v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v3))); + if(source.v4) + source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4))); - DM_copy_face_data(dm, result, faceMap[i], i, 1); - *dest = source; + DM_copy_face_data(dm, result, faceMap[i], i, 1); + *dest = source; - test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3)); - } + test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3)); + } - CDDM_calc_normals(result); + CDDM_calc_normals(result); - BLI_ghash_free(vertHash, NULL, NULL); - BLI_ghash_free(edgeHash, NULL, NULL); + BLI_ghash_free(vertHash, NULL, NULL); + BLI_ghash_free(edgeHash, NULL, NULL); - MEM_freeN(vertMap); - MEM_freeN(edgeMap); - MEM_freeN(faceMap); + MEM_freeN(vertMap); + MEM_freeN(edgeMap); + MEM_freeN(faceMap); - return result; + return result; } /* Array */ @@ -588,7 +589,7 @@ static void arrayModifier_initData(ModifierData *md) ArrayModifierData *amd = (ArrayModifierData*) md; /* default to 2 duplicates distributed along the x-axis by an - offset of 1 object-width + offset of 1 object-width */ amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL; amd->count = 2; @@ -622,9 +623,9 @@ static void arrayModifier_copyData(ModifierData *md, ModifierData *target) } static void arrayModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { ArrayModifierData *amd = (ArrayModifierData*) md; @@ -635,7 +636,7 @@ static void arrayModifier_foreachObjectLink( } static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + Object *ob, DagNode *obNode) { ArrayModifierData *amd = (ArrayModifierData*) md; @@ -643,25 +644,25 @@ static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest, DagNode *curNode = dag_get_node(forest, amd->start_cap); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); } if (amd->end_cap) { DagNode *curNode = dag_get_node(forest, amd->end_cap); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); } if (amd->curve_ob) { DagNode *curNode = dag_get_node(forest, amd->curve_ob); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); } if (amd->offset_ob) { DagNode *curNode = dag_get_node(forest, amd->offset_ob); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Array Modifier"); } } @@ -688,12 +689,12 @@ typedef struct IndexMapEntry { /* the new vert index that this old vert index maps to */ int new; /* -1 if this vert isn't merged, otherwise the old vert index it - * should be replaced with - */ + * should be replaced with + */ int merge; /* 1 if this vert's first copy is merged with the last copy of its - * merge target, otherwise 0 - */ + * merge target, otherwise 0 + */ short merge_final; } IndexMapEntry; @@ -712,19 +713,19 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum) } else { /* vert was merged with another vert */ /* follow the chain of merges to the end, or until we've passed - * a number of vertices equal to the copy number - */ + * a number of vertices equal to the copy number + */ if(copyNum <= 0) return indexMap[oldIndex].new; else return calc_mapping(indexMap, indexMap[oldIndex].merge, - copyNum - 1); + copyNum - 1); } } static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, - Object *ob, DerivedMesh *dm, - int initFlags) + Object *ob, DerivedMesh *dm, + int initFlags) { int i, j; /* offset matrix */ @@ -754,7 +755,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, MTC_Mat4One(offset); indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm), - "indexmap"); + "indexmap"); src_mvert = dm->getVertArray(dm); @@ -765,7 +766,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, if(amd->offset_type & MOD_ARR_OFF_RELATIVE) { for(j = 0; j < 3; j++) offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, - maxVerts, j); + maxVerts, j); } if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) { @@ -778,8 +779,8 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, MTC_Mat4One(obinv); MTC_Mat4MulSerie(result_mat, offset, - obinv, amd->offset_ob->obmat, - NULL, NULL, NULL, NULL, NULL); + obinv, amd->offset_ob->obmat, + NULL, NULL, NULL, NULL, NULL); MTC_Mat4CpyMat4(offset, result_mat); } @@ -796,440 +797,451 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, } /* calculate the maximum number of copies which will fit within the - prescribed length */ + prescribed length */ if(amd->fit_type == MOD_ARR_FITLENGTH - || amd->fit_type == MOD_ARR_FITCURVE) { + || amd->fit_type == MOD_ARR_FITCURVE) { float dist = sqrt(MTC_dot3Float(offset[3], offset[3])); - if(dist > FLT_EPSILON) + if(dist > 1e-6f) /* this gives length = first copy start to last copy end - add a tiny offset for floating point rounding errors */ - count = (length + FLT_EPSILON) / dist; + add a tiny offset for floating point rounding errors */ + count = (length + 1e-6f) / dist; else /* if the offset has no translation, just make one copy */ count = 1; - } + } - if(count < 1) - count = 1; + if(count < 1) + count = 1; /* allocate memory for count duplicates (including original) plus - * start and end caps - */ - finalVerts = dm->getNumVerts(dm) * count; - finalEdges = dm->getNumEdges(dm) * count; - finalFaces = dm->getNumFaces(dm) * count; - if(start_cap) { - finalVerts += start_cap->getNumVerts(start_cap); - finalEdges += start_cap->getNumEdges(start_cap); - finalFaces += start_cap->getNumFaces(start_cap); - } - if(end_cap) { - finalVerts += end_cap->getNumVerts(end_cap); - finalEdges += end_cap->getNumEdges(end_cap); - finalFaces += end_cap->getNumFaces(end_cap); - } - result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces); - - /* calculate the offset matrix of the final copy (for merging) */ - MTC_Mat4One(final_offset); - - for(j=0; j < count - 1; j++) { - MTC_Mat4MulMat4(tmp_mat, final_offset, offset); - MTC_Mat4CpyMat4(final_offset, tmp_mat); - } - - numVerts = numEdges = numFaces = 0; - mvert = CDDM_get_verts(result); - - for (i = 0; i < maxVerts; i++) { - MVert *inMV; - MVert *mv = &mvert[numVerts]; - MVert *mv2; - float co[3]; - - inMV = &src_mvert[i]; - - DM_copy_vert_data(dm, result, i, numVerts, 1); - *mv = *inMV; - numVerts++; - - indexMap[i].new = numVerts - 1; - indexMap[i].merge = -1; /* default to no merge */ - indexMap[i].merge_final = 0; /* default to no merge */ - - VECCOPY(co, mv->co); + * start and end caps + */ + finalVerts = dm->getNumVerts(dm) * count; + finalEdges = dm->getNumEdges(dm) * count; + finalFaces = dm->getNumFaces(dm) * count; + if(start_cap) { + finalVerts += start_cap->getNumVerts(start_cap); + finalEdges += start_cap->getNumEdges(start_cap); + finalFaces += start_cap->getNumFaces(start_cap); + } + if(end_cap) { + finalVerts += end_cap->getNumVerts(end_cap); + finalEdges += end_cap->getNumEdges(end_cap); + finalFaces += end_cap->getNumFaces(end_cap); + } + result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces); + + /* calculate the offset matrix of the final copy (for merging) */ + MTC_Mat4One(final_offset); + + for(j=0; j < count - 1; j++) { + MTC_Mat4MulMat4(tmp_mat, final_offset, offset); + MTC_Mat4CpyMat4(final_offset, tmp_mat); + } + + numVerts = numEdges = numFaces = 0; + mvert = CDDM_get_verts(result); + + for (i = 0; i < maxVerts; i++) { + indexMap[i].merge = -1; /* default to no merge */ + indexMap[i].merge_final = 0; /* default to no merge */ + } + + for (i = 0; i < maxVerts; i++) { + MVert *inMV; + MVert *mv = &mvert[numVerts]; + MVert *mv2; + float co[3]; + + inMV = &src_mvert[i]; + + DM_copy_vert_data(dm, result, i, numVerts, 1); + *mv = *inMV; + numVerts++; + + indexMap[i].new = numVerts - 1; + + VECCOPY(co, mv->co); /* Attempts to merge verts from one duplicate with verts from the - * next duplicate which are closer than amd->merge_dist. - * Only the first such vert pair is merged. - * If verts are merged in the first duplicate pair, they are merged - * in all pairs. - */ - if((count > 1) && (amd->flags & MOD_ARR_MERGE)) { - float tmp_co[3]; - VECCOPY(tmp_co, mv->co); - MTC_Mat4MulVecfl(offset, tmp_co); - - for(j = 0; j < maxVerts; j++) { - inMV = &src_mvert[j]; - /* if this vert is within merge limit, merge */ - if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) { - indexMap[i].merge = j; - - /* test for merging with final copy of merge target */ - if(amd->flags & MOD_ARR_MERGEFINAL) { - VECCOPY(tmp_co, inMV->co); - inMV = &src_mvert[i]; - MTC_Mat4MulVecfl(final_offset, tmp_co); - if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) - indexMap[i].merge_final = 1; - } - break; - } - } - } - - /* if no merging, generate copies of this vert */ - if(indexMap[i].merge < 0) { - for(j=0; j < count - 1; j++) { - mv2 = &mvert[numVerts]; - - DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1); - *mv2 = *mv; - numVerts++; - - MTC_Mat4MulVecfl(offset, co); - VECCOPY(mv2->co, co); - } - } else if(indexMap[i].merge != i && indexMap[i].merge_final) { + * next duplicate which are closer than amd->merge_dist. + * Only the first such vert pair is merged. + * If verts are merged in the first duplicate pair, they are merged + * in all pairs. + */ + if((count > 1) && (amd->flags & MOD_ARR_MERGE)) { + float tmp_co[3]; + VECCOPY(tmp_co, mv->co); + MTC_Mat4MulVecfl(offset, tmp_co); + + for(j = 0; j < maxVerts; j++) { + /* if vertex already merged, don't use it */ + if( indexMap[j].merge != -1 ) continue; + + inMV = &src_mvert[j]; + /* if this vert is within merge limit, merge */ + if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) { + indexMap[i].merge = j; + + /* test for merging with final copy of merge target */ + if(amd->flags & MOD_ARR_MERGEFINAL) { + VECCOPY(tmp_co, inMV->co); + inMV = &src_mvert[i]; + MTC_Mat4MulVecfl(final_offset, tmp_co); + if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) + indexMap[i].merge_final = 1; + } + break; + } + } + } + + /* if no merging, generate copies of this vert */ + if(indexMap[i].merge < 0) { + for(j=0; j < count - 1; j++) { + mv2 = &mvert[numVerts]; + + DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1); + *mv2 = *mv; + numVerts++; + + MTC_Mat4MulVecfl(offset, co); + VECCOPY(mv2->co, co); + } + } else if(indexMap[i].merge != i && indexMap[i].merge_final) { /* if this vert is not merging with itself, and it is merging - * with the final copy of its merge target, remove the first copy - */ - numVerts--; - DM_free_vert_data(result, numVerts, 1); - } - } - - /* make a hashtable so we can avoid duplicate edges from merging */ - edges = BLI_edgehash_new(); - - maxEdges = dm->getNumEdges(dm); - medge = CDDM_get_edges(result); - for(i = 0; i < maxEdges; i++) { - MEdge inMED; - MEdge med; - MEdge *med2; - int vert1, vert2; - - dm->getEdge(dm, i, &inMED); - - med = inMED; - med.v1 = indexMap[inMED.v1].new; - med.v2 = indexMap[inMED.v2].new; + * with the final copy of its merge target, remove the first copy + */ + numVerts--; + DM_free_vert_data(result, numVerts, 1); + } + } + + /* make a hashtable so we can avoid duplicate edges from merging */ + edges = BLI_edgehash_new(); + + maxEdges = dm->getNumEdges(dm); + medge = CDDM_get_edges(result); + for(i = 0; i < maxEdges; i++) { + MEdge inMED; + MEdge med; + MEdge *med2; + int vert1, vert2; + + dm->getEdge(dm, i, &inMED); + + med = inMED; + med.v1 = indexMap[inMED.v1].new; + med.v2 = indexMap[inMED.v2].new; /* if vertices are to be merged with the final copies of their - * merge targets, calculate that final copy - */ - if(indexMap[inMED.v1].merge_final) { - med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge, - count - 1); - } - if(indexMap[inMED.v2].merge_final) { - med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge, - count - 1); - } - - if (initFlags) { - med.flag |= ME_EDGEDRAW | ME_EDGERENDER; - } - - if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) { - DM_copy_edge_data(dm, result, i, numEdges, 1); - medge[numEdges] = med; - numEdges++; - - BLI_edgehash_insert(edges, med.v1, med.v2, NULL); - } - - for(j = 1; j < count; j++) - { - vert1 = calc_mapping(indexMap, inMED.v1, j); - vert2 = calc_mapping(indexMap, inMED.v2, j); - /* avoid duplicate edges */ - if(!BLI_edgehash_haskey(edges, vert1, vert2)) { - med2 = &medge[numEdges]; - - DM_copy_edge_data(dm, result, i, numEdges, 1); - *med2 = med; - numEdges++; - - med2->v1 = vert1; - med2->v2 = vert2; - - BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL); - } - } - } - - maxFaces = dm->getNumFaces(dm); - mface = CDDM_get_faces(result); - for (i=0; i < maxFaces; i++) { - MFace inMF; - MFace *mf = &mface[numFaces]; - - dm->getFace(dm, i, &inMF); - - DM_copy_face_data(dm, result, i, numFaces, 1); - *mf = inMF; - - mf->v1 = indexMap[inMF.v1].new; - mf->v2 = indexMap[inMF.v2].new; - mf->v3 = indexMap[inMF.v3].new; - if(inMF.v4) - mf->v4 = indexMap[inMF.v4].new; + * merge targets, calculate that final copy + */ + if(indexMap[inMED.v1].merge_final) { + med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge, + count - 1); + } + if(indexMap[inMED.v2].merge_final) { + med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge, + count - 1); + } + + if(med.v1 == med.v2) continue; + + if (initFlags) { + med.flag |= ME_EDGEDRAW | ME_EDGERENDER; + } + + if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) { + DM_copy_edge_data(dm, result, i, numEdges, 1); + medge[numEdges] = med; + numEdges++; + + BLI_edgehash_insert(edges, med.v1, med.v2, NULL); + } + + for(j = 1; j < count; j++) + { + vert1 = calc_mapping(indexMap, inMED.v1, j); + vert2 = calc_mapping(indexMap, inMED.v2, j); + /* avoid duplicate edges */ + if(!BLI_edgehash_haskey(edges, vert1, vert2)) { + med2 = &medge[numEdges]; + + DM_copy_edge_data(dm, result, i, numEdges, 1); + *med2 = med; + numEdges++; + + med2->v1 = vert1; + med2->v2 = vert2; + + BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL); + } + } + } + + maxFaces = dm->getNumFaces(dm); + mface = CDDM_get_faces(result); + for (i=0; i < maxFaces; i++) { + MFace inMF; + MFace *mf = &mface[numFaces]; + + dm->getFace(dm, i, &inMF); + + DM_copy_face_data(dm, result, i, numFaces, 1); + *mf = inMF; + + mf->v1 = indexMap[inMF.v1].new; + mf->v2 = indexMap[inMF.v2].new; + mf->v3 = indexMap[inMF.v3].new; + if(inMF.v4) + mf->v4 = indexMap[inMF.v4].new; /* if vertices are to be merged with the final copies of their - * merge targets, calculate that final copy - */ - if(indexMap[inMF.v1].merge_final) - mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1); - if(indexMap[inMF.v2].merge_final) - mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1); - if(indexMap[inMF.v3].merge_final) - mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1); - if(inMF.v4 && indexMap[inMF.v4].merge_final) - mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1); - - test_index_face(mf, &result->faceData, numFaces, inMF.v4?4:3); - numFaces++; - - /* if the face has fewer than 3 vertices, don't create it */ - if(mf->v3 == 0) { - numFaces--; - DM_free_face_data(result, numFaces, 1); - } - - for(j = 1; j < count; j++) - { - MFace *mf2 = &mface[numFaces]; - - DM_copy_face_data(dm, result, i, numFaces, 1); - *mf2 = *mf; - - mf2->v1 = calc_mapping(indexMap, inMF.v1, j); - mf2->v2 = calc_mapping(indexMap, inMF.v2, j); - mf2->v3 = calc_mapping(indexMap, inMF.v3, j); - if (inMF.v4) - mf2->v4 = calc_mapping(indexMap, inMF.v4, j); - - test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3); - numFaces++; - - /* if the face has fewer than 3 vertices, don't create it */ - if(mf2->v3 == 0) { - numFaces--; - DM_free_face_data(result, numFaces, 1); - } - } - } - - /* add start and end caps */ - if(start_cap) { - float startoffset[4][4]; - MVert *cap_mvert; - MEdge *cap_medge; - MFace *cap_mface; - int *origindex; - int *vert_map; - int capVerts, capEdges, capFaces; - - capVerts = start_cap->getNumVerts(start_cap); - capEdges = start_cap->getNumEdges(start_cap); - capFaces = start_cap->getNumFaces(start_cap); - cap_mvert = start_cap->getVertArray(start_cap); - cap_medge = start_cap->getEdgeArray(start_cap); - cap_mface = start_cap->getFaceArray(start_cap); - - Mat4Invert(startoffset, offset); - - vert_map = MEM_callocN(sizeof(*vert_map) * capVerts, - "arrayModifier_doArray vert_map"); - - origindex = result->getVertDataArray(result, CD_ORIGINDEX); - for(i = 0; i < capVerts; i++) { - MVert *mv = &cap_mvert[i]; - short merged = 0; - - if(amd->flags & MOD_ARR_MERGE) { - float tmp_co[3]; - MVert *in_mv; - int j; - - VECCOPY(tmp_co, mv->co); - Mat4MulVecfl(startoffset, tmp_co); - - for(j = 0; j < maxVerts; j++) { - in_mv = &src_mvert[j]; - /* if this vert is within merge limit, merge */ - if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) { - vert_map[i] = calc_mapping(indexMap, j, 0); - merged = 1; - break; - } - } - } - - if(!merged) { - DM_copy_vert_data(start_cap, result, i, numVerts, 1); - mvert[numVerts] = *mv; - Mat4MulVecfl(startoffset, mvert[numVerts].co); - origindex[numVerts] = ORIGINDEX_NONE; - - vert_map[i] = numVerts; - - numVerts++; - } - } - origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); - for(i = 0; i < capEdges; i++) { - int v1, v2; - - v1 = vert_map[cap_medge[i].v1]; - v2 = vert_map[cap_medge[i].v2]; - - if(!BLI_edgehash_haskey(edges, v1, v2)) { - DM_copy_edge_data(start_cap, result, i, numEdges, 1); - medge[numEdges] = cap_medge[i]; - medge[numEdges].v1 = v1; - medge[numEdges].v2 = v2; - origindex[numEdges] = ORIGINDEX_NONE; - - numEdges++; - } - } - origindex = result->getFaceDataArray(result, CD_ORIGINDEX); - for(i = 0; i < capFaces; i++) { - DM_copy_face_data(start_cap, result, i, numFaces, 1); - mface[numFaces] = cap_mface[i]; - mface[numFaces].v1 = vert_map[mface[numFaces].v1]; - mface[numFaces].v2 = vert_map[mface[numFaces].v2]; - mface[numFaces].v3 = vert_map[mface[numFaces].v3]; - if(mface[numFaces].v4) - mface[numFaces].v4 = vert_map[mface[numFaces].v4]; - origindex[numFaces] = ORIGINDEX_NONE; - - numFaces++; - } - - MEM_freeN(vert_map); - start_cap->release(start_cap); - } - - if(end_cap) { - float endoffset[4][4]; - MVert *cap_mvert; - MEdge *cap_medge; - MFace *cap_mface; - int *origindex; - int *vert_map; - int capVerts, capEdges, capFaces; - - capVerts = end_cap->getNumVerts(end_cap); - capEdges = end_cap->getNumEdges(end_cap); - capFaces = end_cap->getNumFaces(end_cap); - cap_mvert = end_cap->getVertArray(end_cap); - cap_medge = end_cap->getEdgeArray(end_cap); - cap_mface = end_cap->getFaceArray(end_cap); - - Mat4MulMat4(endoffset, final_offset, offset); - - vert_map = MEM_callocN(sizeof(*vert_map) * capVerts, - "arrayModifier_doArray vert_map"); - - origindex = result->getVertDataArray(result, CD_ORIGINDEX); - for(i = 0; i < capVerts; i++) { - MVert *mv = &cap_mvert[i]; - short merged = 0; - - if(amd->flags & MOD_ARR_MERGE) { - float tmp_co[3]; - MVert *in_mv; - int j; - - VECCOPY(tmp_co, mv->co); - Mat4MulVecfl(offset, tmp_co); - - for(j = 0; j < maxVerts; j++) { - in_mv = &src_mvert[j]; - /* if this vert is within merge limit, merge */ - if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) { - vert_map[i] = calc_mapping(indexMap, j, count - 1); - merged = 1; - break; - } - } - } - - if(!merged) { - DM_copy_vert_data(end_cap, result, i, numVerts, 1); - mvert[numVerts] = *mv; - Mat4MulVecfl(endoffset, mvert[numVerts].co); - origindex[numVerts] = ORIGINDEX_NONE; - - vert_map[i] = numVerts; - - numVerts++; - } - } - origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); - for(i = 0; i < capEdges; i++) { - int v1, v2; - - v1 = vert_map[cap_medge[i].v1]; - v2 = vert_map[cap_medge[i].v2]; - - if(!BLI_edgehash_haskey(edges, v1, v2)) { - DM_copy_edge_data(end_cap, result, i, numEdges, 1); - medge[numEdges] = cap_medge[i]; - medge[numEdges].v1 = v1; - medge[numEdges].v2 = v2; - origindex[numEdges] = ORIGINDEX_NONE; - - numEdges++; - } - } - origindex = result->getFaceDataArray(result, CD_ORIGINDEX); - for(i = 0; i < capFaces; i++) { - DM_copy_face_data(end_cap, result, i, numFaces, 1); - mface[numFaces] = cap_mface[i]; - mface[numFaces].v1 = vert_map[mface[numFaces].v1]; - mface[numFaces].v2 = vert_map[mface[numFaces].v2]; - mface[numFaces].v3 = vert_map[mface[numFaces].v3]; - if(mface[numFaces].v4) - mface[numFaces].v4 = vert_map[mface[numFaces].v4]; - origindex[numFaces] = ORIGINDEX_NONE; - - numFaces++; - } - - MEM_freeN(vert_map); - end_cap->release(end_cap); - } - - BLI_edgehash_free(edges, NULL); - MEM_freeN(indexMap); - - CDDM_lower_num_verts(result, numVerts); - CDDM_lower_num_edges(result, numEdges); - CDDM_lower_num_faces(result, numFaces); - - return result; + * merge targets, calculate that final copy + */ + if(indexMap[inMF.v1].merge_final) + mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1); + if(indexMap[inMF.v2].merge_final) + mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1); + if(indexMap[inMF.v3].merge_final) + mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1); + if(inMF.v4 && indexMap[inMF.v4].merge_final) + mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1); + + if(test_index_face(mf, &result->faceData, numFaces, inMF.v4?4:3) < 3) + continue; + + numFaces++; + + /* if the face has fewer than 3 vertices, don't create it */ + if(mf->v3 == 0 || (mf->v1 && (mf->v1 == mf->v3 || mf->v1 == mf->v4))) { + numFaces--; + DM_free_face_data(result, numFaces, 1); + } + + for(j = 1; j < count; j++) + { + MFace *mf2 = &mface[numFaces]; + + DM_copy_face_data(dm, result, i, numFaces, 1); + *mf2 = *mf; + + mf2->v1 = calc_mapping(indexMap, inMF.v1, j); + mf2->v2 = calc_mapping(indexMap, inMF.v2, j); + mf2->v3 = calc_mapping(indexMap, inMF.v3, j); + if (inMF.v4) + mf2->v4 = calc_mapping(indexMap, inMF.v4, j); + + test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3); + numFaces++; + + /* if the face has fewer than 3 vertices, don't create it */ + if(mf2->v3 == 0 || (mf2->v1 && (mf2->v1 == mf2->v3 || mf2->v1 == + mf2->v4))) { + numFaces--; + DM_free_face_data(result, numFaces, 1); + } + } + } + + /* add start and end caps */ + if(start_cap) { + float startoffset[4][4]; + MVert *cap_mvert; + MEdge *cap_medge; + MFace *cap_mface; + int *origindex; + int *vert_map; + int capVerts, capEdges, capFaces; + + capVerts = start_cap->getNumVerts(start_cap); + capEdges = start_cap->getNumEdges(start_cap); + capFaces = start_cap->getNumFaces(start_cap); + cap_mvert = start_cap->getVertArray(start_cap); + cap_medge = start_cap->getEdgeArray(start_cap); + cap_mface = start_cap->getFaceArray(start_cap); + + Mat4Invert(startoffset, offset); + + vert_map = MEM_callocN(sizeof(*vert_map) * capVerts, + "arrayModifier_doArray vert_map"); + + origindex = result->getVertDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capVerts; i++) { + MVert *mv = &cap_mvert[i]; + short merged = 0; + + if(amd->flags & MOD_ARR_MERGE) { + float tmp_co[3]; + MVert *in_mv; + int j; + + VECCOPY(tmp_co, mv->co); + Mat4MulVecfl(startoffset, tmp_co); + + for(j = 0; j < maxVerts; j++) { + in_mv = &src_mvert[j]; + /* if this vert is within merge limit, merge */ + if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) { + vert_map[i] = calc_mapping(indexMap, j, 0); + merged = 1; + break; + } + } + } + + if(!merged) { + DM_copy_vert_data(start_cap, result, i, numVerts, 1); + mvert[numVerts] = *mv; + Mat4MulVecfl(startoffset, mvert[numVerts].co); + origindex[numVerts] = ORIGINDEX_NONE; + + vert_map[i] = numVerts; + + numVerts++; + } + } + origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capEdges; i++) { + int v1, v2; + + v1 = vert_map[cap_medge[i].v1]; + v2 = vert_map[cap_medge[i].v2]; + + if(!BLI_edgehash_haskey(edges, v1, v2)) { + DM_copy_edge_data(start_cap, result, i, numEdges, 1); + medge[numEdges] = cap_medge[i]; + medge[numEdges].v1 = v1; + medge[numEdges].v2 = v2; + origindex[numEdges] = ORIGINDEX_NONE; + + numEdges++; + } + } + origindex = result->getFaceDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capFaces; i++) { + DM_copy_face_data(start_cap, result, i, numFaces, 1); + mface[numFaces] = cap_mface[i]; + mface[numFaces].v1 = vert_map[mface[numFaces].v1]; + mface[numFaces].v2 = vert_map[mface[numFaces].v2]; + mface[numFaces].v3 = vert_map[mface[numFaces].v3]; + if(mface[numFaces].v4) + mface[numFaces].v4 = vert_map[mface[numFaces].v4]; + origindex[numFaces] = ORIGINDEX_NONE; + + numFaces++; + } + + MEM_freeN(vert_map); + start_cap->release(start_cap); + } + + if(end_cap) { + float endoffset[4][4]; + MVert *cap_mvert; + MEdge *cap_medge; + MFace *cap_mface; + int *origindex; + int *vert_map; + int capVerts, capEdges, capFaces; + + capVerts = end_cap->getNumVerts(end_cap); + capEdges = end_cap->getNumEdges(end_cap); + capFaces = end_cap->getNumFaces(end_cap); + cap_mvert = end_cap->getVertArray(end_cap); + cap_medge = end_cap->getEdgeArray(end_cap); + cap_mface = end_cap->getFaceArray(end_cap); + + Mat4MulMat4(endoffset, final_offset, offset); + + vert_map = MEM_callocN(sizeof(*vert_map) * capVerts, + "arrayModifier_doArray vert_map"); + + origindex = result->getVertDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capVerts; i++) { + MVert *mv = &cap_mvert[i]; + short merged = 0; + + if(amd->flags & MOD_ARR_MERGE) { + float tmp_co[3]; + MVert *in_mv; + int j; + + VECCOPY(tmp_co, mv->co); + Mat4MulVecfl(offset, tmp_co); + + for(j = 0; j < maxVerts; j++) { + in_mv = &src_mvert[j]; + /* if this vert is within merge limit, merge */ + if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) { + vert_map[i] = calc_mapping(indexMap, j, count - 1); + merged = 1; + break; + } + } + } + + if(!merged) { + DM_copy_vert_data(end_cap, result, i, numVerts, 1); + mvert[numVerts] = *mv; + Mat4MulVecfl(endoffset, mvert[numVerts].co); + origindex[numVerts] = ORIGINDEX_NONE; + + vert_map[i] = numVerts; + + numVerts++; + } + } + origindex = result->getEdgeDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capEdges; i++) { + int v1, v2; + + v1 = vert_map[cap_medge[i].v1]; + v2 = vert_map[cap_medge[i].v2]; + + if(!BLI_edgehash_haskey(edges, v1, v2)) { + DM_copy_edge_data(end_cap, result, i, numEdges, 1); + medge[numEdges] = cap_medge[i]; + medge[numEdges].v1 = v1; + medge[numEdges].v2 = v2; + origindex[numEdges] = ORIGINDEX_NONE; + + numEdges++; + } + } + origindex = result->getFaceDataArray(result, CD_ORIGINDEX); + for(i = 0; i < capFaces; i++) { + DM_copy_face_data(end_cap, result, i, numFaces, 1); + mface[numFaces] = cap_mface[i]; + mface[numFaces].v1 = vert_map[mface[numFaces].v1]; + mface[numFaces].v2 = vert_map[mface[numFaces].v2]; + mface[numFaces].v3 = vert_map[mface[numFaces].v3]; + if(mface[numFaces].v4) + mface[numFaces].v4 = vert_map[mface[numFaces].v4]; + origindex[numFaces] = ORIGINDEX_NONE; + + numFaces++; + } + + MEM_freeN(vert_map); + end_cap->release(end_cap); + } + + BLI_edgehash_free(edges, NULL); + MEM_freeN(indexMap); + + CDDM_lower_num_verts(result, numVerts); + CDDM_lower_num_edges(result, numEdges); + CDDM_lower_num_faces(result, numFaces); + + return result; } static DerivedMesh *arrayModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *result; ArrayModifierData *amd = (ArrayModifierData*) md; @@ -1242,8 +1254,8 @@ static DerivedMesh *arrayModifier_applyModifier( } static DerivedMesh *arrayModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { return arrayModifier_applyModifier(md, ob, derivedData, 0, 1); } @@ -1271,9 +1283,9 @@ static void mirrorModifier_copyData(ModifierData *md, ModifierData *target) } static void mirrorModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { MirrorModifierData *mmd = (MirrorModifierData*) md; @@ -1281,7 +1293,7 @@ static void mirrorModifier_foreachObjectLink( } static void mirrorModifier_updateDepgraph(ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + Object *ob, DagNode *obNode) { MirrorModifierData *mmd = (MirrorModifierData*) md; @@ -1289,15 +1301,15 @@ static void mirrorModifier_updateDepgraph(ModifierData *md, DagForest *forest, DagNode *latNode = dag_get_node(forest, mmd->mirror_ob); dag_add_relation(forest, latNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Mirror Modifier"); } } static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, - Object *ob, - DerivedMesh *dm, - int initFlags, - int axis) + Object *ob, + DerivedMesh *dm, + int initFlags, + int axis) { int i; float tolerance = mmd->tolerance; @@ -1339,9 +1351,9 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, isShared = ABS(co[axis])<=tolerance; /* Because the topology result (# of vertices) must be the same if - * the mesh data is overridden by vertex cos, have to calc sharedness - * based on original coordinates. This is why we test before copy. - */ + * the mesh data is overridden by vertex cos, have to calc sharedness + * based on original coordinates. This is why we test before copy. + */ DM_copy_vert_data(dm, result, i, numVerts, 1); *mv = inMV; numVerts++; @@ -1415,9 +1427,9 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, mf->v4 = indexMap[inMF.v4][0]; if(indexMap[inMF.v1][1] - || indexMap[inMF.v2][1] - || indexMap[inMF.v3][1] - || (mf->v4 && indexMap[inMF.v4][1])) { + || indexMap[inMF.v2][1] + || indexMap[inMF.v3][1] + || (mf->v4 && indexMap[inMF.v4][1])) { MFace *mf2 = CDDM_get_face(result, numFaces); static int corner_indices[4] = {2, 1, 0, 3}; @@ -1449,7 +1461,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3); numFaces++; - } + } } MEM_freeN(indexMap); @@ -1462,8 +1474,8 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, } static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd, - Object *ob, DerivedMesh *dm, - int initFlags) + Object *ob, DerivedMesh *dm, + int initFlags) { DerivedMesh *result = dm; @@ -1486,22 +1498,23 @@ static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd, } static DerivedMesh *mirrorModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *result; MirrorModifierData *mmd = (MirrorModifierData*) md; result = mirrorModifier__doMirror(mmd, ob, derivedData, 0); - CDDM_calc_normals(result); + if(result != derivedData) + CDDM_calc_normals(result); return result; } static DerivedMesh *mirrorModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { return mirrorModifier_applyModifier(md, ob, derivedData, 0, 1); } @@ -1624,15 +1637,15 @@ static int smoothedge_has_vert(SmoothEdge *edge, SmoothVert *vert) } static SmoothMesh *smoothmesh_new(int num_verts, int num_edges, int num_faces, - int max_verts, int max_edges, int max_faces) + int max_verts, int max_edges, int max_faces) { SmoothMesh *mesh = MEM_callocN(sizeof(*mesh), "smoothmesh"); mesh->verts = MEM_callocN(sizeof(*mesh->verts) * max_verts, - "SmoothMesh.verts"); + "SmoothMesh.verts"); mesh->edges = MEM_callocN(sizeof(*mesh->edges) * max_edges, - "SmoothMesh.edges"); + "SmoothMesh.edges"); mesh->faces = MEM_callocN(sizeof(*mesh->faces) * max_faces, - "SmoothMesh.faces"); + "SmoothMesh.faces"); mesh->num_verts = num_verts; mesh->num_edges = num_edges; @@ -1731,7 +1744,7 @@ static void smoothmesh_print(SmoothMesh *mesh) printf("%3d: ind={%3d, %3d}, pos={% 5.1f, % 5.1f, % 5.1f}", i, vert->oldIndex, vert->newIndex, - mv.co[0], mv.co[1], mv.co[2]); + mv.co[0], mv.co[1], mv.co[2]); printf(", faces={"); for(node = vert->faces; node != NULL; node = node->next) { printf(" %d", ((SmoothFace *)node->link)->newIndex); @@ -1746,8 +1759,8 @@ static void smoothmesh_print(SmoothMesh *mesh) printf("%4d: indices={%4d, %4d}, verts={%4d, %4d}", i, - edge->oldIndex, edge->newIndex, - edge->verts[0]->newIndex, edge->verts[1]->newIndex); + edge->oldIndex, edge->newIndex, + edge->verts[0]->newIndex, edge->verts[1]->newIndex); if(edge->verts[0] == edge->verts[1]) printf(" <- DUPLICATE VERTEX"); printf(", faces={"); for(node = edge->faces; node != NULL; node = node->next) { @@ -1789,7 +1802,7 @@ static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm) totface = dm->getNumFaces(dm); mesh = smoothmesh_new(totvert, totedge, totface, - totvert, totedge, totface); + totvert, totedge, totface); mesh->dm = dm; @@ -1859,9 +1872,9 @@ static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm) static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) { DerivedMesh *result = CDDM_from_template(mesh->dm, - mesh->num_verts, - mesh->num_edges, - mesh->num_faces); + mesh->num_verts, + mesh->num_edges, + mesh->num_faces); MVert *new_verts = CDDM_get_verts(result); MEdge *new_edges = CDDM_get_edges(result); MFace *new_faces = CDDM_get_faces(result); @@ -1872,7 +1885,7 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) MVert *newMV = &new_verts[vert->newIndex]; DM_copy_vert_data(mesh->dm, result, - vert->oldIndex, vert->newIndex, 1); + vert->oldIndex, vert->newIndex, 1); mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV); } @@ -1881,7 +1894,7 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) MEdge *newME = &new_edges[edge->newIndex]; DM_copy_edge_data(mesh->dm, result, - edge->oldIndex, edge->newIndex, 1); + edge->oldIndex, edge->newIndex, 1); mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME); newME->v1 = edge->verts[0]->newIndex; newME->v2 = edge->verts[1]->newIndex; @@ -1892,7 +1905,7 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) MFace *newMF = &new_faces[face->newIndex]; DM_copy_face_data(mesh->dm, result, - face->oldIndex, face->newIndex, 1); + face->oldIndex, face->newIndex, 1); mesh->dm->getFace(mesh->dm, face->oldIndex, newMF); newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex; @@ -1922,7 +1935,7 @@ static SmoothVert *other_vert(SmoothEdge *edge, SmoothVert *vert) * (this should never happen) */ static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert, - SmoothEdge *edge) + SmoothEdge *edge) { int i,j; for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) { @@ -1934,8 +1947,8 @@ static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert, } /* if we get to here, something's wrong (there should always be 2 edges - * which use the same vert in a face) - */ + * which use the same vert in a face) + */ return NULL; } @@ -1964,18 +1977,18 @@ static void linklist_copy(LinkNode **target, LinkNode *source) for(; source; source = source->next) { if(node) { node->next = MEM_mallocN(sizeof(*node->next), "nlink_copy"); - node = node->next; - } else { - node = *target = MEM_mallocN(sizeof(**target), "nlink_copy"); - } - node->link = source->link; - node->next = NULL; - } + node = node->next; +} else { + node = *target = MEM_mallocN(sizeof(**target), "nlink_copy"); +} + node->link = source->link; + node->next = NULL; +} } #endif -/* appends source to target if it's not already in target */ -static void linklist_append_unique(LinkNode **target, void *source) + /* appends source to target if it's not already in target */ + static void linklist_append_unique(LinkNode **target, void *source) { LinkNode *node; LinkNode *prev = NULL; @@ -2009,7 +2022,7 @@ static void linklist_prepend_linklist(LinkNode **list, LinkNode *prepend) node->next = *list; *list = prepend; - } +} } #endif @@ -2052,7 +2065,7 @@ static void linklist_empty(LinkNode **list, LinkNodeFreeFP freefunc) * frees the pointer with freefunc if freefunc is not NULL */ static void linklist_remove_first(LinkNode **list, void *value, - LinkNodeFreeFP freefunc) + LinkNodeFreeFP freefunc) { LinkNode *node = *list; LinkNode *prev = NULL; @@ -2077,7 +2090,7 @@ static void linklist_remove_first(LinkNode **list, void *value, /* removes all elements in source from target */ static void linklist_remove_list(LinkNode **target, LinkNode *source, - LinkNodeFreeFP freefunc) + LinkNodeFreeFP freefunc) { for(; source; source = source->next) linklist_remove_first(target, source->link, freefunc); @@ -2152,15 +2165,15 @@ static void face_replace_edge(void *ptr, void *userdata) #ifdef EDGESPLIT_DEBUG_3 printf("replacing edge %4d with %4d in face %4d", - find->newIndex, replace->newIndex, face->newIndex); + find->newIndex, replace->newIndex, face->newIndex); if(face->edges[3]) printf(": {%2d %2d %2d %2d}", face->edges[0]->newIndex, face->edges[1]->newIndex, - face->edges[2]->newIndex, face->edges[3]->newIndex); + face->edges[2]->newIndex, face->edges[3]->newIndex); else printf(": {%2d %2d %2d}", face->edges[0]->newIndex, face->edges[1]->newIndex, - face->edges[2]->newIndex); + face->edges[2]->newIndex); #endif for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) { @@ -2175,11 +2188,11 @@ static void face_replace_edge(void *ptr, void *userdata) if(face->edges[3]) printf(" -> {%2d %2d %2d %2d}\n", face->edges[0]->newIndex, face->edges[1]->newIndex, - face->edges[2]->newIndex, face->edges[3]->newIndex); + face->edges[2]->newIndex, face->edges[3]->newIndex); else printf(" -> {%2d %2d %2d}\n", face->edges[0]->newIndex, face->edges[1]->newIndex, - face->edges[2]->newIndex); + face->edges[2]->newIndex); #endif } @@ -2189,7 +2202,7 @@ static int edge_is_loose(SmoothEdge *edge) } static int edge_is_sharp(SmoothEdge *edge, int flags, - float threshold) + float threshold) { #ifdef EDGESPLIT_DEBUG_1 printf("edge %d: ", edge->newIndex); @@ -2220,7 +2233,7 @@ static int edge_is_sharp(SmoothEdge *edge, int flags, * - returns to the start edge (NULL is returned) */ static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge, - LinkNode **visited_faces, float threshold, int flags) + LinkNode **visited_faces, float threshold, int flags) { SmoothFace *face = NULL; SmoothEdge *edge2 = NULL; @@ -2246,10 +2259,10 @@ static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge, BLI_linklist_prepend(visited_faces, face); /* search until we hit a loose edge or a sharp edge or an edge we've - * seen before - */ + * seen before + */ while(face && !edge_is_sharp(edge2, flags, threshold) - && !linklist_contains(visited_edges, edge2)) { + && !linklist_contains(visited_edges, edge2)) { #ifdef EDGESPLIT_DEBUG_3 printf("current face %4d; current edge %4d\n", face->newIndex, edge2->newIndex); @@ -2275,25 +2288,25 @@ static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge, printf("loose edge: %4d\n", edge2->newIndex); #endif } - } + } - /* either we came back to the start edge or we found a sharp/loose edge */ - if(linklist_contains(visited_edges, edge2)) - /* we came back to the start edge */ - edge2 = NULL; + /* either we came back to the start edge or we found a sharp/loose edge */ + if(linklist_contains(visited_edges, edge2)) + /* we came back to the start edge */ + edge2 = NULL; - BLI_linklist_free(visited_edges, NULL); + BLI_linklist_free(visited_edges, NULL); #ifdef EDGESPLIT_DEBUG_1 - printf("=== END === find_other_sharp_edge(edge = %4d, vert = %4d), " - "returning edge %d\n", - edge->newIndex, vert->newIndex, edge2 ? edge2->newIndex : -1); + printf("=== END === find_other_sharp_edge(edge = %4d, vert = %4d), " + "returning edge %d\n", + edge->newIndex, vert->newIndex, edge2 ? edge2->newIndex : -1); #endif - return edge2; + return edge2; } static void split_single_vert(SmoothVert *vert, SmoothFace *face, - SmoothMesh *mesh) + SmoothMesh *mesh) { SmoothVert *copy_vert; ReplaceData repdata; @@ -2308,7 +2321,7 @@ static void split_single_vert(SmoothVert *vert, SmoothFace *face, static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh); static void propagate_split(SmoothEdge *edge, SmoothVert *vert, - SmoothMesh *mesh) + SmoothMesh *mesh) { SmoothEdge *edge2; LinkNode *visited_faces = NULL; @@ -2318,7 +2331,7 @@ static void propagate_split(SmoothEdge *edge, SmoothVert *vert, #endif edge2 = find_other_sharp_edge(vert, edge, &visited_faces, - mesh->threshold, mesh->flags); + mesh->threshold, mesh->flags); if(!edge2) { /* didn't find a sharp or loose edge, so we've hit a dead end */ @@ -2377,7 +2390,7 @@ static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh) #endif edge2 = find_other_sharp_edge(vert, edge, &visited_faces, - mesh->threshold, mesh->flags); + mesh->threshold, mesh->flags); if(!edge2) { /* didn't find a sharp or loose edge, so try the other vert */ @@ -2402,15 +2415,15 @@ static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh) vert2 = smoothvert_copy(vert, mesh); /* replace vert with its copy in visited_faces (must be done after - * edge replacement so edges have correct vertices) - */ + * edge replacement so edges have correct vertices) + */ repdata.find = vert; repdata.replace = vert2; BLI_linklist_apply(visited_faces, face_replace_vert, &repdata); /* all copying and replacing is done; the mesh should be consistent. - * now propagate the split to the vertices at either end - */ + * now propagate the split to the vertices at either end + */ propagate_split(copy_edge, other_vert(copy_edge, vert2), mesh); propagate_split(copy_edge2, other_vert(copy_edge2, vert2), mesh); @@ -2429,15 +2442,15 @@ static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh) vert2 = smoothvert_copy(vert, mesh); /* replace vert with its copy in visited_faces (must be done after - * edge replacement so edges have correct vertices) - */ + * edge replacement so edges have correct vertices) + */ repdata.find = vert; repdata.replace = vert2; BLI_linklist_apply(visited_faces, face_replace_vert, &repdata); /* copying and replacing is done; the mesh should be consistent. - * now propagate the split to the vertex at the other end - */ + * now propagate the split to the vertex at the other end + */ propagate_split(copy_edge, other_vert(copy_edge, vert2), mesh); if(smoothedge_has_vert(edge, vert)) @@ -2452,7 +2465,7 @@ static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh) } static void tag_and_count_extra_edges(SmoothMesh *mesh, float split_angle, - int flags, int *extra_edges) + int flags, int *extra_edges) { /* if normal1 dot normal2 < threshold, angle is greater, so split */ /* FIXME not sure if this always works */ @@ -2479,35 +2492,35 @@ static void tag_and_count_extra_edges(SmoothMesh *mesh, float split_angle, for(node = edge->faces->next->next->next; node; node = node->next) (*extra_edges)++; } else if((flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG)) - && !edge_is_loose(edge)) { + && !edge_is_loose(edge)) { /* (the edge can only be sharp if we're checking angle or flag, - * and it has at least 2 faces) */ + * and it has at least 2 faces) */ - /* if we're checking the sharp flag and it's set, good */ - if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP)) { - /* this edge is sharp */ - sharp = 1; + /* if we're checking the sharp flag and it's set, good */ + if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP)) { + /* this edge is sharp */ + sharp = 1; - (*extra_edges)++; - } else if(flags & MOD_EDGESPLIT_FROMANGLE) { - /* we know the edge has 2 faces, so check the angle */ - SmoothFace *face1 = edge->faces->link; - SmoothFace *face2 = edge->faces->next->link; - float edge_angle_cos = MTC_dot3Float(face1->normal, - face2->normal); - - if(edge_angle_cos < threshold) { - /* this edge is sharp */ - sharp = 1; - - (*extra_edges)++; - } - } - } + (*extra_edges)++; + } else if(flags & MOD_EDGESPLIT_FROMANGLE) { + /* we know the edge has 2 faces, so check the angle */ + SmoothFace *face1 = edge->faces->link; + SmoothFace *face2 = edge->faces->next->link; + float edge_angle_cos = MTC_dot3Float(face1->normal, + face2->normal); + + if(edge_angle_cos < threshold) { + /* this edge is sharp */ + sharp = 1; - /* set/clear sharp flag appropriately */ - if(sharp) edge->flag |= ME_SHARP; - else edge->flag &= ~ME_SHARP; + (*extra_edges)++; + } + } + } + + /* set/clear sharp flag appropriately */ + if(sharp) edge->flag |= ME_SHARP; + else edge->flag &= ~ME_SHARP; } } @@ -2550,19 +2563,19 @@ static int count_bridge_verts(SmoothMesh *mesh) next_edge = face->edges[next]; /* if there are other faces sharing this vertex but not - * these edges, the vertex will be split, so count it - */ + * these edges, the vertex will be split, so count it + */ /* vert has to have at least one face (this one), so faces != 0 */ if(!edge->faces->next && !next_edge->faces->next - && vert->faces->next) { + && vert->faces->next) { count++; - } + } } } /* each bridge vert will be counted once per face that uses it, - * so count is too high, but it's ok for now - */ + * so count is too high, but it's ok for now + */ return count; } @@ -2585,21 +2598,21 @@ static void split_bridge_verts(SmoothMesh *mesh) next_edge = face->edges[next]; /* if there are other faces sharing this vertex but not - * these edges, split the vertex - */ + * these edges, split the vertex + */ /* vert has to have at least one face (this one), so faces != 0 */ if(!edge->faces->next && !next_edge->faces->next - && vert->faces->next) + && vert->faces->next) /* FIXME this needs to find all faces that share edges with - * this one and split off together - */ + * this one and split off together + */ split_single_vert(vert, face, mesh); } } } static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd, - Object *ob, DerivedMesh *dm) + Object *ob, DerivedMesh *dm) { SmoothMesh *mesh; DerivedMesh *result; @@ -2642,8 +2655,8 @@ static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd, #ifdef EDGESPLIT_DEBUG_0 printf("Edgesplit: Estimated %d verts & %d edges, " - "found %d verts & %d edges\n", max_verts, max_edges, - mesh->num_verts, mesh->num_edges); + "found %d verts & %d edges\n", max_verts, max_edges, + mesh->num_verts, mesh->num_edges); #endif result = CDDM_from_smoothmesh(mesh); @@ -2653,8 +2666,8 @@ static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd, } static DerivedMesh *edgesplitModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *result; EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md; @@ -2667,12 +2680,96 @@ static DerivedMesh *edgesplitModifier_applyModifier( } static DerivedMesh *edgesplitModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1); } +/* Bevel */ + +static void bevelModifier_initData(ModifierData *md) +{ + BevelModifierData *bmd = (BevelModifierData*) md; + + bmd->value = 0.1f; + bmd->res = 1; + bmd->flags = 0; + bmd->val_flags = 0; + bmd->lim_flags = 0; + bmd->e_flags = 0; + bmd->bevel_angle = 30; + bmd->defgrp_name[0] = '\0'; +} + +static void bevelModifier_copyData(ModifierData *md, ModifierData *target) +{ + BevelModifierData *bmd = (BevelModifierData*) md; + BevelModifierData *tbmd = (BevelModifierData*) target; + + tbmd->value = bmd->value; + tbmd->res = bmd->res; + tbmd->flags = bmd->flags; + tbmd->val_flags = bmd->val_flags; + tbmd->lim_flags = bmd->lim_flags; + tbmd->e_flags = bmd->e_flags; + tbmd->bevel_angle = bmd->bevel_angle; + strncpy(tbmd->defgrp_name, bmd->defgrp_name, 32); +} + +CustomDataMask bevelModifier_requiredDataMask(ModifierData *md) +{ + BevelModifierData *bmd = (BevelModifierData *)md; + CustomDataMask dataMask = 0; + + /* ask for vertexgroups if we need them */ + if(bmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT); + + return dataMask; +} + +static DerivedMesh *bevelModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + BME_Mesh *bm; + /*bDeformGroup *def;*/ + int /*i,*/ options, defgrp_index = -1; + BevelModifierData *bmd = (BevelModifierData*) md; + + options = bmd->flags|bmd->val_flags|bmd->lim_flags|bmd->e_flags; + + //~ if ((options & BME_BEVEL_VWEIGHT) && bmd->defgrp_name[0]) { + //~ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) { + //~ if (!strcmp(def->name, bmd->defgrp_name)) { + //~ defgrp_index = i; + //~ break; + //~ } + //~ } + //~ if (defgrp_index < 0) { + //~ options &= ~BME_BEVEL_VWEIGHT; + //~ } + //~ } + + bm = BME_make_mesh(); + bm = BME_derivedmesh_to_bmesh(derivedData, bm); + BME_bevel(bm,bmd->value,bmd->res,options,defgrp_index,bmd->bevel_angle,NULL); + result = BME_bmesh_to_derivedmesh(bm,derivedData); + BME_free_mesh(bm); + + CDDM_calc_normals(result); + + return result; +} + +static DerivedMesh *bevelModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return bevelModifier_applyModifier(md, ob, derivedData, 0, 1); +} + /* Displace */ static void displaceModifier_initData(ModifierData *md) @@ -2715,7 +2812,7 @@ CustomDataMask displaceModifier_requiredDataMask(ModifierData *md) } static void displaceModifier_foreachObjectLink(ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) + ObjectWalkFunc walk, void *userData) { DisplaceModifierData *dmd = (DisplaceModifierData*) md; @@ -2723,7 +2820,7 @@ static void displaceModifier_foreachObjectLink(ModifierData *md, Object *ob, } static void displaceModifier_foreachIDLink(ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) + IDWalkFunc walk, void *userData) { DisplaceModifierData *dmd = (DisplaceModifierData*) md; @@ -2740,8 +2837,8 @@ static int displaceModifier_isDisabled(ModifierData *md) } static void displaceModifier_updateDepgraph( - ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) { DisplaceModifierData *dmd = (DisplaceModifierData*) md; @@ -2749,7 +2846,7 @@ static void displaceModifier_updateDepgraph( DagNode *curNode = dag_get_node(forest, dmd->map_object); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier"); } } @@ -2763,17 +2860,17 @@ static void validate_layer_name(const CustomData *data, int type, char *name) if(index < 0) { /* either no layer was specified, or the layer we want has been - * deleted, so assign the active layer to name - */ + * deleted, so assign the active layer to name + */ index = CustomData_get_active_layer_index(data, CD_MTFACE); strcpy(name, data->layers[index].name); } } static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, - DerivedMesh *dm, - float (*co)[3], float (*texco)[3], - int numVerts) + DerivedMesh *dm, + float (*co)[3], float (*texco)[3], + int numVerts) { int i; int texmapping = dmd->texmapping; @@ -2791,14 +2888,14 @@ static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, MFace *mface = dm->getFaceArray(dm); MFace *mf; char *done = MEM_callocN(sizeof(*done) * numVerts, - "get_texture_coords done"); + "get_texture_coords done"); int numFaces = dm->getNumFaces(dm); MTFace *tf; validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name); tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, - dmd->uvlayer_name); + dmd->uvlayer_name); /* verts are given the UV from the first face that uses them */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { @@ -2842,18 +2939,18 @@ static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, for(i = 0; i < numVerts; ++i, ++co, ++texco) { switch(texmapping) { - case MOD_DISP_MAP_LOCAL: - VECCOPY(*texco, *co); - break; - case MOD_DISP_MAP_GLOBAL: - VECCOPY(*texco, *co); - Mat4MulVecfl(ob->obmat, *texco); - break; - case MOD_DISP_MAP_OBJECT: - VECCOPY(*texco, *co); - Mat4MulVecfl(ob->obmat, *texco); - Mat4MulVecfl(dmd->map_object->imat, *texco); - break; + case MOD_DISP_MAP_LOCAL: + VECCOPY(*texco, *co); + break; + case MOD_DISP_MAP_GLOBAL: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + break; + case MOD_DISP_MAP_OBJECT: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + Mat4MulVecfl(dmd->map_object->imat, *texco); + break; } } } @@ -2863,23 +2960,23 @@ static void get_texture_value(Tex *texture, float *tex_co, TexResult *texres) int result_type; result_type = multitex_ext(texture, tex_co, NULL, - NULL, 1, texres); + NULL, 1, texres); /* if the texture gave an RGB value, we assume it didn't give a valid - * intensity, so calculate one (formula from do_material_tex). - * if the texture didn't give an RGB value, copy the intensity across - */ + * intensity, so calculate one (formula from do_material_tex). + * if the texture didn't give an RGB value, copy the intensity across + */ if(result_type & TEX_RGB) texres->tin = (0.35 * texres->tr + 0.45 * texres->tg - + 0.2 * texres->tb); + + 0.2 * texres->tb); else texres->tr = texres->tg = texres->tb = texres->tin; } /* dm must be a CDDerivedMesh */ static void displaceModifier_do( - DisplaceModifierData *dmd, Object *ob, - DerivedMesh *dm, float (*vertexCos)[3], int numVerts) + DisplaceModifierData *dmd, Object *ob, + DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { int i; MVert *mvert; @@ -2906,7 +3003,7 @@ static void displaceModifier_do( dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, - "displaceModifier_do tex_co"); + "displaceModifier_do tex_co"); get_texture_coords(dmd, ob, dm, vertexCos, tex_co, numVerts); for(i = 0; i < numVerts; ++i) { @@ -2935,25 +3032,25 @@ static void displaceModifier_do( delta *= strength; switch(dmd->direction) { - case MOD_DISP_DIR_X: - vertexCos[i][0] += delta; - break; - case MOD_DISP_DIR_Y: - vertexCos[i][1] += delta; - break; - case MOD_DISP_DIR_Z: - vertexCos[i][2] += delta; - break; - case MOD_DISP_DIR_RGB_XYZ: - vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength; - vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength; - vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength; - break; - case MOD_DISP_DIR_NOR: - vertexCos[i][0] += delta * mvert[i].no[0] / 32767.0f; - vertexCos[i][1] += delta * mvert[i].no[1] / 32767.0f; - vertexCos[i][2] += delta * mvert[i].no[2] / 32767.0f; - break; + case MOD_DISP_DIR_X: + vertexCos[i][0] += delta; + break; + case MOD_DISP_DIR_Y: + vertexCos[i][1] += delta; + break; + case MOD_DISP_DIR_Z: + vertexCos[i][2] += delta; + break; + case MOD_DISP_DIR_RGB_XYZ: + vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength; + vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength; + vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength; + break; + case MOD_DISP_DIR_NOR: + vertexCos[i][0] += delta * mvert[i].no[0] / 32767.0f; + vertexCos[i][1] += delta * mvert[i].no[1] / 32767.0f; + vertexCos[i][2] += delta * mvert[i].no[2] / 32767.0f; + break; } } @@ -2961,8 +3058,8 @@ static void displaceModifier_do( } static void displaceModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; @@ -2974,14 +3071,14 @@ static void displaceModifier_deformVerts( CDDM_calc_normals(dm); displaceModifier_do((DisplaceModifierData *)md, ob, dm, - vertexCos, numVerts); + vertexCos, numVerts); dm->release(dm); } static void displaceModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; @@ -2992,7 +3089,7 @@ static void displaceModifier_deformVertsEM( CDDM_calc_normals(dm); displaceModifier_do((DisplaceModifierData *)md, ob, dm, - vertexCos, numVerts); + vertexCos, numVerts); dm->release(dm); } @@ -3040,7 +3137,7 @@ CustomDataMask uvprojectModifier_requiredDataMask(ModifierData *md) } static void uvprojectModifier_foreachObjectLink(ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) + ObjectWalkFunc walk, void *userData) { UVProjectModifierData *umd = (UVProjectModifierData*) md; int i; @@ -3050,18 +3147,18 @@ static void uvprojectModifier_foreachObjectLink(ModifierData *md, Object *ob, } static void uvprojectModifier_foreachIDLink(ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) + IDWalkFunc walk, void *userData) { UVProjectModifierData *umd = (UVProjectModifierData*) md; walk(userData, ob, (ID **)&umd->image); uvprojectModifier_foreachObjectLink(md, ob, (ObjectWalkFunc)walk, - userData); + userData); } static void uvprojectModifier_updateDepgraph(ModifierData *md, - DagForest *forest, Object *ob, DagNode *obNode) + DagForest *forest, Object *ob, DagNode *obNode) { UVProjectModifierData *umd = (UVProjectModifierData*) md; int i; @@ -3071,7 +3168,7 @@ static void uvprojectModifier_updateDepgraph(ModifierData *md, DagNode *curNode = dag_get_node(forest, umd->projectors[i]); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "UV Project Modifier"); } } } @@ -3083,7 +3180,7 @@ typedef struct Projector { } Projector; static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, - Object *ob, DerivedMesh *dm) + Object *ob, DerivedMesh *dm) { float (*coords)[3], (*co)[3]; MTFace *tface; @@ -3112,13 +3209,13 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, /* make sure we are not modifying the original UV layer */ tface = CustomData_duplicate_referenced_layer_named(&dm->faceData, - CD_MTFACE, - umd->uvlayer_name); + CD_MTFACE, + umd->uvlayer_name); numVerts = dm->getNumVerts(dm); coords = MEM_callocN(sizeof(*coords) * numVerts, - "uvprojectModifier_do coords"); + "uvprojectModifier_do coords"); dm->getVertCos(dm, coords); /* convert coords to world space */ @@ -3129,12 +3226,12 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, for(i = 0; i < num_projectors; ++i) { float tmpmat[4][4]; float offsetmat[4][4]; - + Camera *cam = NULL; /* calculate projection matrix */ Mat4Invert(projectors[i].projmat, projectors[i].ob->obmat); if(projectors[i].ob->type == OB_CAMERA) { - Camera *cam = (Camera *)projectors[i].ob->data; + cam = (Camera *)projectors[i].ob->data; if(cam->type == CAM_PERSP) { float perspmat[4][4]; float xmax; @@ -3154,7 +3251,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, ymin = -ymax; i_window(xmin, xmax, ymin, ymax, - cam->clipsta, cam->clipend, perspmat); + cam->clipsta, cam->clipend, perspmat); Mat4MulMat4(tmpmat, projectors[i].projmat, perspmat); } else if(cam->type == CAM_ORTHO) { float orthomat[4][4]; @@ -3174,7 +3271,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, ymin = -ymax; i_ortho(xmin, xmax, ymin, ymax, - cam->clipsta, cam->clipend, orthomat); + cam->clipsta, cam->clipend, orthomat); Mat4MulMat4(tmpmat, projectors[i].projmat, orthomat); } } else { @@ -3184,6 +3281,20 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, Mat4One(offsetmat); Mat4MulFloat3(offsetmat[0], 0.5); offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5; + + if (cam) { + if (umd->aspectx == umd->aspecty) { + offsetmat[3][0] -= cam->shiftx; + offsetmat[3][1] -= cam->shifty; + } else if (umd->aspectx < umd->aspecty) { + offsetmat[3][0] -=(cam->shiftx * umd->aspecty/umd->aspectx); + offsetmat[3][1] -= cam->shifty; + } else { + offsetmat[3][0] -= cam->shiftx; + offsetmat[3][1] -=(cam->shifty * umd->aspectx/umd->aspecty); + } + } + Mat4MulMat4(projectors[i].projmat, tmpmat, offsetmat); /* calculate worldspace projector normal (for best projector test) */ @@ -3218,8 +3329,8 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, } } else { /* multiple projectors, select the closest to face normal - * direction - */ + * direction + */ float co1[3], co2[3], co3[3], co4[3]; float face_no[3]; int j; @@ -3239,14 +3350,14 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, } /* find the projector which the face points at most directly - * (projector normal with largest dot product is best) - */ + * (projector normal with largest dot product is best) + */ best_dot = MTC_dot3Float(projectors[0].normal, face_no); best_projector = &projectors[0]; for(j = 1; j < num_projectors; ++j) { float tmp_dot = MTC_dot3Float(projectors[j].normal, - face_no); + face_no); if(tmp_dot > best_dot) { best_dot = tmp_dot; best_projector = &projectors[j]; @@ -3285,8 +3396,8 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, } static DerivedMesh *uvprojectModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *result; UVProjectModifierData *umd = (UVProjectModifierData*) md; @@ -3297,8 +3408,8 @@ static DerivedMesh *uvprojectModifier_applyModifier( } static DerivedMesh *uvprojectModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { return uvprojectModifier_applyModifier(md, ob, derivedData, 0, 1); } @@ -3321,8 +3432,8 @@ static void decimateModifier_copyData(ModifierData *md, ModifierData *target) } static DerivedMesh *decimateModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DecimateModifierData *dmd = (DecimateModifierData*) md; DerivedMesh *dm = derivedData, *result = NULL; @@ -3346,7 +3457,7 @@ static DerivedMesh *decimateModifier_applyModifier( if(numTris<3) { modifier_setError(md, - "There must be more than 3 input faces (triangles)."); + "Modifier requires more than 3 input faces (triangles)."); goto exit; } @@ -3436,7 +3547,7 @@ static DerivedMesh *decimateModifier_applyModifier( MEM_freeN(lod.triangle_index_buffer); exit: - return result; + return result; } /* Smooth */ @@ -3487,8 +3598,8 @@ CustomDataMask smoothModifier_requiredDataMask(ModifierData *md) } static void smoothModifier_do( - SmoothModifierData *smd, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) + SmoothModifierData *smd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; MEdge *medges = NULL; @@ -3498,10 +3609,10 @@ static void smoothModifier_do( float *ftmp, fac, facm; ftmp = (float*)MEM_callocN(3*sizeof(float)*numVerts, - "smoothmodifier_f"); + "smoothmodifier_f"); if (!ftmp) return; uctmp = (unsigned char*)MEM_callocN(sizeof(unsigned char)*numVerts, - "smoothmodifier_uc"); + "smoothmodifier_uc"); if (!uctmp) { if (ftmp) MEM_freeN(ftmp); return; @@ -3530,7 +3641,7 @@ static void smoothModifier_do( dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); /* NOTICE: this can be optimized a little bit by moving the - * if (dvert) out of the loop, if needed */ + * if (dvert) out of the loop, if needed */ for (j = 0; j < smd->repeat; j++) { for (i = 0; i < numDMEdges; i++) { float fvec[3]; @@ -3626,8 +3737,8 @@ static void smoothModifier_do( } static void smoothModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; @@ -3638,14 +3749,14 @@ static void smoothModifier_deformVerts( CDDM_calc_normals(dm); smoothModifier_do((SmoothModifierData *)md, ob, dm, - vertexCos, numVerts); + vertexCos, numVerts); dm->release(dm); } static void smoothModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; @@ -3656,7 +3767,7 @@ static void smoothModifier_deformVertsEM( CDDM_calc_normals(dm); smoothModifier_do((SmoothModifierData *)md, ob, dm, - vertexCos, numVerts); + vertexCos, numVerts); dm->release(dm); } @@ -3671,7 +3782,7 @@ static void castModifier_initData(ModifierData *md) cmd->radius = 0.0f; cmd->size = 0.0f; cmd->flag = MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z - | MOD_CAST_SIZE_FROM_RADIUS; + | MOD_CAST_SIZE_FROM_RADIUS; cmd->type = MOD_CAST_TYPE_SPHERE; cmd->defgrp_name[0] = '\0'; cmd->object = NULL; @@ -3716,9 +3827,9 @@ CustomDataMask castModifier_requiredDataMask(ModifierData *md) } static void castModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { CastModifierData *cmd = (CastModifierData*) md; @@ -3726,21 +3837,22 @@ static void castModifier_foreachObjectLink( } static void castModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, - DagNode *obNode) + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { CastModifierData *cmd = (CastModifierData*) md; if (cmd->object) { DagNode *curNode = dag_get_node(forest, cmd->object); - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, + "Cast Modifier"); } } static void castModifier_sphere_do( - CastModifierData *cmd, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) + CastModifierData *cmd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; @@ -3765,8 +3877,8 @@ static void castModifier_sphere_do( ctrl_ob = cmd->object; /* spherify's center is {0, 0, 0} (the ob's own center in its local - * space), by default, but if the user defined a control object, - * we use its location, transformed to ob's local space */ + * space), by default, but if the user defined a control object, + * we use its location, transformed to ob's local space */ if (ctrl_ob) { if(flag & MOD_CAST_USE_OB_TRANSFORM) { Mat4Invert(ctrl_ob->imat, ctrl_ob->obmat); @@ -3783,11 +3895,11 @@ static void castModifier_sphere_do( /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ /* 2) cmd->radius > 0.0f: only the vertices within this radius from - * the center of the effect should be deformed */ + * the center of the effect should be deformed */ if (cmd->radius > FLT_EPSILON) has_radius = 1; /* 3) if we were given a vertex group name, - * only those vertices should be affected */ + * only those vertices should be affected */ if (cmd->defgrp_name[0]) { bDeformGroup *def; @@ -3819,10 +3931,10 @@ static void castModifier_sphere_do( } /* ready to apply the effect, one vertex at a time; - * tiny optimization: the code is separated (with parts repeated) + * tiny optimization: the code is separated (with parts repeated) * in two possible cases: - * with or w/o a vgroup. With lots of if's in the code below, - * further optimizations are possible, if needed */ + * with or w/o a vgroup. With lots of if's in the code below, + * further optimizations are possible, if needed */ if (dvert) { /* with a vgroup */ float fac_orig = fac; for (i = 0; i < numVerts; i++) { @@ -3925,8 +4037,8 @@ static void castModifier_sphere_do( } static void castModifier_cuboid_do( - CastModifierData *cmd, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) + CastModifierData *cmd, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; Object *ctrl_ob = NULL; @@ -3950,11 +4062,11 @@ static void castModifier_cuboid_do( /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ /* 2) cmd->radius > 0.0f: only the vertices within this radius from - * the center of the effect should be deformed */ + * the center of the effect should be deformed */ if (cmd->radius > FLT_EPSILON) has_radius = 1; /* 3) if we were given a vertex group name, - * only those vertices should be affected */ + * only those vertices should be affected */ if (cmd->defgrp_name[0]) { bDeformGroup *def; @@ -3994,12 +4106,12 @@ static void castModifier_cuboid_do( } else { /* get bound box */ /* We can't use the object's bound box because other modifiers - * may have changed the vertex data. */ + * may have changed the vertex data. */ INIT_MINMAX(min, max); /* Cast's center is the ob's own center in its local space, - * by default, but if the user defined a control object, we use - * its location, transformed to ob's local space. */ + * by default, but if the user defined a control object, we use + * its location, transformed to ob's local space. */ if (ctrl_ob) { float vec[3]; @@ -4035,10 +4147,10 @@ static void castModifier_cuboid_do( bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2]; /* ready to apply the effect, one vertex at a time; - * tiny optimization: the code is separated (with parts repeated) + * tiny optimization: the code is separated (with parts repeated) * in two possible cases: - * with or w/o a vgroup. With lots of if's in the code below, - * further optimizations are possible, if needed */ + * with or w/o a vgroup. With lots of if's in the code below, + * further optimizations are possible, if needed */ if (dvert) { /* with a vgroup */ float fac_orig = fac; for (i = 0; i < numVerts; i++) { @@ -4058,8 +4170,8 @@ static void castModifier_cuboid_do( if (has_radius) { if (fabs(tmp_co[0]) > cmd->radius || - fabs(tmp_co[1]) > cmd->radius || - fabs(tmp_co[2]) > cmd->radius) continue; + fabs(tmp_co[1]) > cmd->radius || + fabs(tmp_co[2]) > cmd->radius) continue; } for (j = 0; j < dvert[i].totweight; ++j) { @@ -4076,10 +4188,10 @@ static void castModifier_cuboid_do( /* The algo used to project the vertices to their * bounding box (bb) is pretty simple: * for each vertex v: - * 1) find in which octant v is in; - * 2) find which outer "wall" of that octant is closer to v; - * 3) calculate factor (var fbb) to project v to that wall; - * 4) project. */ + * 1) find in which octant v is in; + * 2) find which outer "wall" of that octant is closer to v; + * 3) calculate factor (var fbb) to project v to that wall; + * 4) project. */ /* find in which octant this vertex is in */ octant = 0; @@ -4113,7 +4225,7 @@ static void castModifier_cuboid_do( continue; /* finally, this is the factor we wanted, to project the vertex - * to its bounding box (bb) */ + * to its bounding box (bb) */ fbb = apex[coord] / tmp_co[coord]; /* calculate the new vertex position */ @@ -4154,8 +4266,8 @@ static void castModifier_cuboid_do( if (has_radius) { if (fabs(tmp_co[0]) > cmd->radius || - fabs(tmp_co[1]) > cmd->radius || - fabs(tmp_co[2]) > cmd->radius) continue; + fabs(tmp_co[1]) > cmd->radius || + fabs(tmp_co[2]) > cmd->radius) continue; } octant = 0; @@ -4205,8 +4317,8 @@ static void castModifier_cuboid_do( } static void castModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; CastModifierData *cmd = (CastModifierData *)md; @@ -4224,8 +4336,8 @@ static void castModifier_deformVerts( } static void castModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; CastModifierData *cmd = (CastModifierData *)md; @@ -4249,7 +4361,7 @@ static void waveModifier_initData(ModifierData *md) WaveModifierData *wmd = (WaveModifierData*) md; // whadya know, moved here from Iraq wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL - | MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z); + | MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z); wmd->objectcenter = NULL; wmd->texture = NULL; @@ -4292,8 +4404,8 @@ static int waveModifier_dependsOnTime(ModifierData *md) } static void waveModifier_foreachObjectLink( - ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) + ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) { WaveModifierData *wmd = (WaveModifierData*) md; @@ -4302,7 +4414,7 @@ static void waveModifier_foreachObjectLink( } static void waveModifier_foreachIDLink(ModifierData *md, Object *ob, - IDWalkFunc walk, void *userData) + IDWalkFunc walk, void *userData) { WaveModifierData *wmd = (WaveModifierData*) md; @@ -4312,21 +4424,23 @@ static void waveModifier_foreachIDLink(ModifierData *md, Object *ob, } static void waveModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, - DagNode *obNode) + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { WaveModifierData *wmd = (WaveModifierData*) md; if(wmd->objectcenter) { DagNode *curNode = dag_get_node(forest, wmd->objectcenter); - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, + "Wave Modifier"); } if(wmd->map_object) { DagNode *curNode = dag_get_node(forest, wmd->map_object); - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, + "Wave Modifer"); } } @@ -4348,9 +4462,9 @@ CustomDataMask waveModifier_requiredDataMask(ModifierData *md) } static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob, - DerivedMesh *dm, - float (*co)[3], float (*texco)[3], - int numVerts) + DerivedMesh *dm, + float (*co)[3], float (*texco)[3], + int numVerts) { int i; int texmapping = wmd->texmapping; @@ -4368,14 +4482,14 @@ static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob, MFace *mface = dm->getFaceArray(dm); MFace *mf; char *done = MEM_callocN(sizeof(*done) * numVerts, - "get_texture_coords done"); + "get_texture_coords done"); int numFaces = dm->getNumFaces(dm); MTFace *tf; validate_layer_name(&dm->faceData, CD_MTFACE, wmd->uvlayer_name); tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, - wmd->uvlayer_name); + wmd->uvlayer_name); /* verts are given the UV from the first face that uses them */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { @@ -4419,25 +4533,25 @@ static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob, for(i = 0; i < numVerts; ++i, ++co, ++texco) { switch(texmapping) { - case MOD_WAV_MAP_LOCAL: - VECCOPY(*texco, *co); - break; - case MOD_WAV_MAP_GLOBAL: - VECCOPY(*texco, *co); - Mat4MulVecfl(ob->obmat, *texco); - break; - case MOD_WAV_MAP_OBJECT: - VECCOPY(*texco, *co); - Mat4MulVecfl(ob->obmat, *texco); - Mat4MulVecfl(wmd->map_object->imat, *texco); - break; + case MOD_WAV_MAP_LOCAL: + VECCOPY(*texco, *co); + break; + case MOD_WAV_MAP_GLOBAL: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + break; + case MOD_WAV_MAP_OBJECT: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + Mat4MulVecfl(wmd->map_object->imat, *texco); + break; } } } static void waveModifier_do( - WaveModifierData *md, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) + WaveModifierData *md, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) { WaveModifierData *wmd = (WaveModifierData*) md; MVert *mvert = NULL; @@ -4445,7 +4559,7 @@ static void waveModifier_do( int defgrp_index; float ctime = bsystem_time(ob, (float)G.scene->r.cfra, 0.0); float minfac = - (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); + (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); float lifefac = wmd->height; float (*tex_co)[3] = NULL; @@ -4490,13 +4604,13 @@ static void waveModifier_do( if(lifefac > wmd->damp) lifefac = 0.0; else lifefac = - (float)(wmd->height * (1.0 - sqrt(lifefac / wmd->damp))); + (float)(wmd->height * (1.0 - sqrt(lifefac / wmd->damp))); } } if(wmd->texture) { tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts, - "waveModifier_do tex_co"); + "waveModifier_do tex_co"); wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts); } @@ -4543,7 +4657,7 @@ static void waveModifier_do( if(wmd->flag & MOD_WAVE_CYCL) { amplit = (float)fmod(amplit - wmd->width, 2.0 * wmd->width) - + wmd->width; + + wmd->width; } /* GAUSSIAN */ @@ -4580,8 +4694,8 @@ static void waveModifier_do( } static void waveModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; WaveModifierData *wmd = (WaveModifierData *)md; @@ -4603,8 +4717,8 @@ static void waveModifier_deformVerts( } static void waveModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; WaveModifierData *wmd = (WaveModifierData *)md; @@ -4661,9 +4775,9 @@ static int armatureModifier_isDisabled(ModifierData *md) } static void armatureModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { ArmatureModifierData *amd = (ArmatureModifierData*) md; @@ -4671,8 +4785,8 @@ static void armatureModifier_foreachObjectLink( } static void armatureModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, - DagNode *obNode) + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { ArmatureModifierData *amd = (ArmatureModifierData*) md; @@ -4680,21 +4794,21 @@ static void armatureModifier_updateDepgraph( DagNode *curNode = dag_get_node(forest, amd->object); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Armature Modifier"); } } static void armatureModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData*) md; modifier_vgroup_cache(md, vertexCos); /* if next modifier needs original vertices */ armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL, - numVerts, amd->deformflag, - (float(*)[3])amd->prevCos, amd->defgrp_name); + numVerts, amd->deformflag, + (float(*)[3])amd->prevCos, amd->defgrp_name); /* free cache */ if(amd->prevCos) { MEM_freeN(amd->prevCos); @@ -4703,8 +4817,8 @@ static void armatureModifier_deformVerts( } static void armatureModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData*) md; DerivedMesh *dm = derivedData; @@ -4712,15 +4826,15 @@ static void armatureModifier_deformVertsEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts, - amd->deformflag, NULL, amd->defgrp_name); + amd->deformflag, NULL, amd->defgrp_name); if(!derivedData) dm->release(dm); } static void armatureModifier_deformMatricesEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], - float (*defMats)[3][3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], + float (*defMats)[3][3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData*) md; DerivedMesh *dm = derivedData; @@ -4728,7 +4842,7 @@ static void armatureModifier_deformMatricesEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts, - amd->deformflag, NULL, amd->defgrp_name); + amd->deformflag, NULL, amd->defgrp_name); if(!derivedData) dm->release(dm); } @@ -4783,9 +4897,9 @@ static int hookModifier_isDisabled(ModifierData *md) } static void hookModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { HookModifierData *hmd = (HookModifierData*) md; @@ -4793,20 +4907,21 @@ static void hookModifier_foreachObjectLink( } static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + Object *ob, DagNode *obNode) { HookModifierData *hmd = (HookModifierData*) md; if (hmd->object) { DagNode *curNode = dag_get_node(forest, hmd->object); - dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA, + "Hook Modifier"); } } static void hookModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { HookModifierData *hmd = (HookModifierData*) md; float vec[3], mat[4][4]; @@ -4815,7 +4930,7 @@ static void hookModifier_deformVerts( Mat4Invert(ob->imat, ob->obmat); Mat4MulSerie(mat, ob->imat, hmd->object->obmat, hmd->parentinv, - NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); /* vertex indices? */ if(hmd->indexar) { @@ -4823,24 +4938,24 @@ static void hookModifier_deformVerts( int index = hmd->indexar[i]; /* This should always be true and I don't generally like - * "paranoid" style code like this, but old files can have - * indices that are out of range because old blender did - * not correct them on exit editmode. - zr - */ + * "paranoid" style code like this, but old files can have + * indices that are out of range because old blender did + * not correct them on exit editmode. - zr + */ if(index < numVerts) { float *co = vertexCos[index]; float fac = hmd->force; /* if DerivedMesh is present and has original index data, - * use it - */ + * use it + */ if(dm && dm->getVertData(dm, 0, CD_ORIGINDEX)) { int j; int orig_index; for(j = 0; j < numVerts; ++j) { fac = hmd->force; orig_index = *(int *)dm->getVertData(dm, j, - CD_ORIGINDEX); + CD_ORIGINDEX); if(orig_index == index) { co = vertexCos[j]; if(hmd->falloff != 0.0) { @@ -4884,44 +4999,44 @@ static void hookModifier_deformVerts( if(dm) if(dm->getVertData(dm, 0, CD_MDEFORMVERT)) { + use_dverts = 1; + maxVerts = dm->getNumVerts(dm); + } else use_dverts = 0; + else if(me->dvert) { use_dverts = 1; - maxVerts = dm->getNumVerts(dm); + maxVerts = me->totvert; } else use_dverts = 0; - else if(me->dvert) { - use_dverts = 1; - maxVerts = me->totvert; - } else use_dverts = 0; - if(curdef && use_dverts) { - MDeformVert *dvert = me->dvert; - int i, j; + if(curdef && use_dverts) { + MDeformVert *dvert = me->dvert; + int i, j; - for(i = 0; i < maxVerts; i++, dvert++) { - if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT); - for(j = 0; j < dvert->totweight; j++) { - if(dvert->dw[j].def_nr == index) { - float fac = hmd->force*dvert->dw[j].weight; - float *co = vertexCos[i]; + for(i = 0; i < maxVerts; i++, dvert++) { + if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT); + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == index) { + float fac = hmd->force*dvert->dw[j].weight; + float *co = vertexCos[i]; - if(hmd->falloff != 0.0) { - float len = VecLenf(co, hmd->cent); - if(len > hmd->falloff) fac = 0.0; - else if(len > 0.0) - fac *= sqrt(1.0 - len / hmd->falloff); - } + if(hmd->falloff != 0.0) { + float len = VecLenf(co, hmd->cent); + if(len > hmd->falloff) fac = 0.0; + else if(len > 0.0) + fac *= sqrt(1.0 - len / hmd->falloff); + } - VecMat4MulVecfl(vec, mat, co); - VecLerpf(co, co, vec, fac); + VecMat4MulVecfl(vec, mat, co); + VecLerpf(co, co, vec, fac); + } } } } - } } } static void hookModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; @@ -4935,8 +5050,8 @@ static void hookModifier_deformVertsEM( /* Softbody */ static void softbodyModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { sbObjectStep(ob, (float)G.scene->r.cfra, vertexCos, numVerts); } @@ -4948,26 +5063,31 @@ static void clothModifier_initData(ModifierData *md) { ClothModifierData *clmd = (ClothModifierData*) md; - clmd->sim_parms = MEM_callocN(sizeof(SimulationSettings), "cloth sim parms"); - clmd->coll_parms = MEM_callocN(sizeof(CollisionSettings), "cloth coll parms"); + clmd->sim_parms = MEM_callocN(sizeof(ClothSimSettings), "cloth sim parms"); + clmd->coll_parms = MEM_callocN(sizeof(ClothCollSettings), "cloth coll parms"); + clmd->point_cache = BKE_ptcache_add(); /* check for alloc failing */ - if(!clmd->sim_parms || !clmd->coll_parms) + if(!clmd->sim_parms || !clmd->coll_parms || !clmd->point_cache) return; cloth_init (clmd); - printf("clothModifier_initData\n"); } static DerivedMesh *clothModifier_applyModifier(ModifierData *md, Object *ob, - DerivedMesh *derivedData, int useRenderParams, int isFinalCalc) + DerivedMesh *derivedData, int useRenderParams, int isFinalCalc) { ClothModifierData *clmd = (ClothModifierData*) md; DerivedMesh *result=NULL; /* check for alloc failing */ if(!clmd->sim_parms || !clmd->coll_parms) - return derivedData; + { + clothModifier_initData(md); + + if(!clmd->sim_parms || !clmd->coll_parms) + return derivedData; + } result = clothModifier_do(clmd, ob, derivedData, useRenderParams, isFinalCalc); @@ -4980,8 +5100,8 @@ static DerivedMesh *clothModifier_applyModifier(ModifierData *md, Object *ob, } static void clothModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, - DagNode *obNode) + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { ClothModifierData *clmd = (ClothModifierData*) md; @@ -4998,22 +5118,19 @@ static void clothModifier_updateDepgraph( if(coll_clmd) { DagNode *curNode = dag_get_node(forest, ob1); - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Cloth Collision"); } } } - } + } } CustomDataMask clothModifier_requiredDataMask(ModifierData *md) { - ClothModifierData *clmd = (ClothModifierData *)md; CustomDataMask dataMask = 0; /* ask for vertexgroups if we need them */ - if(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) - if (clmd->sim_parms->vgroup_mass > 0) - dataMask |= (1 << CD_MDEFORMVERT); + dataMask |= (1 << CD_MDEFORMVERT); return dataMask; } @@ -5026,15 +5143,16 @@ static void clothModifier_copyData(ModifierData *md, ModifierData *target) if(tclmd->sim_parms) MEM_freeN(tclmd->sim_parms); if(tclmd->coll_parms) - MEM_freeN(tclmd->coll_parms); + MEM_freeN(tclmd->coll_parms); + if(tclmd->point_cache) + BKE_ptcache_free(tclmd->point_cache); tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms); tclmd->coll_parms = MEM_dupallocN(clmd->coll_parms); - - tclmd->sim_parms->lastcachedframe = 0; + tclmd->point_cache = BKE_ptcache_copy(clmd->point_cache); + tclmd->clothObject = NULL; } - static int clothModifier_dependsOnTime(ModifierData *md) { return 1; @@ -5046,8 +5164,8 @@ static void clothModifier_freeData(ModifierData *md) if (clmd) { - - printf("clothModifier_freeData\n"); + if(G.rt > 0) + printf("clothModifier_freeData\n"); cloth_free_modifier_extern (clmd); @@ -5055,6 +5173,8 @@ static void clothModifier_freeData(ModifierData *md) MEM_freeN(clmd->sim_parms); if(clmd->coll_parms) MEM_freeN(clmd->coll_parms); + if(clmd->point_cache) + BKE_ptcache_free(clmd->point_cache); } } @@ -5071,7 +5191,7 @@ static void collisionModifier_initData(ModifierData *md) collmd->current_v = NULL; collmd->time = -1; collmd->numverts = 0; - collmd->tree = NULL; + collmd->bvh = NULL; } static void collisionModifier_freeData(ModifierData *md) @@ -5080,8 +5200,8 @@ static void collisionModifier_freeData(ModifierData *md) if (collmd) { - if(collmd->tree) - bvh_free(collmd->tree); + if(collmd->bvh) + bvh_free(collmd->bvh); if(collmd->x) MEM_freeN(collmd->x); if(collmd->xnew) @@ -5103,7 +5223,7 @@ static void collisionModifier_freeData(ModifierData *md) collmd->current_v = NULL; collmd->time = -1; collmd->numverts = 0; - collmd->tree = NULL; + collmd->bvh = NULL; collmd->mfaces = NULL; } } @@ -5114,7 +5234,7 @@ static int collisionModifier_dependsOnTime(ModifierData *md) } static void collisionModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, + ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { CollisionModifierData *collmd = (CollisionModifierData*) md; @@ -5140,12 +5260,13 @@ static void collisionModifier_deformVerts( current_time = bsystem_time ( ob, ( float ) G.scene->r.cfra, 0.0 ); - // printf("current_time %f, collmd->time %f\n", current_time, collmd->time); + if(G.rt > 0) + printf("current_time %f, collmd->time %f\n", current_time, collmd->time); + + numverts = dm->getNumVerts ( dm ); if(current_time > collmd->time) { - numverts = dm->getNumVerts ( dm ); - // check if mesh has changed if(collmd->x && (numverts != collmd->numverts)) collisionModifier_freeData((ModifierData *)collmd); @@ -5172,7 +5293,9 @@ static void collisionModifier_deformVerts( // TODO: epsilon // create bounding box hierarchy - collmd->tree = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sbift); + collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft); + + collmd->time = current_time; } else if(numverts == collmd->numverts) { @@ -5192,23 +5315,46 @@ static void collisionModifier_deformVerts( memcpy(collmd->current_xnew, collmd->x, numverts*sizeof(MVert)); memcpy(collmd->current_x, collmd->x, numverts*sizeof(MVert)); + /* check if GUI setting has changed for bvh */ + if(collmd->bvh) + { + if(ob->pd->pdef_sboft != collmd->bvh->epsilon) + { + bvh_free(collmd->bvh); + collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft); + } + + } + /* happens on file load (ONLY when i decomment changes in readfile.c */ - if(!collmd->tree) + if(!collmd->bvh) { - collmd->tree = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sbift); + collmd->bvh = bvh_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->current_x, numverts, ob->pd->pdef_sboft); } else { // recalc static bounding boxes - bvh_update_from_mvert(collmd->tree, collmd->current_x, numverts, NULL, 0); + bvh_update_from_mvert(collmd->bvh, collmd->current_x, numverts, NULL, 0); } + + collmd->time = current_time; + } + else if(numverts != collmd->numverts) + { + collisionModifier_freeData((ModifierData *)collmd); } - collmd->time = current_time; + } + else if(current_time < collmd->time) + { + collisionModifier_freeData((ModifierData *)collmd); } else { - collmd->time = current_time; + if(numverts != collmd->numverts) + { + collisionModifier_freeData((ModifierData *)collmd); + } } } @@ -5236,9 +5382,9 @@ static int booleanModifier_isDisabled(ModifierData *md) } static void booleanModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { BooleanModifierData *bmd = (BooleanModifierData*) md; @@ -5246,8 +5392,8 @@ static void booleanModifier_foreachObjectLink( } static void booleanModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, - DagNode *obNode) + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { BooleanModifierData *bmd = (BooleanModifierData*) md; @@ -5255,32 +5401,32 @@ static void booleanModifier_updateDepgraph( DagNode *curNode = dag_get_node(forest, bmd->object); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Boolean Modifier"); } } static DerivedMesh *booleanModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { // XXX doesn't handle derived data BooleanModifierData *bmd = (BooleanModifierData*) md; /* we do a quick sanity check */ if(((Mesh *)ob->data)->totface > 3 - && bmd->object && ((Mesh *)bmd->object->data)->totface > 3) { + && bmd->object && ((Mesh *)bmd->object->data)->totface > 3) { DerivedMesh *result = NewBooleanDerivedMesh(bmd->object, ob, - 1 + bmd->operation); + 1 + bmd->operation); /* if new mesh returned, return it; otherwise there was - * an error, so delete the modifier object */ + * an error, so delete the modifier object */ if(result) return result; else bmd->object = NULL; - } + } - return derivedData; + return derivedData; } /* Particles */ @@ -5301,7 +5447,6 @@ static void particleSystemModifier_freeData(ModifierData *md) psmd->dm=0; } - psmd->psys->flag &= ~PSYS_ENABLED; psmd->psys->flag |= PSYS_DELETE; } static void particleSystemModifier_copyData(ModifierData *md, ModifierData *target) @@ -5310,6 +5455,7 @@ static void particleSystemModifier_copyData(ModifierData *md, ModifierData *targ ParticleSystemModifierData *tpsmd= (ParticleSystemModifierData*) target; tpsmd->dm = 0; + tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0; //tpsmd->facepa = 0; tpsmd->flag = psmd->flag; /* need to keep this to recognise a bit later in copy_object */ @@ -5331,7 +5477,7 @@ CustomDataMask particleSystemModifier_requiredDataMask(ModifierData *md) } /* particles only need this if they are after a non deform modifier, and - * the modifier stack will only create them in that case. */ + * the modifier stack will only create them in that case. */ dataMask |= CD_MASK_ORIGSPACE; dataMask |= CD_MASK_ORCO; @@ -5363,12 +5509,13 @@ static int is_last_displist(Object *ob) } /* saves the current emitter state for a particle system and calculates particles */ static void particleSystemModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md; ParticleSystem * psys=0; + Mesh *me; int needsFree=0; if(ob->particlesystem.first) @@ -5376,6 +5523,14 @@ static void particleSystemModifier_deformVerts( else return; + /* multires check */ + if(ob->type == OB_MESH) { + me= (Mesh*)ob->data; + if(me->mr && me->mr->current != 1) + modifier_setError(md, + "Particles only supported on first multires level."); + } + if(!psys_check_enabled(ob, psys)) return; @@ -5426,6 +5581,7 @@ static void particleSystemModifier_deformVerts( /* make new dm */ psmd->dm=CDDM_copy(dm); + CDDM_apply_vert_coords(psmd->dm, vertexCos); CDDM_calc_normals(psmd->dm); if(needsFree){ @@ -5438,8 +5594,8 @@ static void particleSystemModifier_deformVerts( /* report change in mesh structure */ if(psmd->dm->getNumVerts(psmd->dm)!=psmd->totdmvert || - psmd->dm->getNumEdges(psmd->dm)!=psmd->totdmedge || - psmd->dm->getNumFaces(psmd->dm)!=psmd->totdmface){ + psmd->dm->getNumEdges(psmd->dm)!=psmd->totdmedge || + psmd->dm->getNumFaces(psmd->dm)!=psmd->totdmface){ /* in file read dm hasn't really changed but just wasn't saved in file */ psys->recalc |= PSYS_RECALC_HAIR; @@ -5449,13 +5605,13 @@ static void particleSystemModifier_deformVerts( psmd->totdmvert= psmd->dm->getNumVerts(psmd->dm); psmd->totdmedge= psmd->dm->getNumEdges(psmd->dm); psmd->totdmface= psmd->dm->getNumFaces(psmd->dm); - } + } - if(psys){ - particle_system_update(ob,psys); - psmd->flag |= eParticleSystemFlag_psys_updated; - psmd->flag &= ~eParticleSystemFlag_DM_changed; - } + if(psys){ + particle_system_update(ob,psys); + psmd->flag |= eParticleSystemFlag_psys_updated; + psmd->flag &= ~eParticleSystemFlag_DM_changed; + } } /* disabled particles in editmode for now, until support for proper derivedmesh @@ -5481,7 +5637,7 @@ static void particleInstanceModifier_initData(ModifierData *md) ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md; pimd->flag = eParticleInstanceFlag_Parents|eParticleInstanceFlag_Unborn| - eParticleInstanceFlag_Alive|eParticleInstanceFlag_Dead; + eParticleInstanceFlag_Alive|eParticleInstanceFlag_Dead; pimd->psys = 1; } @@ -5500,7 +5656,7 @@ static int particleInstanceModifier_dependsOnTime(ModifierData *md) return 0; } static void particleInstanceModifier_updateDepgraph(ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + Object *ob, DagNode *obNode) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData*) md; @@ -5508,12 +5664,13 @@ static void particleInstanceModifier_updateDepgraph(ModifierData *md, DagForest DagNode *curNode = dag_get_node(forest, pimd->ob); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA, + "Particle Instance Modifier"); } } static void particleInstanceModifier_foreachObjectLink(ModifierData *md, Object *ob, - ObjectWalkFunc walk, void *userData) + ObjectWalkFunc walk, void *userData) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData*) md; @@ -5521,8 +5678,8 @@ static void particleInstanceModifier_foreachObjectLink(ModifierData *md, Object } static DerivedMesh * particleInstanceModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *dm = derivedData, *result; ParticleInstanceModifierData *pimd= (ParticleInstanceModifierData*) md; @@ -5691,8 +5848,8 @@ static DerivedMesh * particleInstanceModifier_applyModifier( return result; } static DerivedMesh *particleInstanceModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { return particleInstanceModifier_applyModifier(md, ob, derivedData, 0, 1); } @@ -5751,8 +5908,8 @@ static float vert_weight(MDeformVert *dvert, int group) } static void explodeModifier_createFacepa(ExplodeModifierData *emd, - ParticleSystemModifierData *psmd, - Object *ob, DerivedMesh *dm) + ParticleSystemModifierData *psmd, + Object *ob, DerivedMesh *dm) { ParticleSystem *psys=psmd->psys; MFace *fa=0, *mface=0; @@ -6307,8 +6464,8 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive } static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, - ParticleSystemModifierData *psmd, Object *ob, - DerivedMesh *to_explode) + ParticleSystemModifierData *psmd, Object *ob, + DerivedMesh *to_explode) { DerivedMesh *explode, *dm=to_explode; MFace *mf=0; @@ -6475,8 +6632,8 @@ static ParticleSystemModifierData * explodeModifier_findPrecedingParticlesystem( return psmd; } static DerivedMesh * explodeModifier_applyModifier( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - int useRenderParams, int isFinalCalc) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *dm = derivedData; ExplodeModifierData *emd= (ExplodeModifierData*) md; @@ -6487,12 +6644,13 @@ static DerivedMesh * explodeModifier_applyModifier( if(psys==0 || psys->totpart==0) return derivedData; if(psys->part==0 || psys->particles==0) return derivedData; + if(psmd->dm==0) return derivedData; /* 1. find faces to be exploded if needed */ if(emd->facepa==0 - || psmd->flag&eParticleSystemFlag_Pars - || emd->flag&eExplodeFlag_CalcFaces - || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumFaces(dm)){ + || psmd->flag&eParticleSystemFlag_Pars + || emd->flag&eExplodeFlag_CalcFaces + || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumFaces(dm)){ if(psmd->flag & eParticleSystemFlag_Pars) psmd->flag &= ~eParticleSystemFlag_Pars; @@ -6500,21 +6658,21 @@ static DerivedMesh * explodeModifier_applyModifier( emd->flag &= ~eExplodeFlag_CalcFaces; explodeModifier_createFacepa(emd,psmd,ob,derivedData); - } - - /* 2. create new mesh */ - if(emd->flag & eExplodeFlag_EdgeSplit){ - int *facepa = emd->facepa; - DerivedMesh *splitdm=explodeModifier_splitEdges(emd,dm); - DerivedMesh *explode=explodeModifier_explodeMesh(emd,psmd,ob,splitdm); - - MEM_freeN(emd->facepa); - emd->facepa=facepa; - splitdm->release(splitdm); - return explode; - } - else - return explodeModifier_explodeMesh(emd,psmd,ob,derivedData); + } + + /* 2. create new mesh */ + if(emd->flag & eExplodeFlag_EdgeSplit){ + int *facepa = emd->facepa; + DerivedMesh *splitdm=explodeModifier_splitEdges(emd,dm); + DerivedMesh *explode=explodeModifier_explodeMesh(emd,psmd,ob,splitdm); + + MEM_freeN(emd->facepa); + emd->facepa=facepa; + splitdm->release(splitdm); + return explode; + } + else + return explodeModifier_explodeMesh(emd,psmd,ob,derivedData); } return derivedData; } @@ -6566,9 +6724,9 @@ static int meshdeformModifier_isDisabled(ModifierData *md) } static void meshdeformModifier_foreachObjectLink( - ModifierData *md, Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; @@ -6576,8 +6734,8 @@ static void meshdeformModifier_foreachObjectLink( } static void meshdeformModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, - DagNode *obNode) + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; @@ -6585,7 +6743,8 @@ static void meshdeformModifier_updateDepgraph( DagNode *curNode = dag_get_node(forest, mmd->object); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA|DAG_RL_OB_DATA|DAG_RL_DATA_OB|DAG_RL_OB_OB); + DAG_RL_DATA_DATA|DAG_RL_OB_DATA|DAG_RL_DATA_OB|DAG_RL_OB_OB, + "Mesh Deform Modifier"); } } @@ -6642,11 +6801,11 @@ static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3 } static void meshdeformModifier_do( - ModifierData *md, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts) { MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; - float imat[4][4], cagemat[4][4], icagemat[4][4], iobmat[3][3]; + float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3]; int a, b, totvert, totcagevert, defgrp_index; DerivedMesh *tmpdm, *cagedm; @@ -6669,11 +6828,12 @@ static void meshdeformModifier_do( if(!cagedm) return; - /* compute matrices to go in and out of cage object space */ + /* compute matrices to go in and out of cage object space */ Mat4Invert(imat, mmd->object->obmat); Mat4MulMat4(cagemat, ob->obmat, imat); - Mat4Invert(icagemat, cagemat); - Mat3CpyMat4(iobmat, icagemat); + Mat4MulMat4(cmat, cagemat, mmd->bindmat); + Mat4Invert(iobmat, cmat); + Mat3CpyMat4(icagemat, iobmat); /* bind weights if needed */ if(!mmd->bindcos) @@ -6771,11 +6931,11 @@ static void meshdeformModifier_do( if(totweight > 0.0f) { VecMulf(co, fac/totweight); - Mat3MulVecfl(iobmat, co); + Mat3MulVecfl(icagemat, co); if(G.rt != 527) VECADD(vertexCos[b], vertexCos[b], co) - else - VECCOPY(vertexCos[b], co) + else + VECCOPY(vertexCos[b], co) } } @@ -6785,8 +6945,8 @@ static void meshdeformModifier_do( } static void meshdeformModifier_deformVerts( - ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; @@ -6804,8 +6964,8 @@ static void meshdeformModifier_deformVerts( } static void meshdeformModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, - DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; @@ -6834,15 +6994,15 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) /* Initialize and return the appropriate type info structure, * assumes that modifier has: - * name == typeName, - * structName == typeName + 'ModifierData' - */ + * name == typeName, + * structName == typeName + 'ModifierData' + */ #define INIT_TYPE(typeName) \ (strcpy(typeArr[eModifierType_##typeName].name, #typeName), \ strcpy(typeArr[eModifierType_##typeName].structName, \ - #typeName "ModifierData"), \ +#typeName "ModifierData"), \ typeArr[eModifierType_##typeName].structSize = \ - sizeof(typeName##ModifierData), \ + sizeof(typeName##ModifierData), \ &typeArr[eModifierType_##typeName]) mti = &typeArr[eModifierType_None]; @@ -6851,13 +7011,13 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->structSize = sizeof(ModifierData); mti->type = eModifierType_None; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_AcceptsCVs; + | eModifierTypeFlag_AcceptsCVs; mti->isDisabled = noneModifier_isDisabled; mti = INIT_TYPE(Curve); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->initData = curveModifier_initData; mti->copyData = curveModifier_copyData; mti->requiredDataMask = curveModifier_requiredDataMask; @@ -6870,7 +7030,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Lattice); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->copyData = latticeModifier_copyData; mti->requiredDataMask = latticeModifier_requiredDataMask; mti->isDisabled = latticeModifier_isDisabled; @@ -6882,9 +7042,9 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Subsurf); mti->type = eModifierTypeType_Constructive; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsMapping - | eModifierTypeFlag_SupportsEditmode - | eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = subsurfModifier_initData; mti->copyData = subsurfModifier_copyData; mti->freeData = subsurfModifier_freeData; @@ -6902,9 +7062,9 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Array); mti->type = eModifierTypeType_Constructive; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsMapping - | eModifierTypeFlag_SupportsEditmode - | eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = arrayModifier_initData; mti->copyData = arrayModifier_copyData; mti->foreachObjectLink = arrayModifier_foreachObjectLink; @@ -6915,9 +7075,9 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Mirror); mti->type = eModifierTypeType_Constructive; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsMapping - | eModifierTypeFlag_SupportsEditmode - | eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = mirrorModifier_initData; mti->copyData = mirrorModifier_copyData; mti->foreachObjectLink = mirrorModifier_foreachObjectLink; @@ -6928,14 +7088,25 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(EdgeSplit); mti->type = eModifierTypeType_Constructive; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsMapping - | eModifierTypeFlag_SupportsEditmode - | eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = edgesplitModifier_initData; mti->copyData = edgesplitModifier_copyData; mti->applyModifier = edgesplitModifier_applyModifier; mti->applyModifierEM = edgesplitModifier_applyModifierEM; + mti = INIT_TYPE(Bevel); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = bevelModifier_initData; + mti->copyData = bevelModifier_copyData; + mti->requiredDataMask = bevelModifier_requiredDataMask; + mti->applyModifier = bevelModifier_applyModifier; + mti->applyModifierEM = bevelModifier_applyModifierEM; + mti = INIT_TYPE(Displace); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsEditmode; @@ -6952,9 +7123,9 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(UVProject); mti->type = eModifierTypeType_Nonconstructive; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsMapping - | eModifierTypeFlag_SupportsEditmode - | eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = uvprojectModifier_initData; mti->copyData = uvprojectModifier_copyData; mti->requiredDataMask = uvprojectModifier_requiredDataMask; @@ -6974,7 +7145,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Smooth); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->initData = smoothModifier_initData; mti->copyData = smoothModifier_copyData; mti->requiredDataMask = smoothModifier_requiredDataMask; @@ -6984,7 +7155,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Cast); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->initData = castModifier_initData; mti->copyData = castModifier_copyData; mti->requiredDataMask = castModifier_requiredDataMask; @@ -6996,7 +7167,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Wave); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->initData = waveModifier_initData; mti->copyData = waveModifier_copyData; mti->dependsOnTime = waveModifier_dependsOnTime; @@ -7010,7 +7181,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Armature); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->initData = armatureModifier_initData; mti->copyData = armatureModifier_copyData; mti->requiredDataMask = armatureModifier_requiredDataMask; @@ -7024,7 +7195,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Hook); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->initData = hookModifier_initData; mti->copyData = hookModifier_copyData; mti->requiredDataMask = hookModifier_requiredDataMask; @@ -7038,17 +7209,14 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Softbody); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_RequiresOriginalData; + | eModifierTypeFlag_RequiresOriginalData; mti->deformVerts = softbodyModifier_deformVerts; mti = INIT_TYPE(Cloth); mti->type = eModifierTypeType_Nonconstructive; mti->initData = clothModifier_initData; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_RequiresOriginalData; - // | eModifierTypeFlag_SupportsMapping - // | eModifierTypeFlag_SupportsEditmode - // | eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_UsesPointCache; mti->dependsOnTime = clothModifier_dependsOnTime; mti->freeData = clothModifier_freeData; mti->requiredDataMask = clothModifier_requiredDataMask; @@ -7059,8 +7227,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Collision); mti->type = eModifierTypeType_OnlyDeform; mti->initData = collisionModifier_initData; - mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_RequiresOriginalData; + mti->flags = eModifierTypeFlag_AcceptsMesh; mti->dependsOnTime = collisionModifier_dependsOnTime; mti->freeData = collisionModifier_freeData; mti->deformVerts = collisionModifier_deformVerts; @@ -7069,8 +7236,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Boolean); mti->type = eModifierTypeType_Nonconstructive; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_RequiresOriginalData - | eModifierTypeFlag_UsesPointCache; + | eModifierTypeFlag_RequiresOriginalData + | eModifierTypeFlag_UsesPointCache; mti->copyData = booleanModifier_copyData; mti->isDisabled = booleanModifier_isDisabled; mti->applyModifier = booleanModifier_applyModifier; @@ -7080,7 +7247,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(MeshDeform); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_SupportsEditmode; + | eModifierTypeFlag_SupportsEditmode; mti->initData = meshdeformModifier_initData; mti->freeData = meshdeformModifier_freeData; mti->copyData = meshdeformModifier_copyData; @@ -7094,11 +7261,11 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(ParticleSystem); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsMapping - | eModifierTypeFlag_UsesPointCache; + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_UsesPointCache; #if 0 - | eModifierTypeFlag_SupportsEditmode; - |eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_SupportsEditmode; + |eModifierTypeFlag_EnableInEditmode; #endif mti->initData = particleSystemModifier_initData; mti->freeData = particleSystemModifier_freeData; @@ -7112,9 +7279,9 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(ParticleInstance); mti->type = eModifierTypeType_Constructive; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_SupportsMapping - | eModifierTypeFlag_SupportsEditmode - | eModifierTypeFlag_EnableInEditmode; + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = particleInstanceModifier_initData; mti->copyData = particleInstanceModifier_copyData; mti->dependsOnTime = particleInstanceModifier_dependsOnTime; @@ -7155,7 +7322,7 @@ ModifierData *modifier_new(int type) md->type = type; md->mode = eModifierMode_Realtime - | eModifierMode_Render | eModifierMode_Expanded; + | eModifierMode_Render | eModifierMode_Expanded; if (mti->flags & eModifierTypeFlag_EnableInEditmode) md->mode |= eModifierMode_Editmode; @@ -7187,7 +7354,7 @@ int modifier_supportsMapping(ModifierData *md) ModifierTypeInfo *mti = modifierType_getInfo(md->type); return (mti->type==eModifierTypeType_OnlyDeform || - (mti->flags & eModifierTypeFlag_SupportsMapping)); + (mti->flags & eModifierTypeFlag_SupportsMapping)); } ModifierData *modifiers_findByType(Object *ob, ModifierType type) @@ -7219,7 +7386,7 @@ void modifiers_clearErrors(Object *ob) } void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, - void *userData) + void *userData) { ModifierData *md = ob->modifiers.first; @@ -7262,9 +7429,9 @@ int modifier_couldBeCage(ModifierData *md) ModifierTypeInfo *mti = modifierType_getInfo(md->type); return ( (md->mode & eModifierMode_Realtime) && - (md->mode & eModifierMode_Editmode) && - (!mti->isDisabled || !mti->isDisabled(md)) && - modifier_supportsMapping(md)); + (md->mode & eModifierMode_Editmode) && + (!mti->isDisabled || !mti->isDisabled(md)) && + modifier_supportsMapping(md)); } void modifier_setError(ModifierData *md, char *format, ...) @@ -7295,7 +7462,7 @@ int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r) ModifierData *md = ob->modifiers.first; int i, cageIndex = -1; - /* Find the last modifier acting on the cage. */ + /* Find the last modifier acting on the cage. */ for (i=0; md; i++,md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -7354,11 +7521,11 @@ LinkNode *modifiers_calcDataMasks(ModifierData *md, CustomDataMask dataMask) } /* build the list of required data masks - each mask in the list must - * include all elements of the masks that follow it - * - * note the list is currently in reverse order, so "masks that follow it" - * actually means "masks that precede it" at the moment - */ + * include all elements of the masks that follow it + * + * note the list is currently in reverse order, so "masks that follow it" + * actually means "masks that precede it" at the moment + */ for(curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) { if(prev) { CustomDataMask prev_mask = (CustomDataMask)prev->link; @@ -7381,8 +7548,8 @@ LinkNode *modifiers_calcDataMasks(ModifierData *md, CustomDataMask dataMask) ModifierData *modifiers_getVirtualModifierList(Object *ob) { /* Kinda hacky, but should be fine since we are never - * reentrant and avoid free hassles. - */ + * reentrant and avoid free hassles. + */ static ArmatureModifierData amd; static CurveModifierData cmd; static LatticeModifierData lmd; @@ -7440,7 +7607,7 @@ Object *modifiers_isDeformedByArmature(Object *ob) ArmatureModifierData *amd= NULL; /* return the first selected armature, this lets us use multiple armatures - */ + */ for (; md; md=md->next) { if (md->type==eModifierType_Armature) { amd = (ArmatureModifierData*) md; @@ -7465,7 +7632,7 @@ Object *modifiers_isDeformedByLattice(Object *ob) LatticeModifierData *lmd= NULL; /* return the first selected armature, this lets us use multiple armatures - */ + */ for (; md; md=md->next) { if (md->type==eModifierType_Lattice) { lmd = (LatticeModifierData*) md; diff --git a/source/blender/blenkernel/intern/multires-firstlevel.c b/source/blender/blenkernel/intern/multires-firstlevel.c index 778dd6f9c77..3d417565eb1 100644 --- a/source/blender/blenkernel/intern/multires-firstlevel.c +++ b/source/blender/blenkernel/intern/multires-firstlevel.c @@ -75,7 +75,7 @@ char type_ok(const int type) } /* Copy vdata or fdata from Mesh or EditMesh to Multires. */ -void multires_update_customdata(MultiresLevel *lvl1, CustomData *src, CustomData *dst, const int type) +void multires_update_customdata(MultiresLevel *lvl1, EditMesh *em, CustomData *src, CustomData *dst, const int type) { if(src && dst && type_ok(type)) { const int tot= (type == CD_MDEFORMVERT ? lvl1->totvert : lvl1->totface); @@ -84,7 +84,7 @@ void multires_update_customdata(MultiresLevel *lvl1, CustomData *src, CustomData CustomData_free(dst, tot); if(CustomData_has_layer(src, type)) { - if(G.obedit) { + if(em) { EditVert *eve= G.editMesh->verts.first; EditFace *efa= G.editMesh->faces.first; CustomData_copy(src, dst, cdmask(type), CD_CALLOC, tot); @@ -227,9 +227,9 @@ void multires_del_lower_customdata(Multires *mr, MultiresLevel *cr_lvl) void multires_update_first_level(Mesh *me, EditMesh *em) { if(me && me->mr && me->mr->current == 1) { - multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, + multires_update_customdata(me->mr->levels.first, em, em ? &em->vdata : &me->vdata, &me->mr->vdata, CD_MDEFORMVERT); - multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata, + multires_update_customdata(me->mr->levels.first, em, em ? &em->fdata : &me->fdata, &me->mr->fdata, CD_MTFACE); multires_update_edge_flags(me, em); } diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 3a8847a5be1..9bc7fe28f44 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -373,7 +373,7 @@ void multires_create(Object *ob, Mesh *me) /* Load vertices and vdata (MDeformVerts) */ lvl->totvert= em ? BLI_countlist(&em->verts) : me->totvert; me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts"); - multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata, + multires_update_customdata(me->mr->levels.first, em, em ? &em->vdata : &me->vdata, &me->mr->vdata, CD_MDEFORMVERT); if(em) eve= em->verts.first; for(i=0; i<lvl->totvert; ++i) { @@ -384,7 +384,7 @@ void multires_create(Object *ob, Mesh *me) /* Load faces and fdata (MTFaces) */ lvl->totface= em ? BLI_countlist(&em->faces) : me->totface; lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces"); - multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata, + multires_update_customdata(me->mr->levels.first, em, em ? &em->fdata : &me->fdata, &me->mr->fdata, CD_MTFACE); if(em) efa= em->faces.first; for(i=0; i<lvl->totface; ++i) { diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 961ea21d088..245c4179bd1 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdlib.h> diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 43a6f2091de..28c3e1c64e6 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -27,6 +27,7 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include <Python.h> #include <stdlib.h> #include <string.h> @@ -34,6 +35,7 @@ #include "DNA_image_types.h" #include "DNA_node_types.h" #include "DNA_material_types.h" +#include "DNA_text_types.h" #include "DNA_scene_types.h" #include "BKE_blender.h" @@ -44,6 +46,7 @@ #include "BKE_main.h" #include "BKE_node.h" #include "BKE_texture.h" +#include "BKE_text.h" #include "BKE_utildefines.h" #include "BLI_arithb.h" @@ -61,10 +64,9 @@ #include "RE_render_ext.h" /* <- ibuf_sample() */ #include "CMP_node.h" -#include "SHD_node.h" +#include "intern/CMP_util.h" /* stupid include path... */ -/* not very important, but the stack solver likes to know a maximum */ -#define MAX_SOCKET 64 +#include "SHD_node.h" static ListBase empty_list = {NULL, NULL}; ListBase node_all_composit = {NULL, NULL}; @@ -72,7 +74,7 @@ ListBase node_all_shaders = {NULL, NULL}; /* ************** Type stuff ********** */ -static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup) +static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id) { if(type==NODE_GROUP) { if(ngroup && GS(ngroup->id.name)==ID_NT) { @@ -83,7 +85,7 @@ static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup) else { bNodeType *ntype = ntree->alltypes.first; for(; ntype; ntype= ntype->next) - if(ntype->type==type) + if(ntype->type==type && id==ntype->id ) return ntype; return NULL; @@ -105,7 +107,27 @@ void ntreeInitTypes(bNodeTree *ntree) for(node= ntree->nodes.first; node; node= next) { next= node->next; - node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id); + if(node->type==NODE_DYNAMIC) { + bNodeType *stype= NULL; + if(node->id==NULL) { /* empty script node */ + stype= node_get_type(ntree, node->type, NULL, NULL); + } else { /* not an empty script node */ + stype= node_get_type(ntree, node->type, NULL, node->id); + if(!stype) { + stype= node_get_type(ntree, node->type, NULL, NULL); + /* needed info if the pynode script fails now: */ + if (node->id) node->storage= ntree; + } else { + node->custom1= 0; + node->custom1= BSET(node->custom1,NODE_DYNAMIC_ADDEXIST); + } + } + node->typeinfo= stype; + node->typeinfo->initfunc(node); + } else { + node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id, NULL); + } + if(node->typeinfo==NULL) { printf("Error: Node type %s doesn't exist anymore, removed\n", node->name); nodeFreeNode(ntree, node); @@ -115,6 +137,18 @@ void ntreeInitTypes(bNodeTree *ntree) ntree->init |= NTREE_TYPE_INIT; } +/* updates node with (modified) bNodeType.. this should be done for all trees */ +void ntreeUpdateType(bNodeTree *ntree, bNodeType *ntype) +{ + bNode *node; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo== ntype) { + nodeUpdateType(ntree, node, ntype); + } + } +} + /* only used internal... we depend on type definitions! */ static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype) { @@ -137,7 +171,7 @@ static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype) if(lb) BLI_addtail(lb, sock); - + return sock; } @@ -497,6 +531,14 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree) break; } } + + /* set socket own_index to zero since it can still have a value + * from being in a group before, otherwise it doesn't get a unique + * index in group_verify_own_indices */ + for(sock= node->inputs.first; sock; sock= sock->next) + sock->own_index= 0; + for(sock= node->outputs.first; sock; sock= sock->next) + sock->own_index= 0; } } @@ -513,7 +555,7 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree) ntreeMakeOwnType(ngroup); /* make group node */ - gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup); + gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup, NULL); gnode->locx= 0.5f*(min[0]+max[0]); gnode->locy= 0.5f*(min[1]+max[1]); @@ -552,6 +594,10 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree) } } } + + /* update node levels */ + ntreeSolveOrder(ntree); + return gnode; } @@ -766,30 +812,28 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode) return 1; } -/* ************** Add stuff ********** */ +void nodeCopyGroup(bNode *gnode) +{ + bNodeSocket *sock; + + gnode->id->us--; + gnode->id= (ID *)ntreeCopyTree((bNodeTree *)gnode->id, 0); + + /* new_sock was set in nodeCopyNode */ + for(sock=gnode->inputs.first; sock; sock=sock->next) + if(sock->tosock) + sock->tosock= sock->tosock->new_sock; + + for(sock=gnode->outputs.first; sock; sock=sock->next) + if(sock->tosock) + sock->tosock= sock->tosock->new_sock; +} -bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup) +/* ************** Add stuff ********** */ +void nodeAddSockets(bNode *node, bNodeType *ntype) { - bNode *node; - bNodeType *ntype= node_get_type(ntree, type, ngroup); bNodeSocketType *stype; - - node= MEM_callocN(sizeof(bNode), "new node"); - BLI_addtail(&ntree->nodes, node); - node->typeinfo= ntype; - - if(ngroup) - BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR); - else - BLI_strncpy(node->name, ntype->name, NODE_MAXSTR); - node->type= ntype->type; - node->flag= NODE_SELECT|ntype->flag; - node->width= ntype->width; - node->miniwidth= 42.0f; /* small value only, allows print of first chars */ - - if(type==NODE_GROUP) - node->id= (ID *)ngroup; - + if(ntype->inputs) { stype= ntype->inputs; while(stype->type != -1) { @@ -804,34 +848,111 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup) stype++; } } - +} + + +bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id) +{ + bNode *node= NULL; + bNodeType *ntype= NULL; + + if(type>=NODE_DYNAMIC_MENU) { + int a=0, idx= type-NODE_DYNAMIC_MENU; + ntype= ntree->alltypes.first; + while(ntype) { + if(ntype->type==NODE_DYNAMIC) { + if(a==idx) + break; + a++; + } + ntype= ntype->next; + } + } else + ntype= node_get_type(ntree, type, ngroup, id); + + node= MEM_callocN(sizeof(bNode), "new node"); + BLI_addtail(&ntree->nodes, node); + node->typeinfo= ntype; + if(type>=NODE_DYNAMIC_MENU) + node->custom2= type; /* for node_dynamic_init */ + + if(ngroup) + BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR); + else if(type>NODE_DYNAMIC_MENU) { + BLI_strncpy(node->name, ntype->id->name+2, NODE_MAXSTR); + } + else + BLI_strncpy(node->name, ntype->name, NODE_MAXSTR); + node->type= ntype->type; + node->flag= NODE_SELECT|ntype->flag; + node->width= ntype->width; + node->miniwidth= 42.0f; /* small value only, allows print of first chars */ + + if(type==NODE_GROUP) + node->id= (ID *)ngroup; + /* need init handler later? */ - /* got it-bob*/ - if(ntype->initfunc!=NULL) - ntype->initfunc(node); + /* got it-bob*/ + if(ntype->initfunc!=NULL) + ntype->initfunc(node); + + nodeAddSockets(node, ntype); - return node; + return node; +} + +void nodeMakeDynamicType(bNode *node) +{ + /* find SH_DYNAMIC_NODE ntype */ + bNodeType *ntype= node_all_shaders.first; + while(ntype) { + if(ntype->type==NODE_DYNAMIC && ntype->id==NULL) + break; + ntype= ntype->next; + } + + /* make own type struct to fill */ + if(ntype) { + /*node->typeinfo= MEM_dupallocN(ntype);*/ + bNodeType *newtype= MEM_callocN(sizeof(bNodeType), "dynamic bNodeType"); + *newtype= *ntype; + newtype->name= BLI_strdup(ntype->name); + node->typeinfo= newtype; + } +} + +void nodeUpdateType(bNodeTree *ntree, bNode* node, bNodeType *ntype) +{ + verify_socket_list(ntree, &node->inputs, ntype->inputs); + verify_socket_list(ntree, &node->outputs, ntype->outputs); } /* keep socket listorder identical, for copying links */ /* ntree is the target tree */ -bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) +bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal) { bNode *nnode= MEM_callocN(sizeof(bNode), "dupli node"); - bNodeSocket *sock; + bNodeSocket *sock, *oldsock; *nnode= *node; BLI_addtail(&ntree->nodes, nnode); duplicatelist(&nnode->inputs, &node->inputs); - for(sock= nnode->inputs.first; sock; sock= sock->next) - sock->own_index= 0; + oldsock= node->inputs.first; + for(sock= nnode->inputs.first; sock; sock= sock->next, oldsock= oldsock->next) { + oldsock->new_sock= sock; + if(internal) + sock->own_index= 0; + } duplicatelist(&nnode->outputs, &node->outputs); - for(sock= nnode->outputs.first; sock; sock= sock->next) { - sock->own_index= 0; + oldsock= node->outputs.first; + for(sock= nnode->outputs.first; sock; sock= sock->next, oldsock= oldsock->next) { + if(internal) + sock->own_index= 0; sock->stack_index= 0; sock->ns.data= NULL; + oldsock->new_sock= sock; } if(nnode->id) @@ -909,7 +1030,7 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) node->new_node= NULL; if(internal_select==0 || (node->flag & NODE_SELECT)) { - nnode= nodeCopyNode(newtree, node); /* sets node->new */ + nnode= nodeCopyNode(newtree, node, internal_select); /* sets node->new */ if(internal_select) { node->flag &= ~NODE_SELECT; nnode->flag |= NODE_SELECT; @@ -1042,6 +1163,7 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node) if(node->typeinfo && node->typeinfo->freestoragefunc) { node->typeinfo->freestoragefunc(node); } + MEM_freeN(node); } @@ -1243,11 +1365,21 @@ bNode *nodeGetActiveID(bNodeTree *ntree, short idtype) bNode *node; if(ntree==NULL) return NULL; + + /* check for group edit */ + for(node= ntree->nodes.first; node; node= node->next) + if(node->flag & NODE_GROUP_EDIT) + break; + + if(node) + ntree= (bNodeTree*)node->id; + /* now find active node with this id */ for(node= ntree->nodes.first; node; node= node->next) if(node->id && GS(node->id->name)==idtype) if(node->flag & NODE_ACTIVE_ID) break; + return node; } @@ -1668,7 +1800,7 @@ static void composit_begin_exec(bNodeTree *ntree, int is_group) if(is_group==0) { for(sock= node->outputs.first; sock; sock= sock->next) { - bNodeStack *ns= ntree->stack[0] + sock->stack_index; + bNodeStack *ns= ntree->stack + sock->stack_index; if(sock->ns.data) { ns->data= sock->ns.data; @@ -1701,7 +1833,7 @@ static void composit_end_exec(bNodeTree *ntree, int is_group) bNodeSocket *sock; for(sock= node->outputs.first; sock; sock= sock->next) { - ns= ntree->stack[0] + sock->stack_index; + ns= ntree->stack + sock->stack_index; if(ns->data) { sock->ns.data= ns->data; ns->data= NULL; @@ -1719,7 +1851,7 @@ static void composit_end_exec(bNodeTree *ntree, int is_group) if(is_group==0) { /* internally, group buffers are not stored */ - for(ns= ntree->stack[0], a=0; a<ntree->stacksize; a++, ns++) { + for(ns= ntree->stack, a=0; a<ntree->stacksize; a++, ns++) { if(ns->data) { printf("freed leftover buffer from stack\n"); free_compbuf(ns->data); @@ -1760,15 +1892,47 @@ static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack) /* per tree (and per group) unique indices are created */ /* the index_ext we need to be able to map from groups to the group-node own stack */ +typedef struct bNodeThreadStack { + struct bNodeThreadStack *next, *prev; + bNodeStack *stack; + int used; +} bNodeThreadStack; + +static bNodeThreadStack *ntreeGetThreadStack(bNodeTree *ntree, int thread) +{ + ListBase *lb= &ntree->threadstack[thread]; + bNodeThreadStack *nts; + + for(nts=lb->first; nts; nts=nts->next) { + if(!nts->used) { + nts->used= 1; + return nts; + } + } + + nts= MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack"); + nts->stack= MEM_dupallocN(ntree->stack); + nts->used= 1; + BLI_addtail(lb, nts); + + return nts; +} + +static void ntreeReleaseThreadStack(bNodeThreadStack *nts) +{ + nts->used= 0; +} + void ntreeBeginExecTree(bNodeTree *ntree) { /* let's make it sure */ if(ntree->init & NTREE_EXEC_INIT) return; - - /* allocate the stack pointer array */ - ntree->stack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(void *), "stack array"); - + + /* allocate the thread stack listbase array */ + if(ntree->type!=NTREE_COMPOSIT) + ntree->threadstack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(ListBase), "thread stack array"); + /* goes recursive over all groups */ ntree->stacksize= ntree_begin_exec_tree(ntree); @@ -1778,7 +1942,7 @@ void ntreeBeginExecTree(bNodeTree *ntree) int a; /* allocate the base stack */ - ns=ntree->stack[0]= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack"); + ns=ntree->stack= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack"); /* tag inputs, the get_stack() gives own socket stackdata if not in use */ for(a=0; a<ntree->stacksize; a++, ns++) ns->hasinput= 1; @@ -1788,7 +1952,7 @@ void ntreeBeginExecTree(bNodeTree *ntree) bNodeSocket *sock; for(sock= node->inputs.first; sock; sock= sock->next) { if(sock->link) { - ns= ntree->stack[0] + sock->link->fromsock->stack_index; + ns= ntree->stack + sock->link->fromsock->stack_index; ns->hasoutput= 1; ns->sockettype= sock->link->fromsock->type; } @@ -1796,16 +1960,11 @@ void ntreeBeginExecTree(bNodeTree *ntree) sock->ns.sockettype= sock->type; } if(node->type==NODE_GROUP && node->id) - group_tag_used_outputs(node, ntree->stack[0]); + group_tag_used_outputs(node, ntree->stack); } - /* composite does 1 node per thread, so no multiple stacks needed */ if(ntree->type==NTREE_COMPOSIT) composit_begin_exec(ntree, 0); - else { - for(a=1; a<BLENDER_MAX_THREADS; a++) - ntree->stack[a]= MEM_dupallocN(ntree->stack[0]); - } } ntree->init |= NTREE_EXEC_INIT; @@ -1815,6 +1974,7 @@ void ntreeEndExecTree(bNodeTree *ntree) { if(ntree->init & NTREE_EXEC_INIT) { + bNodeThreadStack *nts; int a; /* another callback candidate! */ @@ -1822,14 +1982,21 @@ void ntreeEndExecTree(bNodeTree *ntree) composit_end_exec(ntree, 0); if(ntree->stack) { - for(a=0; a<BLENDER_MAX_THREADS; a++) - if(ntree->stack[a]) - MEM_freeN(ntree->stack[a]); - MEM_freeN(ntree->stack); ntree->stack= NULL; } + if(ntree->threadstack) { + for(a=0; a<BLENDER_MAX_THREADS; a++) { + for(nts=ntree->threadstack[a].first; nts; nts=nts->next) + MEM_freeN(nts->stack); + BLI_freelistN(&ntree->threadstack[a]); + } + + MEM_freeN(ntree->threadstack); + ntree->threadstack= NULL; + } + ntree->init &= ~NTREE_EXEC_INIT; } } @@ -1858,12 +2025,20 @@ void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread) bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ bNodeStack *stack; + bNodeThreadStack *nts = NULL; /* only when initialized */ if((ntree->init & NTREE_EXEC_INIT)==0) ntreeBeginExecTree(ntree); - stack= ntree->stack[thread]; + /* composite does 1 node per thread, so no multiple stacks needed */ + if(ntree->type==NTREE_COMPOSIT) { + stack= ntree->stack; + } + else { + nts= ntreeGetThreadStack(ntree, thread); + stack= nts->stack; + } for(node= ntree->nodes.first; node; node= node->next) { if(node->typeinfo->execfunc) { @@ -1875,10 +2050,34 @@ void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread) node_group_execute(stack, callerdata, node, nsin, nsout); } } + + if(nts) + ntreeReleaseThreadStack(nts); } /* ***************************** threaded version for execute composite nodes ************* */ +/* these are nodes without input, only giving values */ +/* or nodes with only value inputs */ +static int node_only_value(bNode *node) +{ + bNodeSocket *sock; + + if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB)) + return 1; + + /* doing this for all node types goes wrong. memory free errors */ + if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) { + int retval= 1; + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->link) + retval &= node_only_value(sock->link->fromnode); + } + return retval; + } + return 0; +} + /* not changing info, for thread callback */ typedef struct ThreadData { @@ -1895,7 +2094,14 @@ static void *exec_composite_node(void *node_v) node_get_stack(node, thd->stack, nsin, nsout); - if(node->typeinfo->execfunc) { + if((node->flag & NODE_MUTED) && (!node_only_value(node))) { + /* viewers we execute, for feedback to user */ + if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) + node->typeinfo->execfunc(thd->rd, node, nsin, nsout); + else + node_compo_pass_on(node, nsin, nsout); + } + else if(node->typeinfo->execfunc) { node->typeinfo->execfunc(thd->rd, node, nsin, nsout); } else if(node->type==NODE_GROUP && node->id) { @@ -1906,27 +2112,6 @@ static void *exec_composite_node(void *node_v) return 0; } -/* these are nodes without input, only giving values */ -/* or nodes with only value inputs */ -static int node_only_value(bNode *node) -{ - bNodeSocket *sock; - - if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB)) - return 1; - - /* doing this for all node types goes wrong. memory free errors */ - if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) { - int retval= 1; - for(sock= node->inputs.first; sock; sock= sock->next) { - if(sock->link) - retval &= node_only_value(sock->link->fromnode); - } - return retval; - } - return 0; -} - /* return total of executable nodes, for timecursor */ /* only compositor uses it */ static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd) @@ -2049,7 +2234,7 @@ static void freeExecutableNode(bNodeTree *ntree) for(node= ntree->nodes.first; node; node= node->next) { if(node->exec & NODE_FREEBUFS) { for(sock= node->outputs.first; sock; sock= sock->next) { - bNodeStack *ns= ntree->stack[0] + sock->stack_index; + bNodeStack *ns= ntree->stack + sock->stack_index; if(ns->data) { free_compbuf(ns->data); ns->data= NULL; @@ -2103,7 +2288,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview) /* setup callerdata for thread callback */ thdata.rd= rd; - thdata.stack= ntree->stack[0]; + thdata.stack= ntree->stack; /* fixed seed, for example noise texture */ BLI_srandom(rd->cfra); @@ -2322,12 +2507,12 @@ void ntreeCompositTagGenerators(bNodeTree *ntree) /* ************* node definition init ********** */ -static bNodeType *is_nodetype_registered(ListBase *typelist, int type) +static bNodeType *is_nodetype_registered(ListBase *typelist, int type, ID *id) { bNodeType *ntype= typelist->first; for(;ntype; ntype= ntype->next ) - if(ntype->type==type) + if(ntype->type==type && ntype->id==id) return ntype; return NULL; @@ -2336,10 +2521,10 @@ static bNodeType *is_nodetype_registered(ListBase *typelist, int type) /* type can be from a static array, we make copy for duplicate types (like group) */ void nodeRegisterType(ListBase *typelist, const bNodeType *ntype) { - bNodeType *found= is_nodetype_registered(typelist, ntype->type); + bNodeType *found= is_nodetype_registered(typelist, ntype->type, ntype->id); if(found==NULL) { - bNodeType *ntypen= MEM_mallocN(sizeof(bNodeType), "node type"); + bNodeType *ntypen= MEM_callocN(sizeof(bNodeType), "node type"); *ntypen= *ntype; BLI_addtail(typelist, ntypen); } @@ -2395,6 +2580,7 @@ static void registerCompositNodes(ListBase *ntypelist) nodeRegisterType(ntypelist, &cmp_node_combyuva); nodeRegisterType(ntypelist, &cmp_node_sepycca); nodeRegisterType(ntypelist, &cmp_node_combycca); + nodeRegisterType(ntypelist, &cmp_node_premulkey); nodeRegisterType(ntypelist, &cmp_node_diff_matte); nodeRegisterType(ntypelist, &cmp_node_chroma); @@ -2409,7 +2595,6 @@ static void registerCompositNodes(ListBase *ntypelist) nodeRegisterType(ntypelist, &cmp_node_crop); nodeRegisterType(ntypelist, &cmp_node_displace); nodeRegisterType(ntypelist, &cmp_node_mapuv); - nodeRegisterType(ntypelist, &cmp_node_glare); nodeRegisterType(ntypelist, &cmp_node_tonemap); nodeRegisterType(ntypelist, &cmp_node_lensdist); @@ -2436,12 +2621,46 @@ static void registerShaderNodes(ListBase *ntypelist) nodeRegisterType(ntypelist, &sh_node_value); nodeRegisterType(ntypelist, &sh_node_rgb); nodeRegisterType(ntypelist, &sh_node_texture); + nodeRegisterType(ntypelist, &node_dynamic_typeinfo); nodeRegisterType(ntypelist, &sh_node_invert); nodeRegisterType(ntypelist, &sh_node_seprgb); nodeRegisterType(ntypelist, &sh_node_combrgb); nodeRegisterType(ntypelist, &sh_node_hue_sat); } +static void remove_dynamic_typeinfos(ListBase *list) +{ + bNodeType *ntype= list->first; + bNodeType *next= NULL; + while(ntype) { + next= ntype->next; + if(ntype->type==NODE_DYNAMIC && ntype->id!=NULL) { + BLI_remlink(list, ntype); + if(ntype->inputs) { + bNodeSocketType *sock= ntype->inputs; + while(sock->type!=-1) { + MEM_freeN(sock->name); + sock++; + } + MEM_freeN(ntype->inputs); + } + if(ntype->outputs) { + bNodeSocketType *sock= ntype->outputs; + while(sock->type!=-1) { + MEM_freeN(sock->name); + sock++; + } + MEM_freeN(ntype->outputs); + } + if(ntype->name) { + MEM_freeN(ntype->name); + } + MEM_freeN(ntype); + } + ntype= next; + } +} + void init_nodesystem(void) { registerCompositNodes(&node_all_composit); @@ -2450,8 +2669,8 @@ void init_nodesystem(void) void free_nodesystem(void) { + /*remove_dynamic_typeinfos(&node_all_composit);*/ /* unused for now */ BLI_freelistN(&node_all_composit); + remove_dynamic_typeinfos(&node_all_shaders); BLI_freelistN(&node_all_shaders); } - - diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 94190f9753b..5594a1dfaf7 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <string.h> @@ -53,6 +50,8 @@ #include "DNA_lattice_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_meta_types.h" +#include "DNA_curve_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_nla_types.h" @@ -91,7 +90,6 @@ #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_displist.h" -#include "BKE_effect.h" #include "BKE_group.h" #include "BKE_icons.h" #include "BKE_ipo.h" @@ -103,6 +101,7 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BKE_property.h" #include "BKE_sca.h" #include "BKE_scene.h" @@ -113,6 +112,8 @@ #include "BPY_extern.h" +#include "blendef.h" + /* Local function protos */ static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul); @@ -157,6 +158,25 @@ void update_base_layer(Object *ob) } } +void object_free_particlesystems(Object *ob) +{ + while(ob->particlesystem.first){ + ParticleSystem *psys = ob->particlesystem.first; + + BLI_remlink(&ob->particlesystem,psys); + + psys_free(ob,psys); + } +} + +void object_free_softbody(Object *ob) +{ + if(ob->soft) { + sbFree(ob->soft); + ob->soft= NULL; + } +} + void object_free_modifiers(Object *ob) { while (ob->modifiers.first) { @@ -168,13 +188,10 @@ void object_free_modifiers(Object *ob) } /* particle modifiers were freed, so free the particlesystems as well */ - while(ob->particlesystem.first){ - ParticleSystem *psys = ob->particlesystem.first; + object_free_particlesystems(ob); - BLI_remlink(&ob->particlesystem,psys); - - psys_free(ob,psys); - } + /* same for softbody */ + object_free_softbody(ob); } /* here we will collect all local displist stuff */ @@ -231,7 +248,6 @@ void free_object(Object *ob) BLI_freelistN(&ob->defbase); if(ob->pose) free_pose(ob->pose); - free_effects(&ob->effect); free_properties(&ob->prop); object_free_modifiers(ob); @@ -277,6 +293,7 @@ void unlink_object(Object *ob) Camera *camera; bConstraint *con; bActionStrip *strip; + ModifierData *md; int a; unlink_controllers(&ob->controllers); @@ -375,10 +392,13 @@ void unlink_object(Object *ob) /* object is deflector or field */ if(ob->pd) { - if(give_parteff(obt)) - obt->recalc |= OB_RECALC_DATA; - else if(obt->soft) + if(obt->soft) obt->recalc |= OB_RECALC_DATA; + + /* cloth */ + for(md=obt->modifiers.first; md; md=md->next) + if(md->type == eModifierType_Cloth) + obt->recalc |= OB_RECALC_DATA; } /* strips */ @@ -514,11 +534,11 @@ void unlink_object(Object *ob) if(v3d->camera==ob) { v3d->camera= NULL; - if(v3d->persp>1) v3d->persp= 1; + if(v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; } if(v3d->localvd && v3d->localvd->camera==ob ) { v3d->localvd->camera= NULL; - if(v3d->localvd->persp>1) v3d->localvd->persp= 1; + if(v3d->localvd->persp==V3D_CAMOB) v3d->localvd->persp= V3D_PERSP; } } else if(sl->spacetype==SPACE_IPO) { @@ -882,8 +902,10 @@ Object *add_only_object(int type, char *name) ob->type= type; /* ob->transflag= OB_QUAT; */ +#if 0 /* not used yet */ QuatOne(ob->quat); QuatOne(ob->dquat); +#endif ob->col[0]= ob->col[1]= ob->col[2]= 0.0; ob->col[3]= 1.0; @@ -974,11 +996,13 @@ void base_init_from_view3d(Base *base, View3D *v3d) if (U.flag & USER_ADD_VIEWALIGNED) { v3d->viewquat[0]= -v3d->viewquat[0]; - if (ob->transflag & OB_QUAT) { + + /* Quats arnt used yet */ + /*if (ob->transflag & OB_QUAT) { QUATCOPY(ob->quat, v3d->viewquat); - } else { + } else {*/ QuatToEul(v3d->viewquat, ob->rot); - } + /*}*/ v3d->viewquat[0]= -v3d->viewquat[0]; } } @@ -993,12 +1017,14 @@ SoftBody *copy_softbody(SoftBody *sb) sbn->totspring= sbn->totpoint= 0; sbn->bpoint= NULL; sbn->bspring= NULL; - sbn->ctime= 0.0f; sbn->keys= NULL; sbn->totkey= sbn->totpointkey= 0; sbn->scratch= NULL; + + sbn->pointcache= BKE_ptcache_copy(sb->pointcache); + return sbn; } @@ -1019,19 +1045,52 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys) pa->keys= MEM_dupallocN(pa->keys); } - if(psys->soft) + if(psys->soft) { psysn->soft= copy_softbody(psys->soft); + psysn->soft->particles = psysn; + } psysn->pathcache= NULL; psysn->childcache= NULL; psysn->edit= NULL; psysn->effectors.first= psysn->effectors.last= 0; + psysn->pointcache= BKE_ptcache_copy(psys->pointcache); + id_us_plus((ID *)psysn->part); return psysn; } +void copy_object_particlesystems(Object *obn, Object *ob) +{ + ParticleSystemModifierData *psmd; + ParticleSystem *psys, *npsys; + ModifierData *md; + + obn->particlesystem.first= obn->particlesystem.last= NULL; + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + npsys= copy_particlesystem(psys); + + BLI_addtail(&obn->particlesystem, npsys); + + /* need to update particle modifiers too */ + for(md=obn->modifiers.first; md; md=md->next) { + if(md->type==eModifierType_ParticleSystem) { + psmd= (ParticleSystemModifierData*)md; + if(psmd->psys==psys) + psmd->psys= npsys; + } + } + } +} + +void copy_object_softbody(Object *obn, Object *ob) +{ + if(ob->soft) + obn->soft= copy_softbody(ob->soft); +} + static void copy_object_pose(Object *obn, Object *ob) { bPoseChannel *chan; @@ -1075,7 +1134,6 @@ Object *copy_object(Object *ob) { Object *obn; ModifierData *md; - ParticleSystem *psys; int a; obn= copy_libblock(ob); @@ -1088,7 +1146,6 @@ Object *copy_object(Object *ob) obn->path= NULL; obn->flag &= ~OB_FROMGROUP; - copy_effects(&obn->effect, &ob->effect); obn->modifiers.first = obn->modifiers.last= NULL; for (md=ob->modifiers.first; md; md=md->next) { @@ -1142,22 +1199,7 @@ Object *copy_object(Object *ob) } } - obn->particlesystem.first= obn->particlesystem.last= NULL; - for(psys=ob->particlesystem.first; psys; psys=psys->next) { - ParticleSystemModifierData *psmd; - ParticleSystem *npsys= copy_particlesystem(psys); - - BLI_addtail(&obn->particlesystem, npsys); - - /* need to update particle modifiers too */ - for(md=obn->modifiers.first; md; md=md->next) { - if(md->type==eModifierType_ParticleSystem) { - psmd= (ParticleSystemModifierData*)md; - if(psmd->psys==psys) - psmd->psys= npsys; - } - } - } + copy_object_particlesystems(obn, ob); obn->derivedDeform = NULL; obn->derivedFinal = NULL; @@ -1173,11 +1215,13 @@ Object *copy_object(Object *ob) void expand_local_object(Object *ob) { bActionStrip *strip; + ParticleSystem *psys; int a; id_lib_extern((ID *)ob->action); id_lib_extern((ID *)ob->ipo); id_lib_extern((ID *)ob->data); + id_lib_extern((ID *)ob->dup_group); for(a=0; a<ob->totcol; a++) { id_lib_extern((ID *)ob->mat[a]); @@ -1185,7 +1229,8 @@ void expand_local_object(Object *ob) for (strip=ob->nlastrips.first; strip; strip=strip->next) { id_lib_extern((ID *)strip->act); } - + for(psys=ob->particlesystem.first; psys; psys=psys->next) + id_lib_extern((ID *)psys->part); } void make_local_object(Object *ob) @@ -1309,11 +1354,29 @@ void object_make_proxy(Object *ob, Object *target, Object *gob) /* skip constraints, constraintchannels, nla? */ - + /* set object type and link to data */ ob->type= target->type; ob->data= target->data; id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_EXTERN */ + /* copy material and index information */ + ob->actcol= ob->totcol= 0; + if(ob->mat) MEM_freeN(ob->mat); + ob->mat = NULL; + if ((target->totcol) && (target->mat) && OB_SUPPORT_MATERIAL(ob)) { + int i; + ob->colbits = target->colbits; + + ob->actcol= target->actcol; + ob->totcol= target->totcol; + + ob->mat = MEM_dupallocN(target->mat); + for(i=0; i<target->totcol; i++) { + /* dont need to run test_object_materials since we know this object is new and not used elsewhere */ + id_us_plus((ID *)ob->mat[i]); + } + } + /* type conversions */ if(target->type == OB_ARMATURE) { copy_object_pose(ob, target); /* data copy, object pointers in constraints */ @@ -1360,7 +1423,7 @@ float bsystem_time(Object *ob, float cfra, float ofs) cfra*= G.scene->r.framelen; if (ob) { - if (no_speed_curve==0 && ob->ipo) + if (no_speed_curve==0 && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra); /* ofset frames */ @@ -1377,7 +1440,7 @@ void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ { float smat[3][3], vec[3]; float rmat[3][3]; - float q1[4]; + /*float q1[4];*/ /* size */ if(ob->ipo) { @@ -1391,7 +1454,8 @@ void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ } /* rot */ - if(ob->transflag & OB_QUAT) { + /* Quats arnt used yet */ + /*if(ob->transflag & OB_QUAT) { if(ob->ipo) { QuatMul(q1, ob->quat, ob->dquat); QuatToMat3(q1, rmat); @@ -1400,7 +1464,7 @@ void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ QuatToMat3(ob->quat, rmat); } } - else { + else {*/ if(ob->ipo) { vec[0]= ob->rot[0]+ob->drot[0]; vec[1]= ob->rot[1]+ob->drot[1]; @@ -1410,7 +1474,7 @@ void object_to_mat3(Object *ob, float mat[][3]) /* no parent */ else { EulToMat3(ob->rot, rmat); } - } + /*}*/ Mat3MulMat3(mat, rmat, smat); } @@ -1435,7 +1499,7 @@ int enable_cu_speed= 1; static void ob_parcurve(Object *ob, Object *par, float mat[][4]) { Curve *cu; - float q[4], vec[4], dir[3], *quat, x1, ctime; + float q[4], vec[4], dir[3], quat[4], x1, ctime; float timeoffs = 0.0, sf_orig = 0.0; Mat4One(mat); @@ -1484,7 +1548,7 @@ static void ob_parcurve(Object *ob, Object *par, float mat[][4]) if( where_on_path(par, ctime, vec, dir) ) { if(cu->flag & CU_FOLLOW) { - quat= vectoquat(dir, ob->trackflag, ob->upflag); + vectoquat(dir, ob->trackflag, ob->upflag, quat); /* the tilt */ Normalize(dir); @@ -1567,9 +1631,12 @@ static void give_parvert(Object *par, int nr, float *vec) } } - if(count > 0) { + if (count==0) { + /* keep as 0,0,0 */ + } else if(count > 0) { VecMulf(vec, 1.0f / count); } else { + /* use first index if its out of range */ dm->getVertCo(dm, 0, vec); } } @@ -1884,13 +1951,13 @@ static void solve_parenting (Object *ob, Object *par, float obmat[][4], float sl } void solve_tracking (Object *ob, float targetmat[][4]) { - float *quat; + float quat[4]; float vec[3]; float totmat[3][3]; float tmat[4][4]; VecSubf(vec, ob->obmat[3], targetmat[3]); - quat= vectoquat(vec, ob->trackflag, ob->upflag); + vectoquat(vec, ob->trackflag, ob->upflag, quat); QuatToMat3(quat, totmat); if(ob->parent && (ob->transflag & OB_POWERTRACK)) { @@ -2146,7 +2213,7 @@ void object_handle_update(Object *ob) if(ob->recalc & OB_RECALC) { if(ob->recalc & OB_RECALC_OB) { - + // printf("recalcob %s\n", ob->id.name+2); /* handle proxy copy for target */ @@ -2162,6 +2229,7 @@ void object_handle_update(Object *ob) } else where_is_object(ob); + if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_OBJECTUPDATE); } if(ob->recalc & OB_RECALC_DATA) { @@ -2181,6 +2249,16 @@ void object_handle_update(Object *ob) else if(ob->type==OB_LATTICE) { lattice_calc_modifiers(ob); } + else if(ob->type==OB_CAMERA) { + Camera *cam = (Camera *)ob->data; + calc_ipo(cam->ipo, frame_to_float(G.scene->r.cfra)); + execute_ipo(&cam->id, cam->ipo); + } + else if(ob->type==OB_LAMP) { + Lamp *la = (Lamp *)ob->data; + calc_ipo(la->ipo, frame_to_float(G.scene->r.cfra)); + execute_ipo(&la->id, la->ipo); + } else if(ob->type==OB_ARMATURE) { /* this happens for reading old files and to match library armatures with poses */ if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC)) @@ -2227,6 +2305,7 @@ void object_handle_update(Object *ob) psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; } } + if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_OBDATAUPDATE); } /* the no-group proxy case, we call update */ @@ -2254,3 +2333,42 @@ float give_timeoffset(Object *ob) { return ob->sf; } } + +int give_obdata_texspace(Object *ob, int **texflag, float **loc, float **size, float **rot) { + + if (ob->data==NULL) + return 0; + + switch (GS(((ID *)ob->data)->name)) { + case ID_ME: + { + Mesh *me= ob->data; + if (texflag) *texflag = &me->texflag; + if (loc) *loc = me->loc; + if (size) *size = me->size; + if (rot) *rot = me->rot; + break; + } + case ID_CU: + { + Curve *cu= ob->data; + if (texflag) *texflag = &cu->texflag; + if (loc) *loc = cu->loc; + if (size) *size = cu->size; + if (rot) *rot = cu->rot; + break; + } + case ID_MB: + { + MetaBall *mb= ob->data; + if (texflag) *texflag = &mb->texflag; + if (loc) *loc = mb->loc; + if (size) *size = mb->size; + if (rot) *rot = mb->rot; + break; + } + default: + return 0; + } + return 1; +} diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index bd33fafe23c..f6a65bd72a5 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -188,7 +185,7 @@ PackedFile * newPackedFile(char * filename) // convert relative filenames to absolute filenames strcpy(name, filename); - BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + BLI_convertstringcode(name, G.sce); // open the file // and create a PackedFile structure @@ -289,7 +286,7 @@ int writePackedFile(char * filename, PackedFile *pf, int guimode) if (guimode) waitcursor(1); strcpy(name, filename); - BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + BLI_convertstringcode(name, G.sce); if (BLI_exists(name)) { for (number = 1; number <= 999; number++) { @@ -320,11 +317,11 @@ int writePackedFile(char * filename, PackedFile *pf, int guimode) if (remove_tmp) { if (ret_value == RET_ERROR) { - if (BLI_rename(tempname, name) == RET_ERROR) { + if (BLI_rename(tempname, name) != 0) { if(guimode) error("Error restoring tempfile. Check files: '%s' '%s'", tempname, name); } } else { - if (BLI_delete(tempname, 0, 0) == RET_ERROR) { + if (BLI_delete(tempname, 0, 0) != 0) { if(guimode) error("Error deleting '%s' (ignored)"); } } @@ -354,7 +351,7 @@ int checkPackedFile(char * filename, PackedFile * pf) char name[FILE_MAXDIR + FILE_MAXFILE]; strcpy(name, filename); - BLI_convertstringcode(name, G.sce, G.scene->r.cfra); + BLI_convertstringcode(name, G.sce); if (stat(name, &st)) { ret_val = PF_NOFILE; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index e09d6a7f06c..2aa0d0ad0b8 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3,15 +3,12 @@ * * $Id: particle.c $ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdlib.h> @@ -78,6 +75,7 @@ #include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_cdderivedmesh.h" +#include "BKE_pointcache.h" #include "blendef.h" #include "RE_render_ext.h" @@ -204,7 +202,7 @@ Object *psys_get_lattice(Object *ob, ParticleSystem *psys) { Object *lattice=0; - if(!psys_in_edit_mode(psys)==0){ + if(psys_in_edit_mode(psys)==0){ ModifierData *md = (ModifierData*)psys_get_modifier(ob,psys); @@ -226,14 +224,14 @@ void psys_disable_all(Object *ob) ParticleSystem *psys=ob->particlesystem.first; for(; psys; psys=psys->next) - psys->flag &= ~PSYS_ENABLED; + psys->flag |= PSYS_DISABLED; } void psys_enable_all(Object *ob) { ParticleSystem *psys=ob->particlesystem.first; for(; psys; psys=psys->next) - psys->flag |= PSYS_ENABLED; + psys->flag &= ~PSYS_DISABLED; } int psys_ob_has_hair(Object *ob) { @@ -252,10 +250,17 @@ int psys_in_edit_mode(ParticleSystem *psys) int psys_check_enabled(Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd; + Mesh *me; - if(!(psys->flag & PSYS_ENABLED)) + if(psys->flag & PSYS_DISABLED) return 0; + if(ob->type == OB_MESH) { + me= (Mesh*)ob->data; + if(me->mr && me->mr->current != 1) + return 0; + } + psmd= psys_get_modifier(ob, psys); if(psys->renderdata) { if(!(psmd->modifier.mode & eModifierMode_Render)) @@ -275,7 +280,8 @@ void psys_free_settings(ParticleSettings *part) if(part->pd) MEM_freeN(part->pd); } -void free_hair(ParticleSystem *psys) + +void free_hair(ParticleSystem *psys, int softbody) { ParticleData *pa; int i, totpart=psys->totpart; @@ -287,6 +293,11 @@ void free_hair(ParticleSystem *psys) } psys->flag &= ~PSYS_HAIR_DONE; + + if(softbody && psys->soft) { + sbFree(psys->soft); + psys->soft = NULL; + } } void free_keyed_keys(ParticleSystem *psys) { @@ -337,7 +348,7 @@ void psys_free(Object *ob, ParticleSystem * psys) psys_free_path_cache(psys); - free_hair(psys); + free_hair(psys, 1); free_keyed_keys(psys); @@ -363,10 +374,11 @@ void psys_free(Object *ob, ParticleSystem * psys) psys->part=0; } - if(psys->soft){ - sbFree(psys->soft); - psys->soft = 0; - } + if(psys->reactevents.first) + BLI_freelistN(&psys->reactevents); + + if(psys->pointcache) + BKE_ptcache_free(psys->pointcache); MEM_freeN(psys); } @@ -535,8 +547,8 @@ void psys_render_restore(Object *ob, ParticleSystem *psys) psmd->totdmface= data->totdmface; psmd->flag &= ~eParticleSystemFlag_psys_updated; - if(psys->part->from==PART_FROM_FACE && psmd->dm) - psys_calc_dmfaces(ob, psmd->dm, psys); + if(psmd->dm) + psys_calc_dmcache(ob, psmd->dm, psys); MEM_freeN(data); psys->renderdata= NULL; @@ -952,7 +964,8 @@ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*or } } } -void psys_interpolate_uvs(MTFace *tface, int quad, float *w, float *uvco){ +void psys_interpolate_uvs(MTFace *tface, int quad, float *w, float *uvco) +{ float v10= tface->uv[0][0]; float v11= tface->uv[0][1]; float v20= tface->uv[1][0]; @@ -973,9 +986,35 @@ void psys_interpolate_uvs(MTFace *tface, int quad, float *w, float *uvco){ uvco[1]= w[0]*v11 + w[1]*v21 + w[2]*v31; } } + +void psys_interpolate_mcol(MCol *mcol, int quad, float *w, MCol *mc) +{ + char *cp, *cp1, *cp2, *cp3, *cp4; + + cp= (char *)mc; + cp1= (char *)&mcol[0]; + cp2= (char *)&mcol[1]; + cp3= (char *)&mcol[2]; + + if(quad) { + cp4= (char *)&mcol[3]; + + cp[0]= (int)(w[0]*cp1[0] + w[1]*cp2[0] + w[2]*cp3[0] + w[3]*cp4[0]); + cp[1]= (int)(w[0]*cp1[1] + w[1]*cp2[1] + w[2]*cp3[1] + w[3]*cp4[1]); + cp[2]= (int)(w[0]*cp1[2] + w[1]*cp2[2] + w[2]*cp3[2] + w[3]*cp4[2]); + cp[3]= (int)(w[0]*cp1[3] + w[1]*cp2[3] + w[2]*cp3[3] + w[3]*cp4[3]); + } + else { + cp[0]= (int)(w[0]*cp1[0] + w[1]*cp2[0] + w[2]*cp3[0]); + cp[1]= (int)(w[0]*cp1[1] + w[1]*cp2[1] + w[2]*cp3[1]); + cp[2]= (int)(w[0]*cp1[2] + w[1]*cp2[2] + w[2]*cp3[2]); + cp[3]= (int)(w[0]*cp1[3] + w[1]*cp2[3] + w[2]*cp3[3]); + } +} + float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, float *fw, float *values) { - if(values==0) + if(values==0 || index==-1) return 0.0; switch(from){ @@ -1055,7 +1094,7 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float * if(node) { /* we have a linked list of faces that we use, faster! */ for(;node; node=node->next) { - findex= (int)node->link; + findex= GET_INT_FROM_POINTER(node->link); faceuv= osface[findex].uv; quad= mface[findex].v4; @@ -1091,24 +1130,30 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float * } /* interprets particle data to get a point on a mesh in object space */ -#define PARTICLE_ERROR(_nor, _vec) _vec[0]=_vec[1]=_vec[2]=0.0; if(_nor){ _nor[0]=_nor[1]=0.0; _nor[2]=1.0; } +#define PARTICLE_ON_DM_ERROR \ + { if(vec) { vec[0]=vec[1]=vec[2]=0.0; } \ + if(nor) { nor[0]=nor[1]=0.0; nor[2]=1.0; } \ + if(orco) { orco[0]=orco[1]=orco[2]=0.0; } \ + if(ornor) { ornor[0]=ornor[1]=0.0; ornor[2]=1.0; } \ + if(utan) { utan[0]=utan[1]=utan[2]=0.0; } \ + if(vtan) { vtan[0]=vtan[1]=vtan[2]=0.0; } } + void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor) { + float temp1[3]; float (*orcodata)[3]; - if(index < 0){ /* 'no dm' error has happened! */ - PARTICLE_ERROR(nor, vec); + if(index < 0) { /* 'no dm' error has happened! */ + PARTICLE_ON_DM_ERROR; return; } orcodata= dm->getVertDataArray(dm, CD_ORCO); if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) { /* this works for meshes with deform verts only - constructive modifiers wont work properly*/ - float temp1[3]; - if(from == PART_FROM_VERT) { if(index >= dm->getNumVerts(dm)) { - PARTICLE_ERROR(nor, vec); + PARTICLE_ON_DM_ERROR; return; } @@ -1131,7 +1176,7 @@ void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int i int uv_index; if(index >= dm->getNumFaces(dm)) { - PARTICLE_ERROR(nor, vec); + PARTICLE_ON_DM_ERROR; return; } @@ -1160,7 +1205,7 @@ void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int i we need a customdata layer like UV's so we can position the particle */ /* Only face supported at the moment */ - if (from==PART_FROM_FACE) { + if(ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { /* find a face on the derived mesh that uses this face */ Mesh *me= (Mesh*)ob->data; MVert *mvert; @@ -1178,7 +1223,7 @@ void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int i /* For this to work we need origindex and OrigSpace coords */ if(origindex==NULL || osface==NULL || index>=me->totface) { - PARTICLE_ERROR(nor, vec); + PARTICLE_ON_DM_ERROR; return; } @@ -1193,7 +1238,7 @@ void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int i * its a BUG watch out for this error! */ if (i==-1) { printf("Cannot find original face %i\n", index); - PARTICLE_ERROR(nor, vec); + PARTICLE_ON_DM_ERROR; return; } else if(i >= totface) @@ -1206,15 +1251,46 @@ void psys_particle_on_dm(Object *ob, DerivedMesh *dm, int from, int index, int i /* we need to modify the original weights to become weights for * the derived mesh face */ psys_origspace_to_w(osface, mface->v4, fw, fw_mod); - psys_interpolate_face(mvert,mface,mtface,orcodata,fw_mod,vec,nor,utan,vtan,orco,ornor); + + if(from==PART_FROM_VOLUME){ + psys_interpolate_face(mvert,mface,mtface,orcodata,fw_mod,vec,temp1,utan,vtan,orco,ornor); + if(nor) + VECCOPY(nor,temp1); + Normalize(temp1); + VecMulf(temp1,-foffset); + VECADD(vec,vec,temp1); + } + else + psys_interpolate_face(mvert,mface,mtface,orcodata,fw_mod,vec,nor,utan,vtan,orco,ornor); + } + else if(from == PART_FROM_VERT) { + if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > dm->getNumVerts(dm)) { + PARTICLE_ON_DM_ERROR; + return; + } + + dm->getVertCo(dm,index_dmcache,vec); + if(nor) { + dm->getVertNo(dm,index_dmcache,nor); + Normalize(nor); + } + if(orco) + VECCOPY(orco, orcodata[index]) + if(ornor) { + dm->getVertNo(dm,index_dmcache,nor); + Normalize(nor); + } + if(utan && vtan) { + utan[0]= utan[1]= utan[2]= 0.0f; + vtan[0]= vtan[1]= vtan[2]= 0.0f; + } } else { - /* TODO PARTICLE - support verts and volume */ - PARTICLE_ERROR(nor, vec); + PARTICLE_ON_DM_ERROR; } } } -#undef PARTICLE_ERROR +#undef PARTICLE_ON_DM_ERROR ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys) { @@ -1305,7 +1381,7 @@ static float vert_weight(MDeformVert *dvert, int group) } static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4]) { - float vec[3]={0.0,0.0,0.0}, q1[4]={1,0,0,0},*q2; + float vec[3]={0.0,0.0,0.0}, q1[4]={1,0,0,0},q2[4]; float t; CLAMP(time,0.0,1.0); @@ -1327,10 +1403,9 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo case PART_KINK_CURL: vec[axis]=1.0; if(par_rot) - q2=par_rot; - else{ - q2=vectoquat(par->vel,axis,(axis+1)%3); - } + QUATCOPY(q2,par_rot) + else + vectoquat(par->vel,axis,(axis+1)%3, q2); QuatMulVecf(q2,vec); VecMulf(vec,amplitude); VECADD(state->co,state->co,vec); @@ -1377,9 +1452,9 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo float inp_y,inp_z,length; if(par_rot) - q2=par_rot; + QUATCOPY(q2,par_rot) else - q2=vectoquat(par->vel,axis,(axis+1)%3); + vectoquat(par->vel,axis,(axis+1)%3,q2); QuatMulVecf(q2,y_vec); QuatMulVecf(q2,z_vec); @@ -1436,59 +1511,6 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo } } break; - //case PART_KINK_ROT: - // vec[axis]=1.0; - - // QuatMulVecf(par->rot,vec); - - // VecMulf(vec,amplitude*(float)sin(t)); - - // VECADD(state->co,state->co,vec); - // break; - } -} -static void do_postkink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4]) -{ - static ParticleKey first; - static float q[4]; - float vec[3]={0.0,0.0,0.0}; - float t; - - CLAMP(time,0.0,1.0); - - t=time; - - t*=(float)M_PI*freq; - - if(par==0) return; - - switch(type){ - case PART_KINK_ROLL: - if(time<(0.5+shape/2.0f)){ - float *q2; - memcpy(&first,state,sizeof(ParticleKey)); - Normalize(first.vel); - if(par_rot) - q2=par_rot; - else - q2=vectoquat(par->vel,axis,(axis+1)%3); - QUATCOPY(q,q2); - } - else{ - float fac; - shape=0.5f+shape/2.0f; - t-=(float)M_PI*(shape*freq + 0.5f); - - vec[axis]=1.0; - - QuatMulVecf(q,vec); - - fac=amplitude*(1.0f+((1.0f-time)/(1.0f-shape)*(float)sin(t))); - VECADDFAC(state->co,first.co,vec,fac); - fac=amplitude*((1.0f-time)/(1.0f-shape)*(float)cos(t)); - VECADDFAC(state->co,state->co,first.vel,fac); - } - break; } } static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump) @@ -1581,7 +1603,7 @@ int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb) VecRotToQuat(guidedir,guidevec[3]-ec->firstloc[3],rot2); QuatMulVecf(rot2,pa_loc); - //q=vectoquat(guidedir, pd->kink_axis, (pd->kink_axis+1)%3); + //vectoquat(guidedir, pd->kink_axis, (pd->kink_axis+1)%3, q); //QuatMul(par.rot,rot2,q); } //else{ @@ -1601,7 +1623,6 @@ int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb) VECCOPY(key.co,pa_loc); do_prekink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0); do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f); - do_postkink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0); VECCOPY(pa_loc,key.co); VECADD(pa_loc,pa_loc,guidevec); @@ -1668,6 +1689,32 @@ static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKe VECADD(state->co,state->co,rough); } +static void do_path_effectors(Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec) +{ + float force[3] = {0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}; + ParticleKey eff_key; + ParticleData *pa; + + VECCOPY(eff_key.co,(ca-1)->co); + VECCOPY(eff_key.vel,(ca-1)->vel); + QUATCOPY(eff_key.rot,(ca-1)->rot); + + pa= psys->particles+i; + do_effectors(i, pa, &eff_key, ob, psys, rootco, force, vel, dfra, cfra); + + VecMulf(force, effector*pow((float)k / (float)steps, 100.0f * psys->part->eff_hair) / (float)steps); + + VecAddf(force, force, vec); + + Normalize(force); + + if(k < steps) { + VecSubf(vec, (ca+1)->co, ca->co); + *length = VecLength(vec); + } + + VECADDFAC(ca->co, (ca-1)->co, force, *length); +} static int check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *state, float max_length, float *cur_length, float length, float *dvec) { if(*cur_length + length > max_length){ @@ -1859,6 +1906,8 @@ int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate) ctx->vg_rough1 = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGH1); ctx->vg_rough2 = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGH2); ctx->vg_roughe = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_ROUGHE); + if(psys->part->flag & PART_CHILD_EFFECT) + ctx->vg_effector = psys_cache_vgroup(ctx->dm,psys,PSYS_VG_EFFECTOR); } /* set correct ipo timing */ @@ -1886,8 +1935,9 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, float co[3], orco[3], ornor[3], t, rough_t, cpa_1st[3], dvec[3]; float branch_begin, branch_end, branch_prob, branchfac, rough_rand; float pa_rough1, pa_rough2, pa_roughe; - float length, pa_length, pa_clump, pa_kink; + float length, pa_length, pa_clump, pa_kink, pa_effector; float max_length = 1.0f, cur_length = 0.0f; + float eff_length, eff_vec[3]; int k, cpa_num, guided=0; short cpa_from; @@ -2000,6 +2050,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, pa_rough1=ptex.rough; pa_rough2=ptex.rough; pa_roughe=ptex.rough; + pa_effector= 1.0f; if(ctx->vg_length) pa_length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length); @@ -2013,16 +2064,17 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, pa_rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2); if(ctx->vg_roughe) pa_roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe); + if(ctx->vg_effector) + pa_effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector); /* create the child path */ for(k=0,state=keys; k<=ctx->steps; k++,state++){ - t=(float)k/(float)ctx->steps; - if(ctx->between){ int w=0; state->co[0] = state->co[1] = state->co[2] = 0.0f; state->vel[0] = state->vel[1] = state->vel[2] = 0.0f; + state->rot[0] = state->rot[1] = state->rot[2] = state->rot[3] = 0.0f; //QUATCOPY(state->rot,key[0]->rot); @@ -2051,6 +2103,23 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, key[0]++; } + } + + /* apply effectors */ + if(part->flag & PART_CHILD_EFFECT) { + for(k=0,state=keys; k<=ctx->steps; k++,state++) { + if(k) { + do_path_effectors(ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, pa_effector, 0.0f, ctx->cfra, &eff_length, eff_vec); + } + else { + VecSubf(eff_vec,(state+1)->co,state->co); + eff_length= VecLength(eff_vec); + } + } + } + + for(k=0,state=keys; k<=ctx->steps; k++,state++){ + t=(float)k/(float)ctx->steps; if(ctx->totparent){ if(i>=ctx->totparent) @@ -2065,8 +2134,9 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, } /* apply different deformations to the child path */ - if(part->flag & PART_CHILD_GUIDE) - guided = do_guide((ParticleKey*)state, i, t, &(psys->effectors)); //safe to cast, since only co and vel are used + if(part->flag & PART_CHILD_EFFECT) + /* state is safe to cast, since only co and vel are used */ + guided = do_guide((ParticleKey*)state, cpa->parent, t, &(psys->effectors)); if(guided==0){ if(part->kink) @@ -2074,10 +2144,6 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat); do_clump((ParticleKey*)state, (ParticleKey*)par, t, part->clumpfac, part->clumppow, pa_clump); - - if(part->kink) - do_postkink((ParticleKey*)state, (ParticleKey*)par, par->rot, t, - part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat); } if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) @@ -2196,7 +2262,7 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed int i, totchild, totparent, totthread; unsigned long totchildstep; - pthreads= psys_threads_create(ob, psys, G.scene->r.threads); + pthreads= psys_threads_create(ob, psys); if(!psys_threads_init_path(pthreads, cfra, editupdate)) { psys_threads_free(pthreads); @@ -2322,8 +2388,10 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda if(ma && (psys->part->draw & PART_DRAW_MAT_COL)) VECCOPY(col, &ma->r) - if(psys->part->from!=PART_FROM_PARTICLE) - vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR); + if(psys->part->from!=PART_FROM_PARTICLE) { + if(!(psys->part->flag & PART_CHILD_EFFECT)) + vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR); + } /*---first main loop: create all actual particles' paths---*/ for(i=0,pa=psys->particles; i<totpart; i++, pa++){ @@ -2417,7 +2485,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda if(soft) { if(hkey[1] != pa->hair + pa->totkey - 1) - bp_to_particle(keys + 3, bp[1], hkey[1] + 1); + bp_to_particle(keys + 3, bp[1] + 1, hkey[1] + 1); else bp_to_particle(keys + 3, bp[1], hkey[1]); } @@ -2453,6 +2521,38 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda } VECCOPY(ca->co, result.co); + + /* selection coloring in edit mode */ + if(edit){ + if(pset->brushtype==PE_BRUSH_WEIGHT){ + if(k==steps) + VecLerpf(ca->col, nosel_col, sel_col, hkey[0]->weight); + else + VecLerpf(ca->col, nosel_col, sel_col, + (1.0f - keytime) * hkey[0]->weight + keytime * hkey[1]->weight); + } + else{ + if((ekey + (hkey[0] - pa->hair))->flag & PEK_SELECT){ + if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ + VECCOPY(ca->col, sel_col); + } + else{ + VecLerpf(ca->col, sel_col, nosel_col, keytime); + } + } + else{ + if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ + VecLerpf(ca->col, nosel_col, sel_col, keytime); + } + else{ + VECCOPY(ca->col, nosel_col); + } + } + } + } + else{ + VECCOPY(ca->col, col); + } } /*--modify paths--*/ @@ -2466,33 +2566,13 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda for(k=0, ca=cache[i]; k<=steps; k++, ca++) { /* apply effectors */ - if(edit==0 && k) { - float force[3] = {0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}; - ParticleKey eff_key; - - VECCOPY(eff_key.co,(ca-1)->co); - VECCOPY(eff_key.vel,(ca-1)->vel); - QUATCOPY(eff_key.rot,(ca-1)->rot); - - do_effectors(i, pa, &eff_key, ob, psys, force, vel, dfra, cfra); - - VecMulf(force, effector*pow((float)k / (float)steps, 100.0f * psys->part->eff_hair) / (float)steps); - - VecAddf(force, force, vec); - - Normalize(force); - - if(k < steps) { - VecSubf(vec, (ca+1)->co, ca->co); - length = VecLength(vec); - } - - VECADDFAC(ca->co, (ca-1)->co, force, length); - } + if(!(psys->part->flag & PART_CHILD_EFFECT) && edit==0 && k) + do_path_effectors(ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); /* apply guide curves to path data */ - if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_GUIDE)==0) - do_guide(&result, i, time, &psys->effectors); + if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) + /* ca is safe to cast, since only co and vel are used */ + do_guide((ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); /* apply lattice */ if(psys->lattice && edit==0) @@ -2501,16 +2581,12 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda /* figure out rotation */ if(k) { - float angle, tangent[3], normal[3], q[4]; + float cosangle, angle, tangent[3], normal[3], q[4]; if(k == 1) { - float *q2; - VECSUB(tangent, ca->co, (ca - 1)->co); - q2 = vectoquat(tangent, OB_POSX, OB_POSZ); - - QUATCOPY((ca - 1)->rot, q2); + vectoquat(tangent, OB_POSX, OB_POSZ, (ca-1)->rot); VECCOPY(prev_tangent, tangent); Normalize(prev_tangent); @@ -2518,12 +2594,17 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda else { VECSUB(tangent, ca->co, (ca - 1)->co); Normalize(tangent); - angle = saacos(Inpf(tangent, prev_tangent)); - if((angle > -0.000001) && (angle < 0.000001)){ + cosangle= Inpf(tangent, prev_tangent); + + /* note we do the comparison on cosangle instead of + * angle, since floating point accuracy makes it give + * different results across platforms */ + if(cosangle > 0.999999f) { QUATCOPY((ca - 1)->rot, (ca - 2)->rot); } - else{ + else { + angle= saacos(cosangle); Crossf(normal, prev_tangent, tangent); VecRotToQuat(normal, angle, q); QuatMul((ca - 1)->rot, q, (ca - 2)->rot); @@ -2532,9 +2613,8 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda VECCOPY(prev_tangent, tangent); } - if(k == steps) { + if(k == steps) QUATCOPY(ca->rot, (ca - 1)->rot); - } } @@ -2549,37 +2629,6 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda } - /* selection coloring in edit mode */ - if(edit){ - if(pset->brushtype==PE_BRUSH_WEIGHT){ - if(k==steps) - VecLerpf(ca->col, nosel_col, sel_col, hkey[0]->weight); - else - VecLerpf(ca->col,nosel_col,sel_col, - (1.0f - keytime) * hkey[0]->weight + keytime * hkey[1]->weight); - } - else{ - if((ekey + (hkey[0] - pa->hair))->flag & PEK_SELECT){ - if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ - VECCOPY(ca->col, sel_col); - } - else{ - VecLerpf(ca->col, sel_col, nosel_col, keytime); - } - } - else{ - if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ - VecLerpf(ca->col, nosel_col, sel_col, keytime); - } - else{ - VECCOPY(ca->col, nosel_col); - } - } - } - } - else{ - VECCOPY(ca->col, col); - } } } @@ -2869,10 +2918,10 @@ static void default_particle_settings(ParticleSettings *part) part->integrator= PART_INT_MIDPOINT; part->phystype= PART_PHYS_NEWTON; - part->hair_step= 10; + part->hair_step= 5; part->keys_step= 5; - part->draw_step= 4; - part->ren_step= 6; + part->draw_step= 2; + part->ren_step= 3; part->adapt_angle= 5; part->adapt_pix= 3; part->kink_axis= 2; @@ -2946,7 +2995,7 @@ ParticleSettings *psys_copy_settings(ParticleSettings *part) return partn; } -void psys_make_local_settings(ParticleSettings *part) +void make_local_particlesettings(ParticleSettings *part) { Object *ob; ParticleSettings *par; @@ -3032,7 +3081,7 @@ void psys_flush_settings(ParticleSettings *part, int event, int hair_recalc) tpsys=BLI_findlink(&tob->particlesystem,psys->target_psys-1); if(tpsys && tpsys->part==part){ - psys->flag |= event; + psys->recalc |= event; flush++; } } @@ -3042,6 +3091,42 @@ void psys_flush_settings(ParticleSettings *part, int event, int hair_recalc) } } } + +LinkNode *psys_using_settings(ParticleSettings *part, int flush_update) +{ + Object *ob, *tob; + ParticleSystem *psys, *tpsys; + LinkNode *node= NULL; + int found; + + /* update all that have same particle settings */ + for(ob=G.main->object.first; ob; ob=ob->id.next) { + found= 0; + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + if(psys->part == part) { + BLI_linklist_append(&node, psys); + found++; + } + else if(psys->part->type == PART_REACTOR){ + tob= (psys->target_ob)? psys->target_ob: ob; + tpsys= BLI_findlink(&tob->particlesystem, psys->target_psys-1); + + if(tpsys && tpsys->part==part) { + BLI_linklist_append(&node, tpsys); + found++; + } + } + } + + if(flush_update && found) + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } + + return node; +} + + /************************************************/ /* Textures */ /************************************************/ @@ -3054,6 +3139,7 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float if(ma) for(m=0; m<MAX_MTEX; m++){ mtex=ma->mtex[m]; if(mtex && (ma->septex & (1<<m))==0){ + float def=mtex->def_var; float var=mtex->varfac; short blend=mtex->blendtype; short neg=mtex->pmaptoneg; @@ -3088,13 +3174,13 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float ptex->time= texture_value_blend(mtex->def_var,ptex->time,value,var,blend,neg & MAP_PA_TIME); } if((event & mtex->pmapto) & MAP_PA_LENGTH) - ptex->length= texture_value_blend(value,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); + ptex->length= texture_value_blend(def,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); if((event & mtex->pmapto) & MAP_PA_CLUMP) - ptex->clump= texture_value_blend(value,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); + ptex->clump= texture_value_blend(def,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); if((event & mtex->pmapto) & MAP_PA_KINK) - ptex->kink= texture_value_blend(value,ptex->kink,value,var,blend,neg & MAP_PA_KINK); + ptex->kink= texture_value_blend(def,ptex->kink,value,var,blend,neg & MAP_PA_KINK); if((event & mtex->pmapto) & MAP_PA_ROUGH) - ptex->rough= texture_value_blend(value,ptex->rough,value,var,blend,neg & MAP_PA_ROUGH); + ptex->rough= texture_value_blend(def,ptex->rough,value,var,blend,neg & MAP_PA_ROUGH); } } if(event & MAP_PA_TIME) { CLAMP(ptex->time,0.0,1.0); } @@ -3114,6 +3200,7 @@ void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd mtex=ma->mtex[m]; if(mtex && (ma->septex & (1<<m))==0){ float var=mtex->varfac; + float def=mtex->def_var; short blend=mtex->blendtype; short neg=mtex->pmaptoneg; @@ -3147,28 +3234,31 @@ void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd externtex(mtex, texco, &value, rgba, rgba+1, rgba+2, rgba+3); if((event & mtex->pmapto) & MAP_PA_TIME){ + /* the first time has to set the base value for time regardless of blend mode */ if((setvars&MAP_PA_TIME)==0){ - ptex->time=0.0; - setvars|=MAP_PA_TIME; + ptex->time *= 1.0f - var; + ptex->time += var * ((neg & MAP_PA_TIME)? 1.0f - value : value); + setvars |= MAP_PA_TIME; } - ptex->time= texture_value_blend(mtex->def_var,ptex->time,value,var,blend,neg & MAP_PA_TIME); + else + ptex->time= texture_value_blend(def,ptex->time,value,var,blend,neg & MAP_PA_TIME); } if((event & mtex->pmapto) & MAP_PA_LIFE) - ptex->life= texture_value_blend(mtex->def_var,ptex->life,value,var,blend,neg & MAP_PA_LIFE); + ptex->life= texture_value_blend(def,ptex->life,value,var,blend,neg & MAP_PA_LIFE); if((event & mtex->pmapto) & MAP_PA_DENS) - ptex->exist= texture_value_blend(mtex->def_var,ptex->exist,value,var,blend,neg & MAP_PA_DENS); + ptex->exist= texture_value_blend(def,ptex->exist,value,var,blend,neg & MAP_PA_DENS); if((event & mtex->pmapto) & MAP_PA_SIZE) - ptex->size= texture_value_blend(mtex->def_var,ptex->size,value,var,blend,neg & MAP_PA_SIZE); + ptex->size= texture_value_blend(def,ptex->size,value,var,blend,neg & MAP_PA_SIZE); if((event & mtex->pmapto) & MAP_PA_IVEL) - ptex->ivel= texture_value_blend(mtex->def_var,ptex->ivel,value,var,blend,neg & MAP_PA_IVEL); + ptex->ivel= texture_value_blend(def,ptex->ivel,value,var,blend,neg & MAP_PA_IVEL); if((event & mtex->pmapto) & MAP_PA_PVEL) texture_rgb_blend(ptex->pvel,rgba,ptex->pvel,value,var,blend); if((event & mtex->pmapto) & MAP_PA_LENGTH) - ptex->length= texture_value_blend(mtex->def_var,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); + ptex->length= texture_value_blend(def,ptex->length,value,var,blend,neg & MAP_PA_LENGTH); if((event & mtex->pmapto) & MAP_PA_CLUMP) - ptex->clump= texture_value_blend(mtex->def_var,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); + ptex->clump= texture_value_blend(def,ptex->clump,value,var,blend,neg & MAP_PA_CLUMP); if((event & mtex->pmapto) & MAP_PA_KINK) - ptex->kink= texture_value_blend(mtex->def_var,ptex->kink,value,var,blend,neg & MAP_PA_CLUMP); + ptex->kink= texture_value_blend(def,ptex->kink,value,var,blend,neg & MAP_PA_CLUMP); } } if(event & MAP_PA_TIME) { CLAMP(ptex->time,0.0,1.0); } @@ -3269,7 +3359,7 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle ChildParticle *cpa; ParticleTexture ptex; ParticleKey *kkey[2] = {NULL, NULL}; - HairKey *hkey[2]; + HairKey *hkey[2] = {NULL, NULL}; ParticleKey *par=0, keys[4]; float t, real_t, dfra, keytime, frs_sec = G.scene->r.frs_sec; @@ -3374,11 +3464,9 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle //else{ // /* TODO: different rotations */ // float nvel[3]; - // float *q2; // VECCOPY(nvel,state->vel); // VecMulf(nvel,-1.0f); - // q2=vectoquat(nvel, OB_POSX, OB_POSZ); - // QUATCOPY(state->rot,q2); + // vectoquat(nvel, OB_POSX, OB_POSZ, state->rot); //} dfra = keys[2].time - keys[1].time; @@ -3533,10 +3621,6 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle do_clump(state, par, t, part->clumpfac, part->clumppow, 1.0f); - if(part->kink) - do_postkink(state, par, par->rot, t, part->kink_freq * pa_kink, part->kink_shape, - part->kink_amp, part->kink, part->kink_axis, ob->obmat); - if(part->rough1 != 0.0) do_rough(orco, t, part->rough1, part->rough1_size, 0.0, state); @@ -3610,36 +3694,34 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey return 1; } else{ - //if(psys->totchild && p>=psys->totpart){ - // ChildParticle *cpa=psys->child+p-psys->totpart; - // ParticleKey *key1, skey; - // float t=(cfra-pa->time)/pa->lifetime, clump; - - // pa=psys->particles+cpa->parent; + if(between) + return 0; /* currently not supported */ + else if(psys->totchild && p>=psys->totpart){ + ChildParticle *cpa=psys->child+p-psys->totpart; + ParticleKey *key1, skey; + float t = (cfra - pa->time + pa->loop * pa->lifetime) / pa->lifetime; - // if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){ - // key1=&skey; - // copy_particle_key(key1,&pa->state,0); - // key_from_object(pa->stick_ob,key1); - // } - // else{ - // key1=&pa->state; - // } - // - // offset_child(cpa, key1, state, part->childflat, part->childrad); - // - // CLAMP(t,0.0,1.0); - // if(part->kink) /* TODO: part->kink_freq*pa_kink */ - // do_prekink(state,key1,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,ob->obmat); - // - // /* TODO: pa_clump vgroup */ - // do_clump(state,key1,t,part->clumpfac,part->clumppow,0); - - // if(part->kink) /* TODO: part->kink_freq*pa_kink */ - // do_postkink(state,key1,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,ob->obmat); + pa = psys->particles + cpa->parent; - //} - //else{ + if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob) { + key1 = &skey; + copy_particle_key(key1,&pa->state,0); + key_from_object(pa->stick_ob,key1); + } + else { + key1=&pa->state; + } + + offset_child(cpa, key1, state, part->childflat, part->childrad); + + CLAMP(t,0.0,1.0); + if(part->kink) /* TODO: part->kink_freq*pa_kink */ + do_prekink(state,key1,key1->rot,t,part->kink_freq,part->kink_shape,part->kink_amp,part->kink,part->kink_axis,ob->obmat); + + /* TODO: pa_clump vgroup */ + do_clump(state,key1,t,part->clumpfac,part->clumppow,1.0); + } + else{ if (pa) { /* TODO PARTICLE - should this ever be NULL? - Campbell */ copy_particle_key(state,&pa->state,0); @@ -3650,7 +3732,7 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey if(psys->lattice) calc_latt_deform(state->co,1.0f); } - //} + } return 1; } @@ -3705,28 +3787,42 @@ void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemMo } } -void psys_get_dupli_path_transform(Object *ob, ParticleSettings *part, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4], float *scale) +void psys_get_dupli_path_transform(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4], float *scale) { - float loc[3], nor[3], vec[3], side[3], len; + float loc[3], nor[3], vec[3], side[3], len, obrotmat[4][4], qmat[4][4]; + float xvec[3] = {-1.0, 0.0, 0.0}, q[4]; VecSubf(vec, (cache+cache->steps-1)->co, cache->co); len= Normalize(vec); if(pa) - psys_particle_on_emitter(ob,psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); + psys_particle_on_emitter(ob,psmd,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,nor,0,0,0,0); else psys_particle_on_emitter(ob, psmd, - (part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, + (psys->part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE, cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,nor,0,0,0,0); - Crossf(side, nor, vec); - Normalize(side); - Crossf(nor, vec, side); - - Mat4One(mat); - VECCOPY(mat[0], vec); - VECCOPY(mat[1], side); - VECCOPY(mat[2], nor); + if(psys->part->rotmode) { + if(!pa) + pa= psys->particles+cpa->pa[0]; + + vectoquat(xvec, ob->trackflag, ob->upflag, q); + QuatToMat4(q, obrotmat); + obrotmat[3][3]= 1.0f; + + QuatToMat4(pa->state.rot, qmat); + Mat4MulMat4(mat, obrotmat, qmat); + } + else { + Crossf(side, nor, vec); + Normalize(side); + Crossf(nor, vec, side); + + Mat4One(mat); + VECCOPY(mat[0], vec); + VECCOPY(mat[1], side); + VECCOPY(mat[2], nor); + } *scale= len; } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index c0ffb7c62f8..596c381b896 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3,15 +3,12 @@ * * $Id: particle_system.c $ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdlib.h> @@ -63,7 +60,6 @@ #include "BKE_bad_level_calls.h" #include "BKE_cdderivedmesh.h" #include "BKE_displist.h" - #include "BKE_particle.h" #include "BKE_global.h" #include "BKE_utildefines.h" @@ -77,6 +73,7 @@ #include "BKE_pointcache.h" #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_scene.h" #include "BSE_headerbuttons.h" @@ -84,6 +81,22 @@ #include "RE_shader_ext.h" +/* fluid sim particle import */ +#ifndef DISABLE_ELBEEM +#include "DNA_object_fluidsim.h" +#include "LBM_fluidsim.h" +#include "elbeem.h" +#include <zlib.h> +#include <string.h> + +#ifdef WIN32 +#ifndef snprintf +#define snprintf _snprintf +#endif +#endif + +#endif // DISABLE_ELBEEM + /************************************************/ /* Reacting to system events */ /************************************************/ @@ -105,7 +118,51 @@ static int get_current_display_percentage(ParticleSystem *psys) return psys->part->disp; } -static void alloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) +void psys_reset(ParticleSystem *psys, int mode) +{ + ParticleSettings *part= psys->part; + ParticleData *pa; + int i; + + if(ELEM(mode, PSYS_RESET_ALL, PSYS_RESET_DEPSGRAPH)) { + if(mode == PSYS_RESET_ALL || !(part->type == PART_HAIR && (psys->flag & PSYS_EDITED))) { + if(psys->particles) { + if(psys->particles->keys) + MEM_freeN(psys->particles->keys); + + for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) + if(pa->hair) MEM_freeN(pa->hair); + + MEM_freeN(psys->particles); + psys->particles= NULL; + } + + psys->totpart= 0; + psys->totkeyed= 0; + psys->flag &= ~(PSYS_HAIR_DONE|PSYS_KEYED); + + if(psys->reactevents.first) + BLI_freelistN(&psys->reactevents); + } + } + + /* reset children */ + if(psys->child) { + MEM_freeN(psys->child); + psys->child= 0; + } + + psys->totchild= 0; + + /* reset path cache */ + psys_free_path_cache(psys); + + /* reset point cache */ + psys->pointcache->flag &= ~PTCACHE_SIMULATION_VALID; + psys->pointcache->simframe= 0; +} + +static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) { ParticleData *newpars = 0, *pa; int i, totpart, totsaved = 0; @@ -129,6 +186,12 @@ static void alloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) if(totsaved) memcpy(newpars,psys->particles,totsaved*sizeof(ParticleData)); + if(psys->particles->keys) + MEM_freeN(psys->particles->keys); + + for(i=0, pa=psys->particles; i<totsaved; i++, pa++) + if(pa->keys) pa->keys= NULL; + for(i=totsaved, pa=psys->particles+totsaved; i<psys->totpart; i++, pa++) if(pa->hair) MEM_freeN(pa->hair); @@ -145,15 +208,24 @@ static void alloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) psys->totpart=totpart; } -static int get_alloc_child_particles_tot(ParticleSystem *psys) +static int get_psys_child_number(ParticleSystem *psys) { - int child_nbr; + int nbr; if(!psys->part->childtype) return 0; - child_nbr= (psys->renderdata)? psys->part->ren_child_nbr: psys->part->child_nbr; - return psys->totpart*child_nbr; + if(psys->renderdata) { + nbr= psys->part->ren_child_nbr; + return get_render_child_particle_number(&G.scene->r, nbr); + } + else + return psys->part->child_nbr; +} + +static int get_psys_tot_child(ParticleSystem *psys) +{ + return psys->totpart*get_psys_child_number(psys); } static void alloc_child_particles(ParticleSystem *psys, int tot) @@ -171,12 +243,13 @@ static void alloc_child_particles(ParticleSystem *psys, int tot) } } -/* only run this if from == PART_FROM_FACE */ -void psys_calc_dmfaces(Object *ob, DerivedMesh *dm, ParticleSystem *psys) +void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys) { - /* use for building derived mesh face-origin info, - node - the allocated links - total derived mesh face count - node_array - is the array of nodes alligned with the base mesh's faces, so each original face can reference its derived faces + /* use for building derived mesh mapping info: + + node: the allocated links - total derived mesh element count + nodearray: the array of nodes aligned with the base mesh's elements, so + each original elements can reference its derived elements */ Mesh *me= (Mesh*)ob->data; ParticleData *pa= 0; @@ -185,57 +258,60 @@ void psys_calc_dmfaces(Object *ob, DerivedMesh *dm, ParticleSystem *psys) /* CACHE LOCATIONS */ if(!dm->deformedOnly) { /* Will use later to speed up subsurf/derivedmesh */ + LinkNode *node, *nodedmelem, **nodearray; + int totdmelem, totelem, i, *origindex; + + if(psys->part->from == PART_FROM_VERT) { + totdmelem= dm->getNumVerts(dm); + totelem= me->totvert; + origindex= DM_get_vert_data_layer(dm, CD_ORIGINDEX); + } + else { /* FROM_FACE/FROM_VOLUME */ + totdmelem= dm->getNumFaces(dm); + totelem= me->totface; + origindex= DM_get_face_data_layer(dm, CD_ORIGINDEX); + } - int tot_dm_face = dm->getNumFaces(dm); - int totface = me->totface; - int *origindex = DM_get_face_data_layer(dm, CD_ORIGINDEX); - int i; - LinkNode *node, *node_dm_faces, **node_array; - - node_dm_faces = node = MEM_callocN(sizeof(LinkNode)*tot_dm_face, "faceindicies"); - node_array = MEM_callocN(sizeof(LinkNode *)*totface, "faceindicies array"); + nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems"); + nodearray= MEM_callocN(sizeof(LinkNode *)*totelem, "psys node array"); - for(i=0; i < tot_dm_face; i++, origindex++, node++) { - node->link = (void *)i; // or use the index? + for(i=0, node=nodedmelem; i<totdmelem; i++, origindex++, node++) { + node->link= SET_INT_IN_POINTER(i); + if(*origindex != -1) { - if(node_array[*origindex]) { + if(nodearray[*origindex]) { /* prepend */ - node->next = node_array[*origindex]; - node_array[*origindex] = node; - } else { - node_array[*origindex] = node; + node->next = nodearray[*origindex]; + nodearray[*origindex]= node; } + else + nodearray[*origindex]= node; } } - /* cache the faces! */ - - + /* cache the verts/faces! */ for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++) { - //i = pa->num; - //if (i<totface) // should never happen - i = psys_particle_dm_face_lookup(ob, dm, pa->num, pa->fuv, node_array[pa->num]); - pa->num_dmcache = i; + if(psys->part->from == PART_FROM_VERT) { + if(nodearray[pa->num]) + pa->num_dmcache= GET_INT_FROM_POINTER(nodearray[pa->num]->link); + } + else { /* FROM_FACE/FROM_VOLUME */ + /* Note that somtimes the pa->num is over the nodearray size, this is bad, maybe there is a better place to fix this, + * but for now passing NULL is OK. every face will be searched for the particle so its slower - Campbell */ + pa->num_dmcache= psys_particle_dm_face_lookup(ob, dm, pa->num, pa->fuv, pa->num < totelem ? nodearray[pa->num] : NULL); + } } - //for (i=0; i < totface; i++) { - // i = psys_particle_dm_face_lookup(ob, dm, node_array[], fuv, (LinkNode*)NULL); - //} - MEM_freeN(node_array); - MEM_freeN(node_dm_faces); - - } else { - /* set the num_dmcache to an invalid value, just incase */ - /* TODO PARTICLE, make the following line unnecessary, each function should know to use the num or num_dmcache */ + MEM_freeN(nodearray); + MEM_freeN(nodedmelem); + } + else { + /* TODO PARTICLE, make the following line unnecessary, each function + * should know to use the num or num_dmcache, set the num_dmcache to + * an invalid value, just incase */ - /* - for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++) { - pa->num_dmcache = pa->num; - } - */ - for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++) { + for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++) pa->num_dmcache = -1; - } } } @@ -395,6 +471,29 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys) } } +/* modified copy from rayshade.c */ +static void hammersley_create(float *out, int n, int seed, float amount) +{ + RNG *rng; + double p, t, offs[2]; + int k, kk; + + rng = rng_new(31415926 + n + seed); + offs[0]= rng_getDouble(rng) + amount; + offs[1]= rng_getDouble(rng) + amount; + rng_free(rng); + + for (k = 0; k < n; k++) { + t = 0; + for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) + if (kk & 1) /* kk mod 2 = 1 */ + t += p; + + out[2*k + 0]= fmod((double)k/(double)n + offs[0], 1.0); + out[2*k + 1]= fmod(t + offs[1], 1.0); + } +} + /* modified copy from effect.c */ static void init_mv_jit(float *jit, int num, int seed2, float amount) { @@ -492,7 +591,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C ParticleData *tpa; ParticleSettings *part= ctx->psys->part; float *v1, *v2, *v3, *v4, nor[3], orco1[3], co1[3], co2[3], nor1[3], ornor1[3]; - float cur_d, min_d; + float cur_d, min_d, randu, randv; int from= ctx->from; int cfrom= ctx->cfrom; int distr= ctx->distr; @@ -534,7 +633,9 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C //ctx->jitoff[i]=(float)fmod(ctx->jitoff[i]+ctx->maxweight/ctx->weight[i],(float)ctx->jitlevel); break; case PART_DISTR_RAND: - psys_uv_to_w(rng_getFloat(thread->rng), rng_getFloat(thread->rng), mface->v4, pa->fuv); + randu= rng_getFloat(thread->rng); + randv= rng_getFloat(thread->rng); + psys_uv_to_w(randu, randv, mface->v4, pa->fuv); break; } pa->foffset= 0.0f; @@ -632,7 +733,9 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C // ctx->jitoff[i]=(float)fmod(ctx->jitoff[i]+ctx->maxweight/ctx->weight[i],(float)ctx->jitlevel); // break; // case PART_DISTR_RAND: - psys_uv_to_w(rng_getFloat(thread->rng), rng_getFloat(thread->rng), mf->v4, cpa->fuv); + randu= rng_getFloat(thread->rng); + randv= rng_getFloat(thread->rng); + psys_uv_to_w(randu, randv, mf->v4, cpa->fuv); // break; //} @@ -789,8 +892,16 @@ static int compare_orig_index(const void *p1, const void *p2) if(index1 < index2) return -1; - else if(index1 == index2) - return 0; + else if(index1 == index2) { + /* this pointer comparison appears to make qsort stable for glibc, + * and apparently on solaris too, makes the renders reproducable */ + if(p1 < p2) + return -1; + else if(p1 == p2) + return 0; + else + return 1; + } else return 1; } @@ -863,7 +974,7 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm BLI_kdtree_balance(tree); - totpart=get_alloc_child_particles_tot(psys); + totpart=get_psys_tot_child(psys); cfrom=from=PART_FROM_FACE; if(part->flag&PART_CHILD_SEAMS){ @@ -912,9 +1023,9 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm } else{ /* no need to figure out distribution */ - int child_nbr= (psys->renderdata)? part->ren_child_nbr: part->child_nbr; + int child_nbr= get_psys_child_number(psys); - totpart= get_alloc_child_particles_tot(psys); + totpart= get_psys_tot_child(psys); alloc_child_particles(psys, totpart); cpa=psys->child; for(i=0; i<child_nbr; i++){ @@ -1002,7 +1113,8 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm if(tot==0){ no_distr=1; if(children){ - fprintf(stderr,"Particle child distribution error: Nothing to emit from!\n"); + if(G.f & G_DEBUG) + fprintf(stderr,"Particle child distribution error: Nothing to emit from!\n"); for(p=0,cpa=psys->child; p<totpart; p++,cpa++){ cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]= 0.0; cpa->foffset= 0.0f; @@ -1012,7 +1124,8 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm } } else { - fprintf(stderr,"Particle distribution error: Nothing to emit from!\n"); + if(G.f & G_DEBUG) + fprintf(stderr,"Particle distribution error: Nothing to emit from!\n"); for(p=0,pa=psys->particles; p<totpart; p++,pa++){ pa->fuv[0]=pa->fuv[1]=pa->fuv[2]= pa->fuv[3]= 0.0; pa->foffset= 0.0f; @@ -1196,9 +1309,15 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm //if(jitlevel>100) jitlevel= 100; } - jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit"); + jit= MEM_callocN((2+ jitlevel*2)*sizeof(float), "jit"); - init_mv_jit(jit, jitlevel, psys->seed, part->jitfac); + /* for small amounts of particles we use regular jitter since it looks + * a bit better, for larger amounts we switch to hammersley sequence + * because it is much faster */ + if(jitlevel < 25) + init_mv_jit(jit, jitlevel, psys->seed, part->jitfac); + else + hammersley_create(jit, jitlevel+1, psys->seed, part->jitfac); BLI_array_randomize(jit, 2*sizeof(float), jitlevel, psys->seed); /* for custom jit or even distribution */ } @@ -1243,7 +1362,7 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl ParticleThreadContext *ctx; int i, totthread; - pthreads= psys_threads_create(ob, psys, G.scene->r.threads); + pthreads= psys_threads_create(ob, psys); if(!psys_threads_init_distribution(pthreads, finaldm, from)) { psys_threads_free(pthreads); @@ -1262,8 +1381,7 @@ static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, Particl else exec_distribution(&pthreads[0]); - if (from == PART_FROM_FACE) - psys_calc_dmfaces(ob, finaldm, psys); + psys_calc_dmcache(ob, finaldm, psys); ctx= pthreads[0].ctx; if(ctx->dm != finaldm) @@ -1316,11 +1434,16 @@ static void distribute_particles(Object *ob, ParticleSystem *psys, int from) } /* threaded child particle distribution and path caching */ -ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys, int totthread) +ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys) { ParticleThread *threads; ParticleThreadContext *ctx; - int i; + int i, totthread; + + if(G.scene->r.mode & R_FIXED_THREADS) + totthread= G.scene->r.threads; + else + totthread= BLI_system_thread_count(); threads= MEM_callocN(sizeof(ParticleThread)*totthread, "ParticleThread"); ctx= MEM_callocN(sizeof(ParticleThreadContext), "ParticleThreadContext"); @@ -1407,7 +1530,7 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps BLI_srandom(psys->seed+p); - if(part->from!=PART_FROM_PARTICLE){ + if(part->from!=PART_FROM_PARTICLE && part->type!=PART_FLUID){ ma=give_current_material(ob,part->omat); /* TODO: needs some work to make most blendtypes generally usefull */ @@ -1499,53 +1622,54 @@ static void initialize_all_particles(Object *ob, ParticleSystem *psys, ParticleS for(p=0, pa=psys->particles; p<totpart; p++, pa++) initialize_particle(pa,p,ob,psys,psmd); - /* store the derived mesh face index for each particle */ - icu=find_ipocurve(psys->part->ipo,PART_EMIT_FREQ); - if(icu){ - float time=psys->part->sta, end=psys->part->end; - float v1, v2, a=0.0f, t1,t2, d; - - p=0; - pa=psys->particles; - - calc_icu(icu,time); - v1=icu->curval; - if(v1<0.0f) v1=0.0f; - - calc_icu(icu,time+1.0f); - v2=icu->curval; - if(v2<0.0f) v2=0.0f; - - for(p=0, pa=psys->particles; p<totpart && time<end; p++, pa++){ - while(a+0.5f*(v1+v2) < (float)(p+1) && time<end){ - a+=0.5f*(v1+v2); - v1=v2; - time++; - calc_icu(icu,time+1.0f); - v2=icu->curval; - } - if(time<end){ - if(v1==v2){ - pa->time=time+((float)(p+1)-a)/v1; + if(psys->part->type != PART_FLUID) { + icu=find_ipocurve(psys->part->ipo,PART_EMIT_FREQ); + if(icu){ + float time=psys->part->sta, end=psys->part->end; + float v1, v2, a=0.0f, t1,t2, d; + + p=0; + pa=psys->particles; + + calc_icu(icu,time); + v1=icu->curval; + if(v1<0.0f) v1=0.0f; + + calc_icu(icu,time+1.0f); + v2=icu->curval; + if(v2<0.0f) v2=0.0f; + + for(p=0, pa=psys->particles; p<totpart && time<end; p++, pa++){ + while(a+0.5f*(v1+v2) < (float)(p+1) && time<end){ + a+=0.5f*(v1+v2); + v1=v2; + time++; + calc_icu(icu,time+1.0f); + v2=icu->curval; } - else{ - d=(float)sqrt(v1*v1-2.0f*(v2-v1)*(a-(float)(p+1))); - t1=(-v1+d)/(v2-v1); - t2=(-v1-d)/(v2-v1); + if(time<end){ + if(v1==v2){ + pa->time=time+((float)(p+1)-a)/v1; + } + else{ + d=(float)sqrt(v1*v1-2.0f*(v2-v1)*(a-(float)(p+1))); + t1=(-v1+d)/(v2-v1); + t2=(-v1-d)/(v2-v1); - /* the root between 0-1 is the correct one */ - if(t1>0.0f && t1<=1.0f) - pa->time=time+t1; - else - pa->time=time+t2; + /* the root between 0-1 is the correct one */ + if(t1>0.0f && t1<=1.0f) + pa->time=time+t1; + else + pa->time=time+t2; + } } - } - pa->dietime = pa->time+pa->lifetime; - pa->flag &= ~PARS_UNEXIST; - } - for(; p<totpart; p++, pa++){ - pa->flag |= PARS_UNEXIST; + pa->dietime = pa->time+pa->lifetime; + pa->flag &= ~PARS_UNEXIST; + } + for(; p<totpart; p++, pa++){ + pa->flag |= PARS_UNEXIST; + } } } } @@ -1557,7 +1681,7 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi ParticleTexture ptex; ParticleKey state; IpoCurve *icu=0; - float fac, phasefac, nor[3]={0,0,0},loc[3],tloc[3],vel[3]={0.0,0.0,0.0},rot[4],*q2=0; + float fac, phasefac, nor[3]={0,0,0},loc[3],tloc[3],vel[3]={0.0,0.0,0.0},rot[4],q2[4]; float r_vel[3],r_ave[3],r_rot[4],p_vel[3]={0.0,0.0,0.0}; float x_vec[3]={1.0,0.0,0.0}, utan[3]={0.0,1.0,0.0}, vtan[3]={0.0,0.0,1.0}, rot_vec[3]={0.0,0.0,0.0}; float q_phase[4]; @@ -1579,7 +1703,10 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi /*TODO: get precise location of particle at birth*/ state.time=cfra; - psys_get_particle_state(tob,tpsys,pa->num,&state,1); + if(pa->num == -1) + memset(&state, 0, sizeof(state)); + else + psys_get_particle_state(tob,tpsys,pa->num,&state,1); psys_get_from_key(&state,loc,nor,rot,0); QuatMulVecf(rot,vtan); @@ -1609,9 +1736,8 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi /* get possible textural influence */ psys_get_texture(ob,give_current_material(ob,part->omat),psmd,psys,pa,&ptex,MAP_PA_IVEL); - if(vg_vel){ + if(vg_vel && pa->num != -1) ptex.ivel*=psys_interpolate_value_from_verts(psmd->dm,part->from,pa->num,pa->fuv,vg_vel); - } /* particles live in global space so */ /* let's convert: */ @@ -1733,7 +1859,7 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi /* create rotation quat */ VecMulf(rot_vec,-1.0); - q2= vectoquat(rot_vec, OB_POSX, OB_POSZ); + vectoquat(rot_vec, OB_POSX, OB_POSZ, q2); /* randomize rotation quat */ if(part->randrotfac!=0.0f) @@ -1852,7 +1978,8 @@ int psys_count_keyed_targets(Object *ob, ParticleSystem *psys) BLI_freelistN(&lb); return select; } -void set_keyed_keys(Object *ob, ParticleSystem *psys) + +static void set_keyed_keys(Object *ob, ParticleSystem *psys) { Object *kob = ob; ParticleSystem *kpsys = psys; @@ -1862,17 +1989,16 @@ void set_keyed_keys(Object *ob, ParticleSystem *psys) float prevtime, nexttime, keyedtime; /* no proper targets so let's clear and bail out */ - if(psys->totkeyed==0){ + if(psys->totkeyed==0) { free_keyed_keys(psys); psys->flag &= ~PSYS_KEYED; return; } - if(totpart && psys->particles->totkey != totkeys){ + if(totpart && psys->particles->totkey != totkeys) { free_keyed_keys(psys); - psys->particles->keys = MEM_callocN(psys->totpart * totkeys * sizeof(ParticleKey),"Keyed keys"); - + psys->particles->keys = MEM_callocN(psys->totpart*totkeys*sizeof(ParticleKey), "Keyed keys"); psys->particles->totkey = totkeys; for(i=1, pa=psys->particles+1; i<totpart; i++,pa++){ @@ -1884,9 +2010,10 @@ void set_keyed_keys(Object *ob, ParticleSystem *psys) psys->flag &= ~PSYS_KEYED; state.time=-1.0; - for(k=0; k<totkeys; k++){ - for(i=0,pa=psys->particles; i<totpart; i++, pa++){ - psys_get_particle_state(kob, kpsys, i%kpsys->totpart, pa->keys + k, 1); + for(k=0; k<totkeys; k++) { + for(i=0,pa=psys->particles; i<totpart; i++, pa++) { + if(kpsys->totpart > 0) + psys_get_particle_state(kob, kpsys, i%kpsys->totpart, pa->keys + k, 1); if(k==0) pa->keys->time = pa->time; @@ -2027,56 +2154,57 @@ void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_o /************************************************/ /* Point Cache */ /************************************************/ -void clear_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra) -{ - ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); - int stack_index = modifiers_indexInObject(ob,(ModifierData*)psmd); - BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_ALL, cfra, stack_index); -} static void write_particles_to_cache(Object *ob, ParticleSystem *psys, int cfra) { - FILE *fp = NULL; - ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); + PTCacheID pid; + PTCacheFile *pf; ParticleData *pa; - int stack_index = modifiers_indexInObject(ob,(ModifierData*)psmd); - int i, totpart = psys->totpart; + int i, totpart= psys->totpart; - if(totpart == 0) return; + if(totpart == 0) + return; - fp = BKE_ptcache_id_fopen((ID *)ob, 'w', cfra, stack_index); - if(!fp) return; + BKE_ptcache_id_from_particles(&pid, ob, psys); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, cfra); + if(!pf) + return; + /* assuming struct consists of tightly packed floats */ for(i=0, pa=psys->particles; i<totpart; i++, pa++) - fwrite(&pa->state, sizeof(ParticleKey), 1, fp); + BKE_ptcache_file_write_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float)); - fclose(fp); + BKE_ptcache_file_close(pf); } + static int get_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra) { - FILE *fp = NULL; - ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys); + PTCacheID pid; + PTCacheFile *pf; ParticleData *pa; - int stack_index = modifiers_indexInObject(ob,(ModifierData*)psmd); - int i, totpart = psys->totpart, ret = 1; + int i, totpart= psys->totpart; - if(totpart == 0) return 0; + if(totpart == 0) + return 0; - fp = BKE_ptcache_id_fopen((ID *)ob, 'r', cfra, stack_index); - if(!fp) - ret = 0; - else { - for(i=0, pa=psys->particles; i<totpart; i++, pa++) - if((fread(&pa->state, sizeof(ParticleKey), 1, fp)) != 1) { - ret = 0; - break; - } - - fclose(fp); + BKE_ptcache_id_from_particles(&pid, ob, psys); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, cfra); + if(!pf) + return 0; + + /* assuming struct consists of tightly packed floats */ + for(i=0, pa=psys->particles; i<totpart; i++, pa++) { + if(!BKE_ptcache_file_read_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float))) { + BKE_ptcache_file_close(pf); + return 0; + } } - return ret; + BKE_ptcache_file_close(pf); + + return 1; } + /************************************************/ /* Effectors */ /************************************************/ @@ -2252,12 +2380,10 @@ static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, { TexResult result[4]; float tex_co[3], strength, mag_vec[3]; - int i; - - if(tex==0) return; + int hasrgb; + if(tex==NULL) return; - for(i=0; i<4; i++) - result[i].nor=0; + result[0].nor = result[1].nor = result[2].nor = result[3].nor = 0; strength= force_val*falloff;///(float)pow((double)distance,(double)power); @@ -2273,9 +2399,9 @@ static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, Mat4Mul3Vecfl(obmat,tex_co); } - multitex_ext(tex, tex_co, NULL,NULL, 1, result); + hasrgb = multitex_ext(tex, tex_co, NULL,NULL, 1, result); - if(mode==PFIELD_TEX_RGB){ + if(hasrgb && mode==PFIELD_TEX_RGB){ mag_vec[0]= (0.5f-result->tr)*strength; mag_vec[1]= (0.5f-result->tg)*strength; mag_vec[2]= (0.5f-result->tb)*strength; @@ -2294,7 +2420,7 @@ static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, tex_co[2]+= nabla; multitex_ext(tex, tex_co, NULL,NULL, 1, result+3); - if(mode==PFIELD_TEX_GRAD){ + if(mode==PFIELD_TEX_GRAD || !hasrgb){ /* if we dont have rgb fall back to grad */ mag_vec[0]= (result[0].tin-result[1].tin)*strength; mag_vec[1]= (result[0].tin-result[2].tin)*strength; mag_vec[2]= (result[0].tin-result[3].tin)*strength; @@ -2393,29 +2519,43 @@ static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSy } } + +static void psys_init_effectors_recurs(Object *ob, Object *obsrc, ParticleSystem *psys, ListBase *listb, int level) +{ + Group *group; + GroupObject *go; + unsigned int layer= obsrc->lay; + + if(level>MAX_DUPLI_RECUR) return; + + if(ob->lay & layer) { + if(ob->pd || ob->particlesystem.first) + add_to_effectors(listb, ob, obsrc, psys); + + if(ob->dup_group) { + group= ob->dup_group; + for(go= group->gobject.first; go; go= go->next) + psys_init_effectors_recurs(go->ob, obsrc, psys, listb, level+1); + } + } +} + void psys_init_effectors(Object *obsrc, Group *group, ParticleSystem *psys) { - ListBase *listb=&psys->effectors; + ListBase *listb= &psys->effectors; Base *base; - unsigned int layer= obsrc->lay; listb->first=listb->last=0; if(group) { GroupObject *go; - for(go= group->gobject.first; go; go= go->next) { - if( (go->ob->lay & layer) && (go->ob->pd || go->ob->particlesystem.first)) { - add_to_effectors(listb, go->ob, obsrc, psys); - } - } + for(go= group->gobject.first; go; go= go->next) + psys_init_effectors_recurs(go->ob, obsrc, psys, listb, 0); } else { - for(base = G.scene->base.first; base; base= base->next) { - if( (base->lay & layer) && (base->object->pd || base->object->particlesystem.first)) { - add_to_effectors(listb, base->object, obsrc, psys); - } - } + for(base = G.scene->base.first; base; base= base->next) + psys_init_effectors_recurs(base->object, obsrc, psys, listb, 0); } } @@ -2593,7 +2733,7 @@ static void precalc_effectors(Object *ob, ParticleSystem *psys, ParticleSystemMo /* calculate forces that all effectors apply to a particle*/ -void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, ParticleSystem *psys, float *force_field, float *vel,float framestep, float cfra) +void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, ParticleSystem *psys, float *rootco, float *force_field, float *vel,float framestep, float cfra) { Object *eob; ParticleSystem *epsys; @@ -2640,14 +2780,15 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P if(falloff<=0.0f) ; /* don't do anything */ - else if(pd->forcefield==PFIELD_TEXTURE) + else if(pd->forcefield==PFIELD_TEXTURE) { do_texture_effector(pd->tex, pd->tex_mode, pd->flag&PFIELD_TEX_2D, pd->tex_nabla, - pd->flag & PFIELD_TEX_OBJECT, state->co, eob->obmat, - pd->f_strength, falloff, force_field); - else + pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat, + pd->f_strength, falloff, force_field); + } else { do_physical_effector(pd->forcefield,pd->f_strength,distance, falloff,pd->f_dist,pd->f_damp,eob->obmat[2],vec_to_part, pa->state.vel,force_field,pd->flag&PFIELD_PLANAR); + } } if(ec->type & PSYS_EC_PARTICLE){ int totepart; @@ -2747,7 +2888,7 @@ static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, Parti tvel[0]=tvel[1]=tvel[2]=0.0; /* add effectors */ if(part->type != PART_HAIR) - do_effectors(pa_no,pa,states+i,ob,psys,force,tvel,dfra,fra); + do_effectors(pa_no,pa,states+i,ob,psys,states->co,force,tvel,dfra,fra); /* calculate air-particle interaction */ if(part->dragfac!=0.0f){ @@ -2767,13 +2908,10 @@ static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, Parti /* add global acceleration (gravitation) */ VECADD(force,force,part->acc); - - //VecMulf(force,dtime); /* calculate next state */ VECADD(states[i].vel,states[i].vel,tvel); - //VecMulf(force,0.5f*dt); switch(part->integrator){ case PART_INT_EULER: VECADDFAC(state->co,states->co,states->vel,dtime); @@ -2839,7 +2977,6 @@ static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, Parti } break; } - //VECADD(states[i+1].co,states[i+1].co,force); } /* damp affects final velocity */ @@ -2853,12 +2990,15 @@ static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, Parti VECCOPY(tkey.co,state->co); VECCOPY(tkey.vel,state->vel); tkey.time=state->time; - if(do_guide(&tkey,pa_no,time,&psys->effectors)){ - VECCOPY(state->co,tkey.co); - /* guides don't produce valid velocity */ - VECSUB(state->vel,tkey.co,pa->state.co); - VecMulf(state->vel,1.0f/dtime); - state->time=tkey.time; + + if(part->type != PART_HAIR) { + if(do_guide(&tkey,pa_no,time,&psys->effectors)) { + VECCOPY(state->co,tkey.co); + /* guides don't produce valid velocity */ + VECSUB(state->vel,tkey.co,pa->state.co); + VecMulf(state->vel,1.0f/dtime); + state->time=tkey.time; + } } } static void rotate_particle(ParticleSettings *part, ParticleData *pa, float dfra, float timestep, ParticleKey *state) @@ -2866,7 +3006,7 @@ static void rotate_particle(ParticleSettings *part, ParticleData *pa, float dfra float rotfac, rot1[4], rot2[4]={1.0,0.0,0.0,0.0}, dtime=dfra*timestep; if((part->flag & PART_ROT_DYN)==0){ - if(ELEM(part->avemode,PART_AVE_SPIN,PART_AVE_VEL)){ + if(part->avemode==PART_AVE_SPIN){ float angle; float len1 = VecLength(pa->state.vel); float len2 = VecLength(state->vel); @@ -2879,10 +3019,9 @@ static void rotate_particle(ParticleSettings *part, ParticleData *pa, float dfra angle=Inpf(pa->state.vel,state->vel)/(len1*len2); VecMulf(state->ave,saacos(angle)/dtime); } - } - if(part->avemode == PART_AVE_SPIN) VecRotToQuat(state->vel,dtime*part->avefac,rot2); + } } rotfac=VecLength(state->ave); @@ -3095,7 +3234,6 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part if(ec->vert_cos==0){ /* convert particle coordinates to object coordinates */ Mat4Invert(imat,ob->obmat); - Mat4MulVecfl(imat,co1); Mat4MulVecfl(imat,co2); } @@ -3114,15 +3252,18 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part radius=pa->size; } - if(ec->face_minmax==0 || AabbIntersectAabb(pa_minmax,pa_minmax+3,ec->ob_minmax,ec->ob_minmax+3)) + if(ec->face_minmax==0 || AabbIntersectAabb(pa_minmax,pa_minmax+3,ec->ob_minmax,ec->ob_minmax+3)) { if(psys_intersect_dm(ob,dm,ec->vert_cos,co1,co2,&min_d,&min_face,min_w, ec->face_minmax,pa_minmax,radius,ipoint)){ + min_ob=ob; + if(ec->vert_cos) global=1; else global=0; } + } } } @@ -3146,7 +3287,6 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part mface+=min_face; mvert=dm->getVertDataArray(dm,CD_MVERT); - /* permeability check */ if(BLI_frand()<ob->pd->pdef_perm) through=1; @@ -3155,10 +3295,7 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part if(through==0 && (part->flag & PART_DIE_ON_COL || ob->pd->flag & PDEFLE_KILL_PART)){ pa->dietime = cfra-(1.0f-min_d)*dfra; - VecLerpf(def_loc,co1,co2,min_d); - - if(global==0) - Mat4MulVecfl(ob->obmat,def_loc); + VecLerpf(def_loc,def_loc,state->co,min_d); VECCOPY(state->co,def_loc); VecLerpf(state->vel,pa->state.vel,state->vel,min_d); @@ -3176,10 +3313,19 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part if(part->flag & PART_STICKY){ pa->stick_ob=ob; pa->flag |= PARS_STICKY; - //stick_particle_to_object(ob,pa,state); } } else{ + VECCOPY(co1,def_loc); + VECCOPY(co2,state->co); + + if(global==0){ + /* convert particle coordinates to object coordinates */ + Mat4Invert(imat,ob->obmat); + Mat4MulVecfl(imat,co1); + Mat4MulVecfl(imat,co2); + } + VecLerpf(def_loc,co1,co2,min_d); if(radius>0.0f){ @@ -3774,7 +3920,7 @@ static void boid_brain(BoidVecFunc *bvf, ParticleData *pa, Object *ob, ParticleS static void boid_body(BoidVecFunc *bvf, ParticleData *pa, ParticleSystem *psys, ParticleSettings *part, float timestep, float *acc, ParticleKey *state) { float dvec[3], bvec[3], length, max_vel=part->max_vel; - float *q2, q[4]; + float q2[4], q[4]; float g=9.81f, pa_mass=part->mass; float yvec[3]={0.0,1.0,0.0}, zvec[3]={0.0,0.0,-1.0}, bank; @@ -3856,7 +4002,7 @@ static void boid_body(BoidVecFunc *bvf, ParticleData *pa, ParticleSystem *psys, VECCOPY(dvec,state->vel); VecMulf(dvec,-1.0f); - q2= vectoquat(dvec, OB_POSX, OB_POSZ); + vectoquat(dvec, OB_POSX, OB_POSZ, q2); QuatMul(state->rot,q,q2); @@ -4017,7 +4163,7 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi vg_size=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); for(p=0, pa=psys->particles; p<totpart; p++,pa++){ - if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST)) continue; + if(pa->flag & PARS_UNEXIST) continue; /* set correct ipo timing */ if((part->flag&PART_ABS_TIME)==0 && part->ipo){ @@ -4032,8 +4178,8 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi reset_particle(pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); - if(cfra>pa->time && part->flag & PART_LOOP && (part->flag & PART_LOOP_INSTANT)==0){ - pa->loop=(short)((cfra-pa->time)/pa->lifetime)+1; + if(cfra>pa->time && part->flag & PART_LOOP && part->type!=PART_HAIR){ + pa->loop=(short)((cfra-pa->time)/pa->lifetime); pa->alive=PARS_UNBORN; } else{ @@ -4086,7 +4232,7 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi /* main loop: calculate physics for all particles */ for(p=0, pa=psys->particles, key=outstate; p<totpart; p++,pa++,key++){ - if(pa->flag & (PARS_NO_DISP|PARS_UNEXIST)) continue; + if(pa->flag & PARS_UNEXIST) continue; copy_particle_key(key,&pa->state,1); @@ -4100,38 +4246,38 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi pa_die=0; - if(pa->alive==PARS_UNBORN || pa->alive==PARS_KILLED || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)){ + birthtime = pa->time + pa->loop * pa->lifetime; + + if(pa->alive==PARS_UNBORN + || pa->alive==PARS_KILLED + || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED) + || birthtime >= cfra){ /* allways reset particles to emitter before birth */ reset_particle(pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); copy_particle_key(key,&pa->state,1); } - if(dfra>0.0 || psys->recalc){ + if(1) { if(psys->reactevents.first && ELEM(pa->alive,PARS_DEAD,PARS_KILLED)==0) react_to_events(psys,p); - pa_dfra= dfra; - pa_dtime= dtime; + pa_dfra = dfra; + pa_dtime = dtime; - if(pa->flag & PART_LOOP && pa->flag & PART_LOOP_INSTANT) - birthtime=pa->dietime; - else - birthtime=pa->time+pa->loop*pa->lifetime; - - dietime=birthtime+pa->lifetime; + dietime = birthtime + pa->lifetime; if(birthtime < cfra && birthtime >= psys->cfra){ /* particle is born some time between this and last step*/ - pa->alive=PARS_ALIVE; - pa_dfra= cfra - birthtime; - pa_dtime= pa_dfra*timestep; + pa->alive = PARS_ALIVE; + pa_dfra = cfra - birthtime; + pa_dtime = pa_dfra*timestep; } else if(dietime <= cfra && psys->cfra < dietime){ /* particle dies some time between this and last step */ - pa_dfra= dietime - psys->cfra; - pa_dtime= pa_dfra*timestep; - pa_die=1; + pa_dfra = dietime - psys->cfra; + pa_dtime = pa_dfra * timestep; + pa_die = 1; } else if(dietime < cfra){ /* TODO: figure out if there's something to be done when particle is dead */ @@ -4167,16 +4313,11 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi if(pa_die){ push_reaction(ob,psys,p,PART_EVENT_DEATH,key); - if(part->flag & PART_LOOP){ + if(part->flag & PART_LOOP && part->type!=PART_HAIR){ pa->loop++; - - if(part->flag & PART_LOOP_INSTANT){ - reset_particle(pa,psys,psmd,ob,0.0,cfra,vg_vel,vg_tan,vg_rot); - pa->alive=PARS_ALIVE; - copy_particle_key(key,&pa->state,1); - } - else - pa->alive=PARS_UNBORN; + reset_particle(pa,psys,psmd,ob,0.0,cfra,vg_vel,vg_tan,vg_rot); + copy_particle_key(key,&pa->state,1); + pa->alive=PARS_ALIVE; } else{ pa->alive=PARS_DEAD; @@ -4210,9 +4351,8 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd, ParticleSettings *part=psys->part; ParticleEditSettings *pset=&G.scene->toolsettings->particle; int distr=0,alloc=0; - int child_nbr= (psys->renderdata)? part->ren_child_nbr: part->child_nbr; - if((psys->part->childtype && psys->totchild != psys->totpart*child_nbr) || psys->recalc&PSYS_ALLOC) + if((psys->part->childtype && psys->totchild != get_psys_tot_child(psys)) || psys->recalc&PSYS_ALLOC) alloc=1; if(alloc || psys->recalc&PSYS_DISTR || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT))) @@ -4220,9 +4360,9 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd, if(distr){ if(alloc) - alloc_particles(ob,psys,psys->totpart); + realloc_particles(ob,psys,psys->totpart); - if(get_alloc_child_particles_tot(psys)) { + if(get_psys_tot_child(psys)) { /* don't generate children while computing the hair keys */ if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { distribute_particles(ob,psys,PART_FROM_CHILD); @@ -4251,10 +4391,20 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd, static void hair_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) { ParticleSettings *part = psys->part; + ParticleData *pa; + int p; + float disp = (float)get_current_display_percentage(psys)/50.0f-1.0f; + + for(p=0, pa=psys->particles; p<psys->totpart; p++,pa++){ + if(pa->r_rot[0] > disp) + pa->flag |= PARS_NO_DISP; + else + pa->flag &= ~PARS_NO_DISP; + } if(psys->recalc & PSYS_DISTR) /* need this for changing subsurf levels */ - psys_calc_dmfaces(ob, psmd->dm, psys); + psys_calc_dmcache(ob, psmd->dm, psys); if(psys->effectors.first) psys_end_effectors(psys); @@ -4270,7 +4420,7 @@ static void hair_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSyst } /* updates cached particles' alive & other flags etc..*/ -static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra, float *vg_size) +static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) { ParticleSettings *part=psys->part; ParticleData *pa; @@ -4278,34 +4428,10 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy IpoCurve *icu_esize=find_ipocurve(part->ipo,PART_EMIT_SIZE); Material *ma=give_current_material(ob,part->omat); int p; - float ipotime=cfra, disp; - - /* deprecated */ - //if(psys->recalc&PSYS_DISTR){ - // /* The dm could have been changed so particle emitter element */ - // /* indices might be wrong. There's really no "nice" way to handle*/ - // /* this so we just try not to crash by correcting indices. */ - // int totnum=-1; - // switch(part->from){ - // case PART_FROM_VERT: - // totnum=psmd->dm->getNumVerts(psmd->dm); - // break; - // case PART_FROM_FACE: - // case PART_FROM_VOLUME: - // totnum=psmd->dm->getNumFaces(psmd->dm); - // break; - // } - - // if(totnum==0){ - // /* Now we're in real trouble, there's no emitter elements!! */ - // for(p=0, pa=psys->particles; p<psys->totpart; p++,pa++) - // pa->num=-1; - // } - // else if(totnum>0){ - // for(p=0, pa=psys->particles; p<psys->totpart; p++,pa++) - // pa->num=pa->num%totnum; - // } - //} + float ipotime=cfra, disp, birthtime, dietime, *vg_size= NULL; + + if(part->from!=PART_FROM_PARTICLE) + vg_size= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); if(psys->effectors.first) psys_end_effectors(psys); @@ -4328,22 +4454,30 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy psys->lattice=psys_get_lattice(ob,psys); + if(part->flag & PART_LOOP && part->type!=PART_HAIR) + pa->loop = (short)((cfra - pa->time) / pa->lifetime); + else + pa->loop = 0; + + birthtime = pa->time + pa->loop * pa->lifetime; + dietime = birthtime + (1 + pa->loop) * (pa->dietime - pa->time); + /* update alive status and push events */ - if(pa->time>cfra) - pa->alive=PARS_UNBORN; - else if(pa->dietime<=cfra){ - if(pa->dietime>psys->cfra){ - state.time=pa->dietime; + if(pa->time > cfra) + pa->alive = PARS_UNBORN; + else if(dietime <= cfra){ + if(dietime > psys->cfra){ + state.time = pa->dietime; psys_get_particle_state(ob,psys,p,&state,1); push_reaction(ob,psys,p,PART_EVENT_DEATH,&state); } - pa->alive=PARS_DEAD; + pa->alive = PARS_DEAD; } else{ - pa->alive=PARS_ALIVE; - state.time=cfra; + pa->alive = PARS_ALIVE; + state.time = cfra; psys_get_particle_state(ob,psys,p,&state,1); - state.time=cfra; + state.time = cfra; push_reaction(ob,psys,p,PART_EVENT_NEAR,&state); } @@ -4357,109 +4491,252 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy else pa->flag &= ~PARS_NO_DISP; } + + /* make sure that children are up to date */ + if(psys->part->childtype && psys->totchild != get_psys_tot_child(psys)) { + realloc_particles(ob, psys, psys->totpart); + distribute_particles(ob, psys, PART_FROM_CHILD); + } + + if(vg_size) + MEM_freeN(vg_size); } -/* Calculates the next state for all particles of the system */ -/* In particles code most fra-ending are frames, time-ending are fra*timestep (seconds)*/ -static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) + +void psys_changed_type(ParticleSystem *psys) { ParticleSettings *part; - ParticleData *pa; - int totpart,oldtotpart=0,p; - float disp, *vg_vel=0, *vg_tan=0, *vg_rot=0, *vg_size=0; - int init=0,distr=0,alloc=0; - int child_nbr; - /*----start validity checks----*/ + part= psys->part; - part=psys->part; - - if(part->flag&PART_ABS_TIME && part->ipo){ - calc_ipo(part->ipo, cfra); - execute_ipo((ID *)part, part->ipo); + /* system type has changed so set sensible defaults and clear non applicable flags */ + if(part->from == PART_FROM_PARTICLE) { + if(part->type != PART_REACTOR) + part->from = PART_FROM_FACE; + if(part->distr == PART_DISTR_GRID) + part->distr = PART_DISTR_JIT; } - if(part->from!=PART_FROM_PARTICLE) - vg_size=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); + if(psys->part->phystype != PART_PHYS_KEYED) + psys->flag &= ~PSYS_KEYED; if(part->type == PART_HAIR) { - if(psys->flag & PSYS_HAIR_DONE) { - hair_step(ob, psmd, psys, cfra); - psys->cfra = cfra; - psys->recalc = 0; - return; - } + part->draw_as = PART_DRAW_PATH; + part->rotfrom = PART_ROT_IINCR; } - else if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) - ; /* cache shouldn't be used for "none" or "keyed" physics */ else { - if(psys->recalc && (psys->flag & PSYS_PROTECT_CACHE) == 0) - clear_particles_from_cache(ob,psys,(int)cfra); - else if(get_particles_from_cache(ob, psys, (int)cfra)) { - cached_step(ob,psmd,psys,cfra,vg_size); - psys->cfra=cfra; - psys->recalc = 0; - return; - } + free_hair(psys, 1); + + if(part->draw_as == PART_DRAW_PATH) + if(psys->part->phystype != PART_PHYS_KEYED) + part->draw_as = PART_DRAW_DOT; } - /* if still here react to events */ + psys->softflag= 0; - if(psys->recalc&PSYS_TYPE) { - /* system type has changed so set sensible defaults and clear non applicable flags */ - if(part->from == PART_FROM_PARTICLE) { - if(part->type != PART_REACTOR) - part->from = PART_FROM_FACE; - if(part->distr == PART_DISTR_GRID) - part->distr = PART_DISTR_JIT; + psys_reset(psys, PSYS_RESET_ALL); +} + +static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) +{ + if(psys->particles){ + MEM_freeN(psys->particles); + psys->particles = 0; + psys->totpart = 0; + } + + /* fluid sim particle import handling, actual loading of particles from file */ + #ifndef DISABLE_ELBEEM + if( (1) && (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && // broken, disabled for now! + (ob->fluidsimSettings)) { + ParticleSettings *part = psys->part; + ParticleData *pa=0; + char *suffix = "fluidsurface_particles_####"; + char *suffix2 = ".gz"; + char filename[256]; + char debugStrBuffer[256]; + int curFrame = G.scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading + int p, j, numFileParts, totpart; + int readMask, activeParts = 0, fileParts = 0; + gzFile gzf; + + if(ob==G.obedit) // off... + return; + + // ok, start loading + strcpy(filename, ob->fluidsimSettings->surfdataPath); + strcat(filename, suffix); + BLI_convertstringcode(filename, G.sce); + BLI_convertstringframe(filename, curFrame); // fixed #frame-no + strcat(filename, suffix2); + + gzf = gzopen(filename, "rb"); + if (!gzf) { + snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename); + //elbeemDebugOut(debugStrBuffer); + return; } - if(psys->part->phystype != PART_PHYS_KEYED) - psys->flag &= ~PSYS_KEYED; + gzread(gzf, &totpart, sizeof(totpart)); + numFileParts = totpart; + totpart = (G.rendering)?totpart:(part->disp*totpart)/100; + + part->totpart= totpart; + part->sta=part->end = 1.0f; + part->lifetime = G.scene->r.efra + 1; + + /* initialize particles */ + realloc_particles(ob, psys, part->totpart); + initialize_all_particles(ob, psys, 0); + + // set up reading mask + readMask = ob->fluidsimSettings->typeFlags; + + for(p=0, pa=psys->particles; p<totpart; p++, pa++) { + int ptype=0; + + gzread(gzf, &ptype, sizeof( ptype )); + if(ptype&readMask) { + activeParts++; + + gzread(gzf, &(pa->size), sizeof( float )); + + pa->size /= 10.0f; - if(part->type == PART_HAIR) { - part->draw_as = PART_DRAW_PATH; - part->rotfrom = PART_ROT_IINCR; + for(j=0; j<3; j++) { + float wrf; + gzread(gzf, &wrf, sizeof( wrf )); + pa->state.co[j] = wrf; + //fprintf(stderr,"Rj%d ",j); + } + for(j=0; j<3; j++) { + float wrf; + gzread(gzf, &wrf, sizeof( wrf )); + pa->state.vel[j] = wrf; + } + + pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0f; + pa->state.rot[0] = 1.0; + pa->state.rot[1] = pa->state.rot[2] = pa->state.rot[3] = 0.0; + + pa->alive = PARS_ALIVE; + //if(a<25) fprintf(stderr,"FSPARTICLE debug set %s , a%d = %f,%f,%f , life=%f \n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime ); + } else { + // skip... + for(j=0; j<2*3+1; j++) { + float wrf; gzread(gzf, &wrf, sizeof( wrf )); + } + } + fileParts++; } - else - free_hair(psys); + gzclose( gzf ); - psys->recalc &= ~PSYS_TYPE; - alloc = 1; + totpart = psys->totpart = activeParts; + snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", psys->totpart,activeParts,fileParts,readMask); + elbeemDebugOut(debugStrBuffer); + } // fluid sim particles done + #endif // DISABLE_ELBEEM +} + +/* Calculates the next state for all particles of the system */ +/* In particles code most fra-ending are frames, time-ending are fra*timestep (seconds)*/ +static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) +{ + ParticleSettings *part; + ParticleData *pa; + PointCache *cache; + PTCacheID pid; + int totpart, oldtotpart, totchild, oldtotchild, p; + float disp, *vg_vel= 0, *vg_tan= 0, *vg_rot= 0, *vg_size= 0; + int init= 0, distr= 0, alloc= 0, usecache= 0; + int framenr, framedelta, startframe, endframe; - /* this is a bad level call, but currently type change - * can happen after redraw, so force redraw from here */ - allqueue(REDRAWBUTSOBJECT, 0); + part= psys->part; + cache= psys->pointcache; + + framenr= (int)CFRA; + framedelta= framenr - cache->simframe; + + BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_id_time(&pid, 0.0f, &startframe, &endframe, NULL); + + /* update ipo's */ + if((part->flag & PART_ABS_TIME) && part->ipo) { + calc_ipo(part->ipo, cfra); + execute_ipo((ID *)part, part->ipo); } + + /* hair if it's already done is handled separate */ + if(part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE)) { + hair_step(ob, psmd, psys, cfra); + psys->cfra = cfra; + psys->recalc = 0; + return; + } + /* fluid is also handled separate */ + else if(part->type == PART_FLUID) { + particles_fluid_step(ob, psys, framenr); + psys->cfra = cfra; + psys->recalc = 0; + return; + } + + /* cache shouldn't be used for hair or "none" or "first keyed" physics */ + if(part->type == PART_HAIR || part->phystype == PART_PHYS_NO) + usecache= 0; + else if(part->type == PART_PHYS_KEYED && (psys->flag & PSYS_FIRST_KEYED)) + usecache= 0; + else if(BKE_ptcache_get_continue_physics()) + usecache= 0; else - oldtotpart = psys->totpart; + usecache= 1; + + if(usecache) { + /* frame clamping */ + if(framenr < startframe) { + psys_reset(psys, PSYS_RESET_DEPSGRAPH); + psys->cfra = cfra; + psys->recalc = 0; + return; + } + else if(framenr > endframe) { + framenr= endframe; + } + } + + /* verify if we need to reallocate */ + oldtotpart = psys->totpart; + oldtotchild = psys->totchild; if(part->distr == PART_DISTR_GRID) - totpart = part->grid_res * part->grid_res * part->grid_res; + totpart = part->grid_res*part->grid_res*part->grid_res; else totpart = psys->part->totpart; + totchild = get_psys_tot_child(psys); - child_nbr= (psys->renderdata)? part->ren_child_nbr: part->child_nbr; - if(oldtotpart != totpart || psys->recalc&PSYS_ALLOC || (psys->part->childtype && psys->totchild != psys->totpart*child_nbr)) + if(oldtotpart != totpart || (psys->part->childtype && oldtotchild != totchild)) { + realloc_particles(ob, psys, totpart); alloc = 1; + distr= 1; + init= 1; + } - if(alloc || psys->recalc&PSYS_DISTR || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT) && ob==OBACT)) - distr = 1; - - if(distr || psys->recalc&PSYS_INIT) - init = 1; + if(psys->recalc & PSYS_DISTR) { + distr= 1; + init= 1; + } if(init) { if(distr) { if(alloc) - alloc_particles(ob, psys, totpart); + realloc_particles(ob, psys, totpart); distribute_particles(ob, psys, part->from); if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE)) - /* don't generate children while growing hair - waste of time */ - psys_free_children(psys); - else if(get_alloc_child_particles_tot(psys)) - distribute_particles(ob, psys, PART_FROM_CHILD); + /* don't generate children while growing hair - waste of time */ + psys_free_children(psys); + else if(get_psys_tot_child(psys)) + distribute_particles(ob, psys, PART_FROM_CHILD); } initialize_all_particles(ob, psys, psmd); @@ -4470,17 +4747,62 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier psmd->flag |= eParticleSystemFlag_Pars; } + /* try to read from the cache */ + if(usecache) { + if(get_particles_from_cache(ob, psys, framenr)) { + if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { + psys_count_keyed_targets(ob,psys); + set_keyed_keys(ob, psys); + } + + cached_step(ob,psmd,psys,cfra); + psys->cfra=cfra; + psys->recalc = 0; + + if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { + psys_update_path_cache(ob,psmd,psys,framenr); + } + + cache->simframe= framenr; + cache->flag |= PTCACHE_SIMULATION_VALID; + + return; + } + else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { + psys_reset(psys, PSYS_RESET_DEPSGRAPH); + psys->cfra=cfra; + psys->recalc = 0; + return; + } + + if(framenr != startframe && framedelta != 1) { + psys_reset(psys, PSYS_RESET_DEPSGRAPH); + psys->cfra = cfra; + psys->recalc = 0; + return; + } + } + else { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } + + /* if on second frame, write cache for first frame */ + if(usecache && framenr == startframe+1) + write_particles_to_cache(ob, psys, startframe); if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) psys_count_keyed_targets(ob,psys); - if(part->from!=PART_FROM_PARTICLE){ - vg_vel=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_VEL); - vg_tan=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_TAN); - vg_rot=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROT); + /* initialize vertex groups */ + if(part->from!=PART_FROM_PARTICLE) { + vg_vel= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_VEL); + vg_tan= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_TAN); + vg_rot= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROT); + vg_size= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); } - /* set particles to be not calculated */ + /* set particles to be not calculated TODO: can't work with pointcache */ disp= (float)get_current_display_percentage(psys)/50.0f-1.0f; for(p=0, pa=psys->particles; p<totpart; p++,pa++){ @@ -4493,15 +4815,16 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier /* ok now we're all set so let's go */ if(psys->totpart) dynamics_step(ob,psys,psmd,cfra,vg_vel,vg_tan,vg_rot,vg_size); + + cache->simframe= framenr; + cache->flag |= PTCACHE_SIMULATION_VALID; psys->recalc = 0; psys->cfra = cfra; - if(part->type == PART_HAIR || part->phystype == PART_PHYS_NO - || (part->phystype == PART_PHYS_KEYED && psys->flag & PSYS_FIRST_KEYED)) - ; /* cache shouldn't be used for hair or "none" or "first keyed" physics */ - else - write_particles_to_cache(ob, psys, cfra); + /* only write cache starting from second frame */ + if(usecache && framenr != startframe) + write_particles_to_cache(ob, psys, framenr); /* for keyed particles the path is allways known so it can be drawn */ if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED){ @@ -4511,8 +4834,11 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier else if(psys->pathcache) psys_free_path_cache(psys); - if(vg_vel) - MEM_freeN(vg_vel); + /* cleanup */ + if(vg_vel) MEM_freeN(vg_vel); + if(vg_tan) MEM_freeN(vg_tan); + if(vg_rot) MEM_freeN(vg_rot); + if(vg_size) MEM_freeN(vg_size); if(psys->lattice){ end_latt_deform(); @@ -4520,105 +4846,97 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier } } -void psys_to_softbody(Object *ob, ParticleSystem *psys, int force_recalc) +void psys_to_softbody(Object *ob, ParticleSystem *psys) { SoftBody *sb; short softflag; - if((psys->softflag&OB_SB_ENABLE)==0) return; - - if(psys->recalc || force_recalc) - psys->softflag|=OB_SB_REDO; + if(!(psys->softflag & OB_SB_ENABLE)) + return; /* let's replace the object's own softbody with the particle softbody */ /* a temporary solution before cloth simulation is implemented, jahka */ /* save these */ - sb=ob->soft; - softflag=ob->softflag; + sb= ob->soft; + softflag= ob->softflag; /* swich to new ones */ - ob->soft=psys->soft; - ob->softflag=psys->softflag; + ob->soft= psys->soft; + ob->softflag= psys->softflag; /* do softbody */ sbObjectStep(ob, (float)G.scene->r.cfra, NULL, psys_count_keys(psys)); /* return things back to normal */ - psys->soft=ob->soft; - psys->softflag=ob->softflag; + psys->soft= ob->soft; + psys->softflag= ob->softflag; - ob->soft=sb; - ob->softflag=softflag; + ob->soft= sb; + ob->softflag= softflag; } + static int hair_needs_recalc(ParticleSystem *psys) { - if((psys->flag & PSYS_EDITED)==0 && ( - (psys->flag & PSYS_HAIR_DONE)==0 - || psys->recalc & PSYS_RECALC_HAIR) - ) { + if((psys->flag & PSYS_EDITED)==0 && + ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_HAIR)) { psys->recalc &= ~PSYS_RECALC_HAIR; return 1; } return 0; } -/* main particle update call, checks that things are ok on the large scale before actual particle calculations */ -void particle_system_update(Object *ob, ParticleSystem *psys){ - ParticleSystemModifierData *psmd=0; +/* main particle update call, checks that things are ok on the large scale before actual particle calculations */ +void particle_system_update(Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd; float cfra; if(!psys_check_enabled(ob, psys)) return; - cfra=bsystem_time(ob,(float)CFRA,0.0); + cfra= bsystem_time(ob, CFRA, 0.0f); psmd= psys_get_modifier(ob, psys); /* system was already updated from modifier stack */ - if(psmd->flag&eParticleSystemFlag_psys_updated) { + if(psmd->flag & eParticleSystemFlag_psys_updated) { psmd->flag &= ~eParticleSystemFlag_psys_updated; /* make sure it really was updated to cfra */ - if(psys->cfra==cfra) + if(psys->cfra == cfra) return; } if(!psmd->dm) return; - /* baked path softbody */ - if(psys->part->type==PART_HAIR && psys->soft) - psys_to_softbody(ob, psys, 0); - - /* not needed, this is all handled in hair_step */ - ///* is the mesh changing under the edited particles? */ - //if((psys->flag & PSYS_EDITED) && psys->part->type==PART_HAIR && psys->recalc & PSYS_RECALC_HAIR) { - // /* Just update the particles on the mesh */ - // psys_update_edithair_dmfaces(ob, psmd->dm, psys); - //} - - if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)){ + /* (re-)create hair */ + if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) { float hcfra=0.0f; int i; - free_hair(psys); + + free_hair(psys, 0); /* first step is negative so particles get killed and reset */ - psys->cfra=1.0f; + psys->cfra= 1.0f; for(i=0; i<=psys->part->hair_step; i++){ hcfra=100.0f*(float)i/(float)psys->part->hair_step; - system_step(ob,psys,psmd,hcfra); - save_hair(ob,psys,psmd,hcfra); + system_step(ob, psys, psmd, hcfra); + save_hair(ob, psys, psmd, hcfra); } psys->flag |= PSYS_HAIR_DONE; - - if(psys->softflag&OB_SB_ENABLE) - psys_to_softbody(ob,psys,1); } - system_step(ob,psys,psmd,cfra); + /* handle softbody hair */ + if(psys->part->type==PART_HAIR && psys->soft) + psys_to_softbody(ob, psys); + + /* the main particle system step */ + system_step(ob, psys, psmd, cfra); - Mat4Invert(psys->imat, ob->obmat); /* used for duplicators */ + /* save matrix for duplicators */ + Mat4Invert(psys->imat, ob->obmat); } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 2afcf19427c..7b727528b3d 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1,14 +1,11 @@ /** * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -24,24 +21,39 @@ * * Contributor(s): Campbell Barton <ideasman42@gmail.com> * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ - #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> -#include "BKE_pointcache.h" +#include "MEM_guardedalloc.h" -#include "BKE_utildefines.h" -#include "BKE_global.h" -#include "BKE_library.h" +#include "DNA_ID.h" +#include "DNA_cloth_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" #include "BLI_blenlib.h" + +#include "BKE_cloth.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_pointcache.h" +#include "BKE_softbody.h" #include "BKE_utildefines.h" + #include "blendef.h" /* needed for directory lookup */ @@ -51,30 +63,141 @@ #include "BLI_winstuff.h" #endif +/* untitled blend's need getpid for a unique name */ +#ifdef WIN32 +#include <process.h> +#else +#include <unistd.h> +#endif + +/* Creating ID's */ + +void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) +{ + ParticleSystemModifierData *psmd; + ModifierData *md; + int a; + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= sb; + pid->type= PTCACHE_TYPE_SOFTBODY; + pid->cache= sb->pointcache; + + if(sb->particles) { + psmd= psys_get_modifier(ob, sb->particles); + pid->stack_index= modifiers_indexInObject(ob, (ModifierData*)psmd); + } + else { + for(a=0, md=ob->modifiers.first; md; md=md->next, a++) { + if(md->type == eModifierType_Softbody) { + pid->stack_index = a; + break; + } + } + } +} + +void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= psys; + pid->type= PTCACHE_TYPE_PARTICLES; + pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)psmd); + pid->cache= psys->pointcache; +} + +void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd) +{ + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->data= clmd; + pid->type= PTCACHE_TYPE_CLOTH; + pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)clmd); + pid->cache= clmd->point_cache; +} + +void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) +{ + PTCacheID *pid; + ParticleSystem *psys; + ModifierData *md; + + lb->first= lb->last= NULL; + + if(ob->soft) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_softbody(pid, ob, ob->soft); + BLI_addtail(lb, pid); + } + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_particles(pid, ob, psys); + BLI_addtail(lb, pid); + + if(psys->soft) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_softbody(pid, ob, psys->soft); + BLI_addtail(lb, pid); + } + } + + for(md=ob->modifiers.first; md; md=md->next) { + if(md->type == eModifierType_Cloth) { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md); + BLI_addtail(lb, pid); + } + } +} + /* Takes an Object ID and returns a unique name - id: object id - cfra: frame for the cache, can be negative - stack_index: index in the modifier stack. we can have cache for more then one stack_index */ -static int ptcache_path(char *filename) +static int ptcache_path(PTCacheID *pid, char *filename) { - char dir[FILE_MAX], file[FILE_MAX]; /* we dont want the dir, only the file */ + Library *lib; int i; + + lib= (pid)? pid->ob->id.lib: NULL; + + if (G.relbase_valid || lib) { + char file[FILE_MAX]; /* we dont want the dir, only the file */ + char *blendfilename; + + blendfilename= (lib)? lib->filename: G.sce; + + BLI_split_dirfile_basic(blendfilename, NULL, file); + i = strlen(file); + + /* remove .blend */ + if (i > 6) + file[i-6] = '\0'; + + sprintf(filename, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */ + BLI_add_slash(filename); + BLI_convertstringcode(filename, blendfilename); + return strlen(filename); + } - BLI_split_dirfile(G.sce, dir, file); - i = strlen(file); - - /* remove .blend */ - if (i > 6) - file[i-6] = '\0'; - - sprintf(filename, PTCACHE_PATH"%s/", file); /* add blend file name to pointcache dir */ - BLI_convertstringcode(filename, G.sce, 0); + /* use the temp path. this is weak but better then not using point cache at all */ + /* btempdir is assumed to exist and ALWAYS has a trailing slash */ + sprintf(filename, "%s"PTCACHE_PATH"%d", btempdir, abs(getpid())); + BLI_add_slash(filename); return strlen(filename); } -int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_index, short do_path, short do_ext) +static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext) { int len=0; char *idname; @@ -82,14 +205,14 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i filename[0] = '\0'; newname = filename; - if (!G.relbase_valid) return 0; /* save blend fiel before using pointcache */ + /*if (!G.relbase_valid) return 0; *//* save blend file before using pointcache */ /* start with temp dir */ if (do_path) { - len = ptcache_path(filename); + len = ptcache_path(pid, filename); newname += len; } - idname = (id->name+2); + idname = (pid->ob->id.name+2); /* convert chars to hex so they are always a valid filename */ while('\0' != *idname) { sprintf(newname, "%02X", (char)(*idname++)); @@ -98,7 +221,7 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i } if (do_ext) { - sprintf(newname, "_%06d_%02d"PTCACHE_EXT, cfra, stack_index); /* always 6 chars */ + sprintf(newname, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ len += 16; } @@ -106,39 +229,61 @@ int BKE_ptcache_id_filename(struct ID *id, char *filename, int cfra, int stack_i } /* youll need to close yourself after! */ -FILE *BKE_ptcache_id_fopen(struct ID *id, char mode, int cfra, int stack_index) +PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra) { - /* mode is same as fopen's modes */ + PTCacheFile *pf; FILE *fp = NULL; char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; - if (!G.relbase_valid) return NULL; /* save blend fiel before using pointcache */ + /* don't allow writing for linked objects */ + if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE) + return NULL; + + /*if (!G.relbase_valid) return NULL; *//* save blend file before using pointcache */ - BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); - if (mode=='r') { + if (mode==PTCACHE_FILE_READ) { if (!BLI_exists(filename)) { return NULL; } fp = fopen(filename, "rb"); - } else if (mode=='w') { + } else if (mode==PTCACHE_FILE_WRITE) { BLI_make_existing_file(filename); /* will create the dir if needs be, same as //textures is created */ fp = fopen(filename, "wb"); } - if (!fp) { + if (!fp) return NULL; - } + + pf= MEM_mallocN(sizeof(PTCacheFile), "PTCacheFile"); + pf->fp= fp; - return fp; + return pf; +} + +void BKE_ptcache_file_close(PTCacheFile *pf) +{ + fclose(pf->fp); + MEM_freeN(pf); +} + +int BKE_ptcache_file_read_floats(PTCacheFile *pf, float *f, int tot) +{ + return (fread(f, sizeof(float), tot, pf->fp) == tot); +} + +int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot) +{ + return (fwrite(f, sizeof(float), tot, pf->fp) == tot); } /* youll need to close yourself after! - * mode, + * mode - PTCACHE_CLEAR_ALL, */ -void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) +void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) { int len; /* store the length of the string */ @@ -148,16 +293,24 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) char path[FILE_MAX]; char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; char path_full[(FILE_MAXDIR+FILE_MAXFILE)*2]; - - if (!G.relbase_valid) return; /* save blend fiel before using pointcache */ + + if(!pid->cache) + return; + + /* don't allow clearing for linked objects */ + if(pid->ob->id.lib) + return; + + /*if (!G.relbase_valid) return; *//* save blend file before using pointcache */ /* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */ switch (mode) { case PTCACHE_CLEAR_ALL: case PTCACHE_CLEAR_BEFORE: case PTCACHE_CLEAR_AFTER: - ptcache_path(path); - len = BKE_ptcache_id_filename(id, filename, cfra, stack_index, 0, 0); /* no path */ + ptcache_path(pid, path); + + len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */ dir = opendir(path); if (dir==NULL) @@ -192,18 +345,240 @@ void BKE_ptcache_id_clear(struct ID *id, char mode, int cfra, int stack_index) break; case PTCACHE_CLEAR_FRAME: - len = BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); /* no path */ + len = BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */ BLI_delete(filename, 0, 0); break; } - return; } -int BKE_ptcache_id_exist(struct ID *id, int cfra, int stack_index) +int BKE_ptcache_id_exist(PTCacheID *pid, int cfra) { char filename[(FILE_MAXDIR+FILE_MAXFILE)*2]; + + if(!pid->cache) + return 0; - BKE_ptcache_id_filename(id, filename, cfra, stack_index, 1, 1); + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); return BLI_exists(filename); } + +void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endframe, float *timescale) +{ + Object *ob; + PointCache *cache; + float offset, time, nexttime; + + /* time handling for point cache: + * - simulation time is scaled by result of bsystem_time + * - for offsetting time only time offset is taken into account, since + * that's always the same and can't be animated. a timeoffset which + * varies over time is not simpe to support. + * - field and motion blur offsets are currently ignored, proper solution + * is probably to interpolate results from two frames for that .. + */ + + ob= pid->ob; + cache= pid->cache; + + if(timescale) { + time= bsystem_time(ob, cfra, 0.0f); + nexttime= bsystem_time(ob, cfra+1.0f, 0.0f); + + *timescale= MAX2(nexttime - time, 0.0f); + } + + if(startframe && endframe) { + *startframe= cache->startframe; + *endframe= cache->endframe; + + if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) { + offset= give_timeoffset(ob); + + *startframe += (int)(offset+0.5f); + *endframe += (int)(offset+0.5f); + } + } +} + +int BKE_ptcache_id_reset(PTCacheID *pid, int mode) +{ + PointCache *cache; + int reset, clear; + + if(!pid->cache) + return 0; + + cache= pid->cache; + reset= 0; + clear= 0; + + if(mode == PTCACHE_RESET_DEPSGRAPH) { + if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) { + reset= 1; + clear= 1; + } + else + cache->flag |= PTCACHE_OUTDATED; + } + else if(mode == PTCACHE_RESET_BAKED) { + if(!BKE_ptcache_get_continue_physics()) { + reset= 1; + clear= 1; + } + else + cache->flag |= PTCACHE_OUTDATED; + } + else if(mode == PTCACHE_RESET_OUTDATED) { + reset = 1; + + if(cache->flag & PTCACHE_OUTDATED) + if(!(cache->flag & PTCACHE_BAKED)) + clear= 1; + } + + if(reset) { + cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_SIMULATION_VALID); + cache->simframe= 0; + + if(pid->type == PTCACHE_TYPE_CLOTH) + cloth_free_modifier(pid->ob, pid->data); + else if(pid->type == PTCACHE_TYPE_SOFTBODY) + sbFreeSimulation(pid->data); + else if(pid->type == PTCACHE_TYPE_PARTICLES) + psys_reset(pid->data, PSYS_RESET_DEPSGRAPH); + } + if(clear) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + return (reset || clear); +} + +int BKE_ptcache_object_reset(Object *ob, int mode) +{ + PTCacheID pid; + ParticleSystem *psys; + ModifierData *md; + int reset; + + reset= 0; + + if(ob->soft) { + BKE_ptcache_id_from_softbody(&pid, ob, ob->soft); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + + for(psys=ob->particlesystem.first; psys; psys=psys->next) { + BKE_ptcache_id_from_particles(&pid, ob, psys); + reset |= BKE_ptcache_id_reset(&pid, mode); + + if(psys->soft) { + BKE_ptcache_id_from_softbody(&pid, ob, psys->soft); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + } + + for(md=ob->modifiers.first; md; md=md->next) { + if(md->type == eModifierType_Cloth) { + BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md); + reset |= BKE_ptcache_id_reset(&pid, mode); + } + } + + return reset; +} + +/* Use this when quitting blender, with unsaved files */ +void BKE_ptcache_remove(void) +{ + char path[FILE_MAX]; + char path_full[FILE_MAX]; + int rmdir = 1; + + ptcache_path(NULL, path); + + if (BLI_exist(path)) { + /* The pointcache dir exists? - remove all pointcache */ + + DIR *dir; + struct dirent *de; + + dir = opendir(path); + if (dir==NULL) + return; + + while ((de = readdir(dir)) != NULL) { + if( strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) { + /* do nothing */ + } else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/ + BLI_join_dirfile(path_full, path, de->d_name); + BLI_delete(path_full, 0, 0); + } else { + rmdir = 0; /* unknown file, dont remove the dir */ + } + } + + closedir(dir); + } else { + rmdir = 0; /* path dosnt exist */ + } + + if (rmdir) { + BLI_delete(path, 1, 0); + } +} + +/* Continuous Interaction */ + +static int CONTINUE_PHYSICS = 0; + +void BKE_ptcache_set_continue_physics(int enable) +{ + Object *ob; + + if(CONTINUE_PHYSICS != enable) { + CONTINUE_PHYSICS = enable; + + if(CONTINUE_PHYSICS == 0) { + for(ob=G.main->object.first; ob; ob=ob->id.next) + if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_OUTDATED)) + DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + } + } +} + +int BKE_ptcache_get_continue_physics() +{ + return CONTINUE_PHYSICS; +} + +/* Point Cache */ + +PointCache *BKE_ptcache_add() +{ + PointCache *cache; + + cache= MEM_callocN(sizeof(PointCache), "PointCache"); + cache->startframe= 1; + cache->endframe= 250; + + return cache; +} + +void BKE_ptcache_free(PointCache *cache) +{ + MEM_freeN(cache); +} + +PointCache *BKE_ptcache_copy(PointCache *cache) +{ + PointCache *ncache; + + ncache= MEM_dupallocN(cache); + + ncache->flag= 0; + ncache->simframe= 0; + + return ncache; +} + diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c index a60c03c4840..f55bdd15279 100644 --- a/source/blender/blenkernel/intern/property.c +++ b/source/blender/blenkernel/intern/property.c @@ -4,15 +4,12 @@ * ton roosendaal * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index e772a3bcdb4..86e395b3770 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** * these all are linked to objects (listbase) * all data is 'direct data', not Blender lib data. */ @@ -461,6 +458,12 @@ void init_actuator(bActuator *act) case ACT_VISIBILITY: act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act"); break; + case ACT_2DFILTER: + act->data = MEM_callocN(sizeof( bTwoDFilterActuator ), "2d filter act"); + break; + case ACT_PARENT: + act->data = MEM_callocN(sizeof( bParentActuator ), "parent act"); + break; default: ; /* this is very severe... I cannot make any memory for this */ /* logic brick... */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 23aca38463b..6798c3c47b7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -82,6 +79,7 @@ #include "BKE_utildefines.h" #include "BIF_previewrender.h" +#include "BIF_editseq.h" #include "BPY_extern.h" #include "BLI_arithb.h" @@ -220,6 +218,15 @@ Scene *add_scene(char *name) sce->r.stereomode = 1; // no stereo + sce->r.simplify_subsurf= 6; + sce->r.simplify_particles= 1.0f; + sce->r.simplify_shadowsamples= 16; + sce->r.simplify_aosss= 1.0f; + + sce->r.cineonblack= 95; + sce->r.cineonwhite= 685; + sce->r.cineongamma= 1.7f; + sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings),"Tool Settings Struct"); sce->toolsettings->cornertype=1; sce->toolsettings->degr = 90; @@ -262,7 +269,7 @@ Scene *add_scene(char *name) sce->r.osa= 8; sculptdata_init(sce); - + /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */ scene_add_render_layer(sce); @@ -289,6 +296,9 @@ void set_scene_bg(Scene *sce) GroupObject *go; int flag; + // Note: this here is defined in editseq.c (BIF_editseq.h), NOT in blenkernel! + set_last_seq(NULL); + G.scene= sce; /* check for cyclic sets, for reading old files but also for definite security (py?) */ @@ -417,6 +427,9 @@ int next_object(int val, Base **base, Object **ob) duplilist= object_duplilist(G.scene, (*base)->object); dupob= duplilist->first; + + if(!dupob) + free_object_duplilist(duplilist); } } } @@ -498,27 +511,23 @@ void scene_select_base(Scene *sce, Base *selbase) int scene_check_setscene(Scene *sce) { Scene *scene; + int a, totscene; if(sce->set==NULL) return 1; - /* LIB_DOIT is the free flag to tag library data */ + totscene= 0; for(scene= G.main->scene.first; scene; scene= scene->id.next) - scene->id.flag &= ~LIB_DOIT; - - scene= sce; - while(scene->set) { - scene->id.flag |= LIB_DOIT; - /* when set has flag set, we got a cycle */ - if(scene->set->id.flag & LIB_DOIT) - break; - scene= scene->set; - } - - if(scene->set) { - /* the tested scene gets zero'ed, that's typically current scene */ - sce->set= NULL; - return 0; + totscene++; + + for(a=0, scene=sce; scene->set; scene=scene->set, a++) { + /* more iterations than scenes means we have a cycle */ + if(a > totscene) { + /* the tested scene gets zero'ed, that's typically current scene */ + sce->set= NULL; + return 0; + } } + return 1; } @@ -591,8 +600,10 @@ void sculptdata_init(Scene *sce) sd= &sce->sculptdata; - if(sd->cumap) + if(sd->cumap) { curvemapping_free(sd->cumap); + sd->cumap = NULL; + } memset(sd, 0, sizeof(SculptData)); @@ -604,9 +615,9 @@ void sculptdata_init(Scene *sce) sd->grabbrush.strength = sd->layerbrush.strength = sd->flattenbrush.strength = 25; sd->drawbrush.dir = sd->pinchbrush.dir = sd->inflatebrush.dir = sd->layerbrush.dir= 1; - sd->drawbrush.airbrush = sd->smoothbrush.airbrush = - sd->pinchbrush.airbrush = sd->inflatebrush.airbrush = - sd->layerbrush.airbrush = sd->flattenbrush.airbrush = 0; + sd->drawbrush.flag = sd->smoothbrush.flag = + sd->pinchbrush.flag = sd->inflatebrush.flag = + sd->layerbrush.flag = sd->flattenbrush.flag = 0; sd->drawbrush.view= 0; sd->brush_type= DRAW_BRUSH; sd->texact= -1; @@ -701,3 +712,38 @@ void sculpt_reset_curve(SculptData *sd) curvemapping_changed(sd->cumap, 0); } + +/* render simplification */ + +int get_render_subsurf_level(RenderData *r, int lvl) +{ + if(G.rt == 1 && (r->mode & R_SIMPLIFY)) + return MIN2(r->simplify_subsurf, lvl); + else + return lvl; +} + +int get_render_child_particle_number(RenderData *r, int num) +{ + if(G.rt == 1 && (r->mode & R_SIMPLIFY)) + return (int)(r->simplify_particles*num); + else + return num; +} + +int get_render_shadow_samples(RenderData *r, int samples) +{ + if(G.rt == 1 && (r->mode & R_SIMPLIFY) && samples > 0) + return MIN2(r->simplify_shadowsamples, samples); + else + return samples; +} + +float get_render_aosss_error(RenderData *r, float error) +{ + if(G.rt == 1 && (r->mode & R_SIMPLIFY)) + return ((1.0f-r->simplify_aosss)*10.0f + 1.0f)*error; + else + return error; +} + diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 5e8735147c3..7a45493e1f4 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <string.h> diff --git a/source/blender/blenkernel/intern/script.c b/source/blender/blenkernel/intern/script.c index b99c2c51441..b93821da218 100644 --- a/source/blender/blenkernel/intern/script.c +++ b/source/blender/blenkernel/intern/script.c @@ -5,15 +5,12 @@ * * Function(s) related to struct script management. * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,11 +28,11 @@ * * Contributor(s): Willian P. Germano. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include "BKE_script.h" -#include "BPI_script.h" +#include "DNA_space_types.h" #include "MEM_guardedalloc.h" #include "BKE_bad_level_calls.h" /* for BPY_clear_script */ @@ -60,12 +57,5 @@ void free_script (Script *script) { if (!script) return; - - if (script->py_globaldict || script->py_button || - script->py_event || script->py_draw) - { - BPY_clear_script(script); - } - - return; + BPY_clear_script(script); } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 7c427d3c434..768f5ff980e 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2,15 +2,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -28,7 +25,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ /* @@ -87,7 +84,7 @@ variables on the UI for now #include "BIF_editdeform.h" #include "BIF_graphics.h" #include "PIL_time.h" -#include "ONL_opennl.h" +// #include "ONL_opennl.h" remove linking to ONL for now /* callbacks for errors and interrupts and some goo */ static int (*SB_localInterruptCallBack)(void) = NULL; @@ -106,7 +103,7 @@ typedef struct BodySpring { typedef struct BodyFace { int v1, v2, v3 ,v4; - float ext_force[3]; /* edges colliding and sailing */ + float ext_force[3]; /* faces colliding */ short flag; } BodyFace; @@ -135,7 +132,9 @@ typedef struct SBScratch { #define BSF_INTERSECT 1 /* edge intersects collider face */ #define SBF_DOFUZZY 1 /* edge intersects collider face */ -#define BFF_INTERSECT 1 /* edge intersects collider face */ + +#define BFF_INTERSECT 1 /* collider edge intrudes face */ +#define BFF_CLOSEVERT 2 /* collider vertex repulses face */ float SoftHeunTol = 1.0f; /* humm .. this should be calculated from sb parameters and sizes */ @@ -786,7 +785,7 @@ static void calculate_collision_balls(Object *ob) bs = sb->bspring + bp->springs[b-1]; if (bs->order == 1){ akku += bs->len; - akku_count++; + akku_count++, min = MIN2(bs->len,min); max = MAX2(bs->len,max); } @@ -814,50 +813,6 @@ static void calculate_collision_balls(Object *ob) } -char set_octant_flags(float *ce, float *pos, float ball) -{ - float x,y,z; - char res = 0; - int a; - - for (a=0;a<7;a++){ - switch(a){ - case 0: x=pos[0]; y=pos[1]; z=pos[2]; break; - case 1: x=pos[0]+ball; y=pos[1]; z=pos[2]; break; - case 2: x=pos[0]-ball; y=pos[1]; z=pos[2]; break; - case 3: x=pos[0]; y=pos[1]+ball; z=pos[2]; break; - case 4: x=pos[0]; y=pos[1]-ball; z=pos[2]; break; - case 5: x=pos[0]; y=pos[1]; z=pos[2]+ball; break; - case 6: x=pos[0]; y=pos[1]; z=pos[2]-ball; break; - } - - x=pos[0]; y=pos[1]; z=pos[2]; - - if (x > ce[0]){ - if (y > ce[1]){ - if (z > ce[2]) res|= 1; - else res|= 2; - } - else{ - if (z > ce[2]) res|= 4; - else res|= 8; - } - } - - else{ - if (y > ce[1]){ - if (z > ce[2]) res|= 16; - else res|= 32; - } - else{ - if (z > ce[2]) res|= 64; - else res|= 128; - } - } - } - return res; -} - /* creates new softbody if didn't exist yet, makes new points and springs arrays */ static void renew_softbody(Object *ob, int totpoint, int totspring) { @@ -892,6 +847,8 @@ static void renew_softbody(Object *ob, int totpoint, int totspring) bp->nofsprings= 0; bp->springs= NULL; bp->choke = 0.0f; + bp->choke2 = 0.0f; + bp->frozen = 1.0f; bp->colball = 0.0f; bp->flag = 0; @@ -996,6 +953,7 @@ static void Vec3PlusStVec(float *v, float s, float *v1) } /* +++ dependancy information functions*/ + static int are_there_deflectors(unsigned int layer) { Base *base; @@ -1013,38 +971,9 @@ static int query_external_colliders(Object *me) { return(are_there_deflectors(me->lay)); } - -#if 0 -static int query_external_forces(Object *me) -{ -/* silly but true: we need to create effector cache to see if anything is in it */ - ListBase *ec = pdInitEffectors(me,NULL); - int result = 0; - if (ec){ - result = 1; - pdEndEffectors(ec); /* sorry ec, yes i'm an idiot, but i needed to know if you were there */ - } - return result; -} - -/* -any of that external objects may have an IPO or something alike .. -so unless we can ask them if they are moving we have to assume they do -*/ -static int query_external_time(Object *me) -{ - if (query_external_colliders(me)) return 1; - if (query_external_forces(me)) return 1; - return 0; -} -static int query_internal_time(Object *me) -{ - if (me->softflag & OB_SB_GOAL) return 1; - return 0; -} -#endif /* --- dependancy information functions*/ + /* +++ the aabb "force" section*/ int sb_detect_aabb_collisionCached( float force[3], unsigned int par_layer,struct Object *vertexowner,float time) { @@ -1110,6 +1039,103 @@ int sb_detect_aabb_collisionCached( float force[3], unsigned int par_layer,struc /* +++ the face external section*/ +int sb_detect_face_pointCached(float face_v1[3],float face_v2[3],float face_v3[3],float *damp, + float force[3], unsigned int par_layer,struct Object *vertexowner,float time) + { + Object *ob; + GHash *hash; + GHashIterator *ihash; + float nv1[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3]; + float facedist,outerfacethickness,tune = 10.f; + int a, deflected=0; + + aabbmin[0] = MIN3(face_v1[0],face_v2[0],face_v3[0]); + aabbmin[1] = MIN3(face_v1[1],face_v2[1],face_v3[1]); + aabbmin[2] = MIN3(face_v1[2],face_v2[2],face_v3[2]); + aabbmax[0] = MAX3(face_v1[0],face_v2[0],face_v3[0]); + aabbmax[1] = MAX3(face_v1[1],face_v2[1],face_v3[1]); + aabbmax[2] = MAX3(face_v1[2],face_v2[2],face_v3[2]); + + /* calculate face normal once again SIGH */ + VECSUB(edge1, face_v1, face_v2); + VECSUB(edge2, face_v3, face_v2); + Crossf(d_nvect, edge2, edge1); + Normalize(d_nvect); + + + hash = vertexowner->soft->scratch->colliderhash; + ihash = BLI_ghashIterator_new(hash); + while (!BLI_ghashIterator_isDone(ihash) ) { + + ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); + ob = BLI_ghashIterator_getKey (ihash); + /* only with deflecting set */ + if(ob->pd && ob->pd->deflect) { + MVert *mvert= NULL; + MVert *mprevvert= NULL; + if(ccdm){ + mvert= ccdm->mvert; + a = ccdm->totvert; + mprevvert= ccdm->mprevvert; + outerfacethickness =ob->pd->pdef_sboft; + if ((aabbmax[0] < ccdm->bbmin[0]) || + (aabbmax[1] < ccdm->bbmin[1]) || + (aabbmax[2] < ccdm->bbmin[2]) || + (aabbmin[0] > ccdm->bbmax[0]) || + (aabbmin[1] > ccdm->bbmax[1]) || + (aabbmin[2] > ccdm->bbmax[2]) ) { + /* boxes dont intersect */ + BLI_ghashIterator_step(ihash); + continue; + } + + } + else{ + /*aye that should be cached*/ + printf("missing cache error \n"); + BLI_ghashIterator_step(ihash); + continue; + } + + + /* use mesh*/ + if (mvert) { + while(a){ + VECCOPY(nv1,mvert[a-1].co); + if(mprevvert){ + VecMulf(nv1,time); + Vec3PlusStVec(nv1,(1.0f-time),mprevvert[a-1].co); + } + /* origin to face_v2*/ + VECSUB(nv1, nv1, face_v2); + facedist = Inpf(nv1,d_nvect); + if (ABS(facedist)<outerfacethickness){ + if (point_in_tri_prism(nv1, face_v1,face_v2,face_v3) ){ + float df; + if (facedist > 0){ + df = (outerfacethickness-facedist)/outerfacethickness; + } + else { + df = (outerfacethickness+facedist)/outerfacethickness; + } + + *damp=df*tune*ob->pd->pdef_sbdamp; + + df = 0.01f*exp(- 100.0f*df); + Vec3PlusStVec(force,-df,d_nvect); + deflected = 3; + } + } + a--; + }/* while(a)*/ + } /* if (mvert) */ + } /* if(ob->pd && ob->pd->deflect) */ + BLI_ghashIterator_step(ihash); + } /* while () */ + BLI_ghashIterator_free(ihash); + return deflected; +} + int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_v3[3],float *damp, float force[3], unsigned int par_layer,struct Object *vertexowner,float time) @@ -1118,7 +1144,7 @@ int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_ GHash *hash; GHashIterator *ihash; float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3]; - float t; + float t,tune = 10.0f; int a, deflected=0; aabbmin[0] = MIN3(face_v1[0],face_v2[0],face_v3[0]); @@ -1217,8 +1243,8 @@ int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_ LineIntersectsTriangle(nv1, nv2, face_v1, face_v2, face_v3, &t, NULL) || LineIntersectsTriangle(nv2, nv3, face_v1, face_v2, face_v3, &t, NULL) || LineIntersectsTriangle(nv3, nv1, face_v1, face_v2, face_v3, &t, NULL) ){ - Vec3PlusStVec(force,-1.0f,d_nvect); - *damp=ob->pd->pdef_sbdamp; + Vec3PlusStVec(force,-0.5f,d_nvect); + *damp=tune*ob->pd->pdef_sbdamp; deflected = 2; } if (mface->v4){ /* quad */ @@ -1228,11 +1254,12 @@ int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_ Crossf(d_nvect, edge2, edge1); Normalize(d_nvect); if ( - LineIntersectsTriangle(nv1, nv3, face_v1, face_v2, face_v3, &t, NULL) || + /* LineIntersectsTriangle(nv1, nv3, face_v1, face_v2, face_v3, &t, NULL) || + we did that edge allready */ LineIntersectsTriangle(nv3, nv4, face_v1, face_v2, face_v3, &t, NULL) || LineIntersectsTriangle(nv4, nv1, face_v1, face_v2, face_v3, &t, NULL) ){ - Vec3PlusStVec(force,-1.0f,d_nvect); - *damp=ob->pd->pdef_sbdamp; + Vec3PlusStVec(force,-0.5f,d_nvect); + *damp=tune*ob->pd->pdef_sbdamp; deflected = 2; } } @@ -1253,7 +1280,7 @@ void scan_for_ext_face_forces(Object *ob,float timenow) SoftBody *sb = ob->soft; BodyFace *bf; int a; - float damp; + float damp=0.0f,choke=1.0f; float tune = -10.0f; float feedback[3]; @@ -1263,43 +1290,71 @@ void scan_for_ext_face_forces(Object *ob,float timenow) bf = sb->scratch->bodyface; for(a=0; a<sb->scratch->totface; a++, bf++) { bf->ext_force[0]=bf->ext_force[1]=bf->ext_force[2]=0.0f; +/*+++edges intruding*/ + bf->flag &= ~BFF_INTERSECT; feedback[0]=feedback[1]=feedback[2]=0.0f; - bf->flag &= ~BFF_INTERSECT; - if (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos, &damp, feedback, ob->lay ,ob , timenow)){ - Vec3PlusStVec(bf->ext_force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v2].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); +// Vec3PlusStVec(bf->ext_force,tune,feedback); bf->flag |= BFF_INTERSECT; + choke = MIN2(MAX2(damp,choke),1.0f); } feedback[0]=feedback[1]=feedback[2]=0.0f; if ((bf->v4) && (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v3].pos, sb->bpoint[bf->v4].pos, &damp, feedback, ob->lay ,ob , timenow))){ - Vec3PlusStVec(bf->ext_force,tune,feedback); - bf->flag |= BFF_INTERSECT; + Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v4].force,tune,feedback); +// Vec3PlusStVec(bf->ext_force,tune,feedback); + bf->flag |= BFF_INTERSECT; + choke = MIN2(MAX2(damp,choke),1.0f); } - } +/*---edges intruding*/ + +/*+++ close vertices*/ + if (( bf->flag & BFF_INTERSECT)==0){ + bf->flag &= ~BFF_CLOSEVERT; + tune = -1.0f; + feedback[0]=feedback[1]=feedback[2]=0.0f; + if (sb_detect_face_pointCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos, + &damp, feedback, ob->lay ,ob , timenow)){ + Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v2].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); +// Vec3PlusStVec(bf->ext_force,tune,feedback); + bf->flag |= BFF_CLOSEVERT; + choke = MIN2(MAX2(damp,choke),1.0f); + } - - + feedback[0]=feedback[1]=feedback[2]=0.0f; + if ((bf->v4) && (sb_detect_face_pointCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v3].pos, sb->bpoint[bf->v4].pos, + &damp, feedback, ob->lay ,ob , timenow))){ + Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); + Vec3PlusStVec(sb->bpoint[bf->v4].force,tune,feedback); +// Vec3PlusStVec(bf->ext_force,tune,feedback); + bf->flag |= BFF_CLOSEVERT; + choke = MIN2(MAX2(damp,choke),1.0f); + } + } +/*--- close vertices*/ + } bf = sb->scratch->bodyface; for(a=0; a<sb->scratch->totface; a++, bf++) { - if ( bf->flag & BFF_INTERSECT) + if (( bf->flag & BFF_INTERSECT) || ( bf->flag & BFF_CLOSEVERT)) { - VECADD(sb->bpoint[bf->v1].force,sb->bpoint[bf->v1].force,bf->ext_force); - VECADD(sb->bpoint[bf->v2].force,sb->bpoint[bf->v2].force,bf->ext_force); - VECADD(sb->bpoint[bf->v3].force,sb->bpoint[bf->v3].force,bf->ext_force); + sb->bpoint[bf->v1].choke2=MAX2(sb->bpoint[bf->v1].choke2,choke); + sb->bpoint[bf->v2].choke2=MAX2(sb->bpoint[bf->v2].choke2,choke); + sb->bpoint[bf->v3].choke2=MAX2(sb->bpoint[bf->v3].choke2,choke); if (bf->v4){ - VECADD(sb->bpoint[bf->v4].force,sb->bpoint[bf->v4].force,bf->ext_force); + sb->bpoint[bf->v2].choke2=MAX2(sb->bpoint[bf->v2].choke2,choke); } - - } - + } } - - - - } } @@ -1851,253 +1906,6 @@ int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], float * return deflected; } -/* not complete yet .. - try to find a pos resolving all inside collisions -*/ -#if 0 //mute it for now -int sb_detect_vertex_collisionCachedEx(float opco[3], float facenormal[3], float *damp, - float force[3], unsigned int par_layer,struct Object *vertexowner, - float time,float vel[3], float *intrusion) -{ - Object *ob; - GHash *hash; - GHashIterator *ihash; - float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3], - vv1[3], vv2[3], vv3[3], vv4[3], - facedist,n_mag,force_mag_norm,minx,miny,minz,maxx,maxy,maxz, - innerfacethickness,outerfacethickness, - closestinside, - ee = 5.0f, ff = 0.1f, fa; - int a, deflected=0, cavel=0; -/* init */ - *intrusion = 0.0f; - hash = vertexowner->soft->scratch->colliderhash; - ihash = BLI_ghashIterator_new(hash); -/* go */ - while (!BLI_ghashIterator_isDone(ihash) ) { - - ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); - ob = BLI_ghashIterator_getKey (ihash); - /* only with deflecting set */ - if(ob->pd && ob->pd->deflect) { - MFace *mface= NULL; - MVert *mvert= NULL; - MVert *mprevvert= NULL; - ccdf_minmax *mima= NULL; - - if(ccdm){ - mface= ccdm->mface; - mvert= ccdm->mvert; - mprevvert= ccdm->mprevvert; - mima= ccdm->mima; - a = ccdm->totface; - - minx =ccdm->bbmin[0]; - miny =ccdm->bbmin[1]; - minz =ccdm->bbmin[2]; - - maxx =ccdm->bbmax[0]; - maxy =ccdm->bbmax[1]; - maxz =ccdm->bbmax[2]; - - if ((opco[0] < minx) || - (opco[1] < miny) || - (opco[2] < minz) || - (opco[0] > maxx) || - (opco[1] > maxy) || - (opco[2] > maxz) ) { - /* outside the padded boundbox --> collision object is too far away */ - BLI_ghashIterator_step(ihash); - continue; - } - } - else{ - /*aye that should be cached*/ - printf("missing cache error \n"); - BLI_ghashIterator_step(ihash); - continue; - } - - /* do object level stuff */ - /* need to have user control for that since it depends on model scale */ - innerfacethickness =-ob->pd->pdef_sbift; - outerfacethickness =ob->pd->pdef_sboft; - closestinside = innerfacethickness; - fa = (ff*outerfacethickness-outerfacethickness); - fa *= fa; - fa = 1.0f/fa; - avel[0]=avel[1]=avel[2]=0.0f; - /* use mesh*/ - while (a--) { - if ( - (opco[0] < mima->minx) || - (opco[0] > mima->maxx) || - (opco[1] < mima->miny) || - (opco[1] > mima->maxy) || - (opco[2] < mima->minz) || - (opco[2] > mima->maxz) - ) { - mface++; - mima++; - continue; - } - - if (mvert){ - - VECCOPY(nv1,mvert[mface->v1].co); - VECCOPY(nv2,mvert[mface->v2].co); - VECCOPY(nv3,mvert[mface->v3].co); - if (mface->v4){ - VECCOPY(nv4,mvert[mface->v4].co); - } - - if (mprevvert){ - /* grab the average speed of the collider vertices - before we spoil nvX - humm could be done once a SB steps but then we' need to store that too - since the AABB reduced propabitlty to get here drasticallly - it might be a nice tradeof CPU <--> memory - */ - VECSUB(vv1,nv1,mprevvert[mface->v1].co); - VECSUB(vv2,nv2,mprevvert[mface->v2].co); - VECSUB(vv3,nv3,mprevvert[mface->v3].co); - if (mface->v4){ - VECSUB(vv4,nv4,mprevvert[mface->v4].co); - } - - VecMulf(nv1,time); - Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); - - VecMulf(nv2,time); - Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); - - VecMulf(nv3,time); - Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); - - if (mface->v4){ - VecMulf(nv4,time); - Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); - } - } - } - - /* switch origin to be nv2*/ - VECSUB(edge1, nv1, nv2); - VECSUB(edge2, nv3, nv2); - VECSUB(dv1,opco,nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */ - - Crossf(d_nvect, edge2, edge1); - n_mag = Normalize(d_nvect); - facedist = Inpf(dv1,d_nvect); - - if ((facedist > closestinside) && (facedist < outerfacethickness)){ -// if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ - if (point_in_tri_prism(opco, nv1, nv2, nv3) ){ - force_mag_norm =(float)exp(-ee*facedist); - if (facedist > outerfacethickness*ff) - force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); - *damp=ob->pd->pdef_sbdamp; - - if (facedist > 0.0f){ - *damp *= (1.0f - facedist/outerfacethickness); - Vec3PlusStVec(force,force_mag_norm,d_nvect); - if (deflected < 2){ - deflected = 1; - if ((mprevvert) && (*damp > 0.0f)){ - choose_winner(ve,opco,nv1,nv2,nv3,vv1,vv2,vv3); - VECADD(avel,avel,ve); - cavel ++; - } - } - - } - else{ - Vec3PlusStVec(force,force_mag_norm,d_nvect); - VECCOPY(facenormal,d_nvect); - if ((mprevvert) && (*damp > 0.0f)){ - choose_winner(avel,opco,nv1,nv2,nv3,vv1,vv2,vv3); - cavel = 1; - deflected = 2; - closestinside = facedist; - } - } - *intrusion = facedist; - } - } - if (mface->v4){ /* quad */ - /* switch origin to be nv4 */ - VECSUB(edge1, nv3, nv4); - VECSUB(edge2, nv1, nv4); - VECSUB(dv1,opco,nv4); /* abuse dv1 to have vertex in question at *origin* of triangle */ - - Crossf(d_nvect, edge2, edge1); - n_mag = Normalize(d_nvect); - facedist = Inpf(dv1,d_nvect); - - if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ - if (point_in_tri_prism(opco, nv1, nv3, nv4) ){ - force_mag_norm =(float)exp(-ee*facedist); - if (facedist > outerfacethickness*ff) - force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); - Vec3PlusStVec(force,force_mag_norm,d_nvect); - *damp=ob->pd->pdef_sbdamp; - - if (facedist > 0.0f){ - *damp *= (1.0f - facedist/outerfacethickness); - Vec3PlusStVec(force,force_mag_norm,d_nvect); - if (deflected < 2){ - deflected = 1; - if ((mprevvert) && (*damp > 0.0f)){ - choose_winner(ve,opco,nv1,nv3,nv4,vv1,vv3,vv4); - VECADD(avel,avel,ve); - cavel ++; - } - } - - } - else{ - Vec3PlusStVec(force,force_mag_norm,d_nvect); - VECCOPY(facenormal,d_nvect); - if ((mprevvert) && (*damp > 0.0f)){ - choose_winner(avel,opco,nv1,nv3,nv4,vv1,vv3,vv4); - cavel = 1; - deflected = 2; - closestinside = facedist; - } - } - - - - *intrusion = facedist; - } - - } - } - mface++; - mima++; - }/* while a */ - } /* if(ob->pd && ob->pd->deflect) */ - BLI_ghashIterator_step(ihash); - } /* while () */ - BLI_ghashIterator_free(ihash); - if (cavel) VecMulf(avel,1.0f/(float)cavel); - VECCOPY(vel,avel); - - /* we did stay "outside" but have some close to contact forces - just to be complete fake a face normal - */ - if (deflected ==1){ - VECCOPY(facenormal,force); - Normalize(facenormal); - } - else{ - facenormal[0] = facenormal[1] = facenormal[2] = 0.0f; - } - return deflected; -} -#endif - - /* sandbox to plug in various deflection algos */ static int sb_deflect_face(Object *ob,float *actpos,float *facenormal,float *force,float *cf,float time,float *vel,float *intrusion) @@ -2110,6 +1918,7 @@ static int sb_deflect_face(Object *ob,float *actpos,float *facenormal,float *for return(deflected); } +/* hiding this for now .. but the jacobian may pop up on other tasks .. so i'd like to keep it static void dfdx_spring(int ia, int ic, int op, float dir[3],float L,float len,float factor) { float m,delta_ij; @@ -2143,6 +1952,7 @@ static void dfdv_goal(int ia, int ic,float factor) int i; for(i=0;i<3;i++) nlMatrixAdd(ia+i,ic+i,factor); } +*/ static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float forcetime,int nl_flags) { SoftBody *sb= ob->soft; /* is supposed to be there */ @@ -2196,18 +2006,18 @@ static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float fo /* do jacobian stuff if needed */ if(nl_flags & NLF_BUILD){ - int op =3*sb->totpoint; - float mvel = -forcetime*kd; - float mpos = -forcetime*forcefactor; + //int op =3*sb->totpoint; + //float mvel = -forcetime*kd; + //float mpos = -forcetime*forcefactor; /* depending on my pos */ - dfdx_spring(ia,ia,op,dir,bs->len,distance,-mpos); + // dfdx_spring(ia,ia,op,dir,bs->len,distance,-mpos); /* depending on my vel */ - dfdv_goal(ia,ia,mvel); // well that ignores geometie + // dfdv_goal(ia,ia,mvel); // well that ignores geometie if(bp2->goal < SOFTGOALSNAP){ /* ommit this bp when it snaps */ /* depending on other pos */ - dfdx_spring(ia,ic,op,dir,bs->len,distance,mpos); + // dfdx_spring(ia,ic,op,dir,bs->len,distance,mpos); /* depending on other vel */ - dfdv_goal(ia,ia,-mvel); // well that ignores geometie + // dfdv_goal(ia,ia,-mvel); // well that ignores geometie } } } @@ -2229,14 +2039,14 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int int a, b, do_deflector,do_selfcollision,do_springcollision,do_aero; - +/* jacobian NLboolean success; if(nl_flags){ nlBegin(NL_SYSTEM); nlBegin(NL_MATRIX); } - +*/ gravity = sb->grav * sb_grav_force_scale(ob); @@ -2263,17 +2073,14 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int /* clear forces accumulator */ bp->force[0]= bp->force[1]= bp->force[2]= 0.0; if(nl_flags & NLF_BUILD){ - int ia =3*(sb->totpoint-a); - int op =3*sb->totpoint; + //int ia =3*(sb->totpoint-a); + //int op =3*sb->totpoint; /* dF/dV = v */ - + /* jacobioan nlMatrixAdd(op+ia,ia,-forcetime); nlMatrixAdd(op+ia+1,ia+1,-forcetime); nlMatrixAdd(op+ia+2,ia+2,-forcetime); - - - /* we need [unit - h* dF/dy]^-1 */ - + nlMatrixAdd(ia,ia,1); nlMatrixAdd(ia+1,ia+1,1); nlMatrixAdd(ia+2,ia+2,1); @@ -2281,7 +2088,7 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int nlMatrixAdd(op+ia,op+ia,1); nlMatrixAdd(op+ia+1,op+ia+1,1); nlMatrixAdd(op+ia+2,op+ia+2,1); - + */ } @@ -2328,17 +2135,17 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int Vec3PlusStVec(bp->force,sb->balldamp,dvel); if(nl_flags & NLF_BUILD){ - int ia =3*(sb->totpoint-a); - int ic =3*(sb->totpoint-c); - int op =3*sb->totpoint; - float mvel = forcetime*sb->nodemass*sb->balldamp; - float mpos = forcetime*tune*(1.0f-sb->balldamp); + //int ia =3*(sb->totpoint-a); + //int ic =3*(sb->totpoint-c); + //int op =3*sb->totpoint; + //float mvel = forcetime*sb->nodemass*sb->balldamp; + //float mpos = forcetime*tune*(1.0f-sb->balldamp); /*some quick and dirty entries to the jacobian*/ - dfdx_goal(ia,ia,op,mpos); - dfdv_goal(ia,ia,mvel); + //dfdx_goal(ia,ia,op,mpos); + //dfdv_goal(ia,ia,mvel); /* exploit force(a,b) == -force(b,a) part1/2 */ - dfdx_goal(ic,ic,op,mpos); - dfdv_goal(ic,ic,mvel); + //dfdx_goal(ic,ic,op,mpos); + //dfdv_goal(ic,ic,mvel); /*TODO sit down an X-out the true jacobian entries*/ @@ -2368,7 +2175,7 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int if(bp->goal < SOFTGOALSNAP){ /* ommit this bp when it snaps */ float auxvect[3]; float velgoal[3]; - float absvel =0, projvel= 0; + /* do goal stuff */ if(ob->softflag & OB_SB_GOAL) { /* true elastic goal */ @@ -2379,10 +2186,10 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int bp->force[2]+= -ks*(auxvect[2]); if(nl_flags & NLF_BUILD){ - int ia =3*(sb->totpoint-a); - int op =3*(sb->totpoint); + //int ia =3*(sb->totpoint-a); + //int op =3*(sb->totpoint); /* depending on my pos */ - dfdx_goal(ia,ia,op,ks*forcetime); + //dfdx_goal(ia,ia,op,ks*forcetime); } @@ -2396,10 +2203,10 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int bp->force[1]-= kd * (auxvect[1]); bp->force[2]-= kd * (auxvect[2]); if(nl_flags & NLF_BUILD){ - int ia =3*(sb->totpoint-a); + //int ia =3*(sb->totpoint-a); Normalize(auxvect); /* depending on my vel */ - dfdv_goal(ia,ia,kd*forcetime); + //dfdv_goal(ia,ia,kd*forcetime); } } @@ -2446,18 +2253,18 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int bp->force[2]-= bp->vec[2]*kd; /* friction in media done */ if(nl_flags & NLF_BUILD){ - int ia =3*(sb->totpoint-a); - int op =3*sb->totpoint; + //int ia =3*(sb->totpoint-a); /* da/dv = */ - nlMatrixAdd(ia,ia,forcetime*kd); - nlMatrixAdd(ia+1,ia+1,forcetime*kd); - nlMatrixAdd(ia+2,ia+2,forcetime*kd); +// nlMatrixAdd(ia,ia,forcetime*kd); +// nlMatrixAdd(ia+1,ia+1,forcetime*kd); +// nlMatrixAdd(ia+2,ia+2,forcetime*kd); } } /* +++cached collision targets */ bp->choke = 0.0f; + bp->choke2 = 0.0f; bp->flag &= ~SBF_DOFUZZY; if(do_deflector) { float cfforce[3],defforce[3] ={0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}, facenormal[3], cf = 1.0f,intrusion; @@ -2484,8 +2291,8 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int } Vec3PlusStVec(bp->force,kd,defforce); if (nl_flags & NLF_BUILD){ - int ia =3*(sb->totpoint-a); - int op =3*sb->totpoint; + // int ia =3*(sb->totpoint-a); + // int op =3*sb->totpoint; //dfdx_goal(ia,ia,op,mpos); // don't do unless you know //dfdv_goal(ia,ia,-cf); @@ -2521,6 +2328,7 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow); /* finish matrix and solve */ +#if (0) // remove onl linking for now .. still i am not sure .. the jacobian can be usefull .. so keep that BM if(nl_flags & NLF_SOLVE){ //double sct,sst=PIL_check_seconds_timer(); for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { @@ -2588,135 +2396,9 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int //if (sct-sst > 0.01f) printf(" implicit solver time %f %s \r",sct-sst,ob->id.name); } /* cleanup */ - +#endif if(do_effector) pdEndEffectors(do_effector); } - - -static void softbody_apply_fake_implicit_forces(Object *ob, float forcetime, float *err, float *err_ref_pos,float *err_ref_vel) -{ - /* time evolution */ - /* do semi implicit euler */ - SoftBody *sb= ob->soft; /* is supposed to be there */ - BodyPoint *bp; - float *perp,*perv; - float erp[3],erv[3],dx[3],dv[3],aabbmin[3],aabbmax[3],cm[3]={0.0f,0.0f,0.0f}; - float timeovermass; - float maxerrpos= 0.0f,maxerrvel = 0.0f,maxerrvel2 = 0.0f; - int a,fuzzy=0; - - forcetime *= sb_time_scale(ob); - - aabbmin[0]=aabbmin[1]=aabbmin[2] = 1e20f; - aabbmax[0]=aabbmax[1]=aabbmax[2] = -1e20f; - - /* claim a minimum mass for vertex */ - if (sb->nodemass > 0.009999f) timeovermass = forcetime/sb->nodemass; - else timeovermass = forcetime/0.009999f; - /* step along error reference vector */ - perp =err_ref_pos; - perv =err_ref_vel; - - for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { - /* step along error reference vector */ - if(perp) {VECCOPY(erp,perp);perp +=3;} - if(perv) {VECCOPY(erv,perv);perv +=3;} - if(bp->goal < SOFTGOALSNAP){ - - /* so here is (v)' = a(cceleration) = sum(F_springs)/m + gravitation + some friction forces + more forces*/ - /* the ( ... )' operator denotes derivate respective time */ - /* the "implicit" euler step for velocity then becomes */ - /* v(t + dt) = v(t) + O * X(t) * dt */ - /* O = [1-dt*dA/d(X)]^1 */ - /* with X = (a[n],v[n]) */ - /* da/dv | da/dx */ - /* dA/d(X) = ( ------------- )*/ - /* dv/dv | dv/dx */ - /* note!! we did not solve any implicit system but looking forward more or less smart - what a implicit solution may look like by means of taylor expansion */ - VECCOPY(dx,bp->vec); - - bp->force[0]= timeovermass * bp->impdv[0]; /* individual mass of node here */ - bp->force[1]= timeovermass * bp->impdv[1]; - bp->force[2]= timeovermass * bp->impdv[2]; - VECCOPY(dv,bp->force); - if(perv){ - maxerrvel = MAX2(maxerrvel,ABS(dv[0] - erv[0])); - maxerrvel = MAX2(maxerrvel,ABS(dv[1] - erv[1])); - maxerrvel = MAX2(maxerrvel,ABS(dv[2] - erv[2])); - } - - maxerrvel2 = MAX2(maxerrvel2,ABS(dv[0])); - maxerrvel2 = MAX2(maxerrvel2,ABS(dv[1])); - maxerrvel2 = MAX2(maxerrvel2,ABS(dv[2])); - - VECADD(bp->vec, bp->vec, dv); - - /* so here is (x)'= v(elocity) */ - /* the euler step for location then becomes */ - /* x(t + dt) = x(t) + v(t) * dt */ - -// VECCOPY(dx,bp->vec); - - dx[0]*=forcetime; - dx[1]*=forcetime; - dx[2]*=forcetime; - - /* bp->choke is set when we need to pull a vertex or edge out of the collider. - the collider object signals to get out by pushing hard. on the other hand - we don't want to end up in deep space so we add some <viscosity> - to balance that out */ - if (bp->choke > 0.0f){ - dx[0]*=(1.0f - bp->choke); - dx[1]*=(1.0f - bp->choke); - dx[2]*=(1.0f - bp->choke); - } - - - /* should be possible to get more out of the matrix inversion - but not verified yet - dx[0]*=forcetime*forcetime*bp->impdx[0]; - dx[1]*=forcetime*forcetime*bp->impdx[1]; - dx[2]*=forcetime*forcetime*bp->impdx[2]; - */ - VECADD(bp->pos, bp->pos, dx); - if (perp){ - maxerrpos = MAX2(maxerrpos,ABS(bp->pos[0]-erp[0])); - maxerrpos = MAX2(maxerrpos,ABS(bp->pos[1]-erp[1])); - maxerrpos = MAX2(maxerrpos,ABS(bp->pos[2]-erp[2])); - } - - - }/*snap*/ - /* so while we are looping BPs anyway do statistics on the fly */ - aabbmin[0] = MIN2(aabbmin[0],bp->pos[0]); - aabbmin[1] = MIN2(aabbmin[1],bp->pos[1]); - aabbmin[2] = MIN2(aabbmin[2],bp->pos[2]); - aabbmax[0] = MAX2(aabbmax[0],bp->pos[0]); - aabbmax[1] = MAX2(aabbmax[1],bp->pos[1]); - aabbmax[2] = MAX2(aabbmax[2],bp->pos[2]); - if (bp->flag & SBF_DOFUZZY) fuzzy =1; - } /*for*/ - - if (sb->totpoint) VecMulf(cm,1.0f/sb->totpoint); - if (sb->scratch){ - VECCOPY(sb->scratch->aabbmin,aabbmin); - VECCOPY(sb->scratch->aabbmax,aabbmax); - } - - if (err){ /* so step size will be controlled by biggest difference in slope */ - if (sb->solverflags & SBSO_OLDERR) - *err = MAX2(maxerrpos,maxerrvel); - else - if (perp) *err = maxerrpos; - else *err = maxerrvel2; - //printf("EP %f EV %f \n",maxerrpos,maxerrvel); - if (fuzzy){ - *err /= sb->fuzzyness; - } - } -} - static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err, int mid_flags) { /* time evolution */ @@ -2725,7 +2407,7 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * SoftBody *sb= ob->soft; /* is supposed to be there */ BodyPoint *bp; float dx[3],dv[3],aabbmin[3],aabbmax[3],cm[3]={0.0f,0.0f,0.0f}; - float timeovermass; + float timeovermass/*,freezeloc=0.00001f,freezeforce=0.00000000001f*/; float maxerrpos= 0.0f,maxerrvel = 0.0f; int a,fuzzy=0; @@ -2740,15 +2422,14 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { if(bp->goal < SOFTGOALSNAP){ - if(mid_flags & MID_PRESERVE) VECCOPY(dx,bp->vec); + /* this makes t~ = t */ + if(mid_flags & MID_PRESERVE) VECCOPY(dx,bp->vec); /* so here is (v)' = a(cceleration) = sum(F_springs)/m + gravitation + some friction forces + more forces*/ /* the ( ... )' operator denotes derivate respective time */ /* the euler step for velocity then becomes */ /* v(t + dt) = v(t) + a(t) * dt */ - bp->force[0]*= timeovermass; /* individual mass of node here */ - bp->force[1]*= timeovermass; - bp->force[2]*= timeovermass; + VecMulf(bp->force,timeovermass);/* individual mass of node here */ /* some nasty if's to have heun in here too */ VECCOPY(dv,bp->force); @@ -2769,13 +2450,24 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * } else {VECADD(bp->vec, bp->vec, bp->force);} + /* this makes t~ = t+dt */ + if(!(mid_flags & MID_PRESERVE)) VECCOPY(dx,bp->vec); + /* so here is (x)'= v(elocity) */ /* the euler step for location then becomes */ - /* x(t + dt) = x(t) + v(t) * dt */ - if(!(mid_flags & MID_PRESERVE)) VECCOPY(dx,bp->vec); - dx[0]*=forcetime; - dx[1]*=forcetime; - dx[2]*=forcetime; + /* x(t + dt) = x(t) + v(t~) * dt */ + VecMulf(dx,forcetime); + + /* the freezer */ + /* + if ((Inpf(dx,dx)<freezeloc )&&(Inpf(bp->force,bp->force)<freezeforce )){ + bp->frozen /=2; + } + else{ + bp->frozen =MIN2(bp->frozen*1.05f,1.0f); + } + VecMulf(dx,bp->frozen); + */ /* again some nasty if's to have heun in here too */ if (mode ==1){ VECCOPY(bp->prevpos,bp->pos); @@ -2785,7 +2477,7 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * if (mode ==2){ bp->pos[0] = bp->prevpos[0] + 0.5f * ( dx[0] + bp->prevdx[0]); bp->pos[1] = bp->prevpos[1] + 0.5f * ( dx[1] + bp->prevdx[1]); - bp->pos[2] = bp->prevpos[2] + 0.5f* ( dx[2] + bp->prevdx[2]); + bp->pos[2] = bp->prevpos[2] + 0.5f * ( dx[2] + bp->prevdx[2]); maxerrpos = MAX2(maxerrpos,ABS(dx[0] - bp->prevdx[0])); maxerrpos = MAX2(maxerrpos,ABS(dx[1] - bp->prevdx[1])); maxerrpos = MAX2(maxerrpos,ABS(dx[2] - bp->prevdx[2])); @@ -2794,10 +2486,11 @@ static void softbody_apply_forces(Object *ob, float forcetime, int mode, float * the collider object signals to get out by pushing hard. on the other hand we don't want to end up in deep space so we add some <viscosity> to balance that out */ + if (bp->choke2 > 0.0f){ + VecMulf(bp->vec,(1.0f - bp->choke2)); + } if (bp->choke > 0.0f){ - bp->vec[0] = bp->vec[0]*(1.0f - bp->choke); - bp->vec[1] = bp->vec[1]*(1.0f - bp->choke); - bp->vec[2] = bp->vec[2]*(1.0f - bp->choke); + VecMulf(bp->vec,(1.0f - bp->choke)); } } @@ -2844,6 +2537,7 @@ static void softbody_restore_prev_step(Object *ob) } } +#if 0 static void softbody_store_step(Object *ob) { SoftBody *sb= ob->soft; /* is supposed to be there*/ @@ -2915,6 +2609,7 @@ static void softbody_swap_state(Object *ob,float *ppos,float *pvel) pp+=3; } } +#endif /* care for bodypoints taken out of the 'ordinary' solver step @@ -2937,6 +2632,30 @@ static void softbody_apply_goalsnap(Object *ob) } } + +void apply_spring_memory(Object *ob) +{ + SoftBody *sb = ob->soft; + BodySpring *bs; + BodyPoint *bp1, *bp2; + int a; + float b,l,r; + + b = sb->plastic; + if (sb && sb->totspring){ + for(a=0; a<sb->totspring; a++) { + bs = &sb->bspring[a]; + bp1 =&sb->bpoint[bs->v1]; + bp2 =&sb->bpoint[bs->v2]; + l = VecLenf(bp1->pos,bp2->pos); + r = bs->len/l; + if (( r > 1.05f) || (r < 0.95)){ + bs->len = ((100.0f - b) * bs->len + b*l)/100.0f; + } + } + } +} + /* expects full initialized softbody */ static void interpolate_exciter(Object *ob, int timescale, int time) { @@ -3025,9 +2744,9 @@ static void springs_from_mesh(Object *ob) } /* recalculate spring length for meshes here */ - /* special hidden feature! shrink to fit */ - if (G.rt > 500){ - scale = (G.rt - 500) / 100.0f; + /* public version shrink to fit */ + if (sb->springpreload != 0 ){ + scale = sb->springpreload / 100.0f; } for(a=0; a<sb->totspring; a++) { BodySpring *bs = &sb->bspring[a]; @@ -3430,9 +3149,12 @@ static void particles_to_softbody(Object *ob) /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ renew_softbody(ob, totpoint, totedge); - psys->particles->bpi = 0; - for(a=1, pa=psys->particles+1; a<psys->totpart; a++, pa++) - pa->bpi = (pa-1)->bpi + pa->totkey; + /* find first BodyPoint index for each particle */ + if(psys->totpart > 0) { + psys->particles->bpi = 0; + for(a=1, pa=psys->particles+1; a<psys->totpart; a++, pa++) + pa->bpi = (pa-1)->bpi + (pa-1)->totkey; + } /* we always make body points */ sb= ob->soft; @@ -3494,95 +3216,66 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, } } -void softbody_clear_cache(Object *ob, float framenr) -{ - SoftBody *sb = ob->soft; - ModifierData *md = ob->modifiers.first; - int stack_index = -1; - int a; - - if(sb==NULL) return; - - if(sb->particles) - stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); - else { - for(a=0; md; md=md->next, a++) { - if(md->type == eModifierType_Softbody) { - stack_index = a; - break; - } - } - } - - BKE_ptcache_id_clear((ID *)ob, PTCACHE_CLEAR_ALL, framenr, stack_index); -} -static void softbody_write_cache(Object *ob, float framenr) +void sbWriteCache(Object *ob, int framenr) { - FILE *fp = NULL; - SoftBody *sb = ob->soft; + SoftBody *sb= ob->soft; BodyPoint *bp; - ModifierData *md = ob->modifiers.first; - int stack_index = -1; + PTCacheID pid; + PTCacheFile *pf; int a; - if(sb->totpoint == 0) return; - - if(sb->particles) - stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); - else { - for(a=0; md; md=md->next, a++) { - if(md->type == eModifierType_Softbody) { - stack_index = a; - break; - } - } - } + if(sb->totpoint == 0) + return; - fp = BKE_ptcache_id_fopen((ID *)ob, 'w', framenr, stack_index); - if(!fp) return; + BKE_ptcache_id_from_softbody(&pid, ob, sb); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr); + if(!pf) + return; + + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) + BKE_ptcache_file_write_floats(pf, bp->pos, 3); for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) - fwrite(&bp->pos, sizeof(float), 3, fp); - - fclose(fp); + BKE_ptcache_file_write_floats(pf, bp->vec, 3); + + BKE_ptcache_file_close(pf); } + static int softbody_read_cache(Object *ob, float framenr) { - FILE *fp = NULL; - SoftBody *sb = ob->soft; + SoftBody *sb= ob->soft; BodyPoint *bp; - ModifierData *md = ob->modifiers.first; - int stack_index = -1; - int a, ret = 1; + PTCacheID pid; + PTCacheFile *pf; + int a; - if(sb->totpoint == 0) return 0; + if(sb->totpoint == 0) + return 0; + + BKE_ptcache_id_from_softbody(&pid, ob, sb); + pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr); + if(!pf) + return 0; - if(sb->particles) - stack_index = modifiers_indexInObject(ob,(ModifierData*)psys_get_modifier(ob,sb->particles)); - else { - for(a=0; md; md=md->next, a++) { - if(md->type == eModifierType_Softbody) { - stack_index = a; - break; - } + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) { + if(!BKE_ptcache_file_read_floats(pf, bp->pos, 3)) { + BKE_ptcache_file_close(pf); + return 0; } } - fp = BKE_ptcache_id_fopen((ID *)ob, 'r', framenr, stack_index); - if(!fp) - ret = 0; - else { - for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) - if(fread(&bp->pos, sizeof(float), 3, fp) != 3) { - ret = 0; - break; - } - - fclose(fp); + for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) { + if(!BKE_ptcache_file_read_floats(pf, bp->vec, 3)) { + BKE_ptcache_file_close(pf); + return 0; + } } - return ret; + BKE_ptcache_file_close(pf); + + return 1; } + /* +++ ************ maintaining scratch *************** */ void sb_new_scratch(SoftBody *sb) { @@ -3641,6 +3334,9 @@ SoftBody *sbNew(void) /*todo backward file compat should set sb->shearstiff = 1.0f while reading old files*/ sb->shearstiff = 1.0f; sb->solverflags |= SBSO_OLDERR; + + sb->pointcache = BKE_ptcache_add(); + return sb; } @@ -3648,14 +3344,19 @@ SoftBody *sbNew(void) void sbFree(SoftBody *sb) { free_softbody_intern(sb); + BKE_ptcache_free(sb->pointcache); MEM_freeN(sb); } +void sbFreeSimulation(SoftBody *sb) +{ + free_softbody_intern(sb); +} /* makes totally fresh start situation */ void sbObjectToSoftbody(Object *ob) { - ob->softflag |= OB_SB_REDO; + //ob->softflag |= OB_SB_REDO; free_softbody_intern(ob->soft); } @@ -3679,562 +3380,406 @@ void sbSetInterruptCallBack(int (*f)(void)) SB_localInterruptCallBack = f; } - -/* simulates one step. framenr is in frames */ -void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts) +static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) { - ParticleSystemModifierData *psmd=0; - ParticleData *pa=0; - SoftBody *sb; + ParticleSystemModifierData *psmd= NULL; + ParticleData *pa= NULL; HairKey *key= NULL; BodyPoint *bp; - int a; - float dtime,ctime,forcetime; float hairmat[4][4]; + int a; - /* This part only sets goals and springs, based on original mesh/curve/lattice data. - Copying coordinates happens in next chunk by setting softbody flag OB_SB_RESET */ - /* remake softbody if: */ - if( (ob->softflag & OB_SB_REDO) || /* signal after weightpainting */ - (ob->soft==NULL) || /* just to be nice we allow full init */ - (ob->soft->bpoint==NULL) || /* after reading new file, or acceptable as signal to refresh */ - (numVerts!=ob->soft->totpoint) || /* should never happen, just to be safe */ - ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) /* happens when in UI edges was set */ - { - if(ob->soft && ob->soft->bpoint) /* don't clear on file load */ - softbody_clear_cache(ob, framenr); - - if(ob->soft->particles){ - particles_to_softbody(ob); - } - else switch(ob->type) { - case OB_MESH: - mesh_to_softbody(ob); - break; - case OB_LATTICE: - lattice_to_softbody(ob); - break; - case OB_CURVE: - case OB_SURF: - curve_surf_to_softbody(ob); - break; - default: - renew_softbody(ob, numVerts, 0); - break; - } + /* update the vertex locations */ + if(sb->particles) { + psmd= psys_get_modifier(ob,sb->particles); + pa= sb->particles->particles; + key= pa->hair; - /* still need to update to correct vertex locations, happens on next step */ - ob->softflag |= OB_SB_RESET; - ob->softflag &= ~OB_SB_REDO; + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); } - sb= ob->soft; + for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { + /* store where goals are now */ + VECCOPY(bp->origS, bp->origE); + /* copy the position of the goals at desired end time */ + if(sb->particles) { + if(key == pa->hair + pa->totkey) { + pa++; + key = pa->hair; - /* still no points? go away */ - if(sb->totpoint==0) return; + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + VECCOPY(bp->origE, key->co); + Mat4MulVecfl(hairmat,bp->origE); - if(sb->particles){ - psmd=psys_get_modifier(ob,sb->particles); - pa=sb->particles->particles; + key++; + } + else{ + VECCOPY(bp->origE, vertexCos[a]); + /* vertexCos came from local world, go global */ + Mat4MulVecfl(ob->obmat, bp->origE); + } + /* just to be save give bp->origT a defined value + will be calulated in interpolate_exciter()*/ + VECCOPY(bp->origT, bp->origE); } +} - /* checking time: */ +static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) +{ + ParticleSystemModifierData *psmd= NULL; + HairKey *key= NULL; + ParticleData *pa= NULL; + BodyPoint *bp; + float hairmat[4][4]; + int a; - ctime= bsystem_time(ob, framenr, 0.0); + if(sb->particles) { + psmd= psys_get_modifier(ob, sb->particles); + pa= sb->particles->particles; + key= pa->hair; - if (ob->softflag&OB_SB_RESET) { - dtime = 0.0; - } else { - dtime= ctime - sb->ctime; + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); } - if(softbody_read_cache(ob, framenr)) { - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, sb->local); - sb->ctime = ctime; - return; - } - - /* the simulator */ - - /* update the vertex locations */ - if (dtime!=0.0) { + for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { if(sb->particles) { - pa=sb->particles->particles; - key = pa->hair; + if(key == pa->hair + pa->totkey) { + pa++; + key = pa->hair; - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + } + VECCOPY(bp->pos, key->co); + Mat4MulVecfl(hairmat, bp->pos); + key++; + } + else { + VECCOPY(bp->pos, vertexCos[a]); + Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ } + VECCOPY(bp->origS, bp->pos); + VECCOPY(bp->origE, bp->pos); + VECCOPY(bp->origT, bp->pos); + bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; + + /* the bp->prev*'s are for rolling back from a canceled try to propagate in time + adaptive step size algo in a nutshell: + 1. set sheduled time step to new dtime + 2. try to advance the sheduled time step, beeing optimistic execute it + 3. check for success + 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so! + 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2. + 4. check if we did reach dtime + 4.a nope we need to do some more at 2. + 4.b yup we're done + */ - for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { - /* store where goals are now */ - VECCOPY(bp->origS, bp->origE); - /* copy the position of the goals at desired end time */ - if(sb->particles) { - if(key == pa->hair + pa->totkey) { - pa++; - key = pa->hair; + VECCOPY(bp->prevpos, bp->pos); + VECCOPY(bp->prevvec, bp->vec); + VECCOPY(bp->prevdx, bp->vec); + VECCOPY(bp->prevdv, bp->vec); + } - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); - } - VECCOPY(bp->origE, key->co); - Mat4MulVecfl(hairmat,bp->origE); + /* make a nice clean scratch struc */ + free_scratch(sb); /* clear if any */ + sb_new_scratch(sb); /* make a new */ + sb->scratch->needstobuildcollider=1; - key++; - } - else{ - VECCOPY(bp->origE, vertexCos[a]); - /* vertexCos came from local world, go global */ - Mat4MulVecfl(ob->obmat, bp->origE); - } - /* just to be save give bp->origT a defined value - will be calulated in interpolate_exciter()*/ - VECCOPY(bp->origT, bp->origE); + if((sb->particles)==0) { + /* copy some info to scratch */ + switch(ob->type) { + case OB_MESH: + if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); + break; + case OB_LATTICE: + break; + case OB_CURVE: + case OB_SURF: + break; + default: + break; } } +} - if((ob->softflag&OB_SB_RESET) || /* got a reset signal */ - (dtime<0.0) || /* back in time */ - (dtime>=9.9*G.scene->r.framelen) /* too far forward in time --> goals won't be accurate enough */ - ) - { - if(sb->particles) { - pa=sb->particles->particles; - key = pa->hair; +static void softbody_step(Object *ob, SoftBody *sb, float dtime) +{ + /* the simulator */ + float forcetime; + double sct,sst=PIL_check_seconds_timer(); + ccd_update_deflector_hache(ob,sb->scratch->colliderhash); - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + if(sb->scratch->needstobuildcollider){ + if (query_external_colliders(ob)){ + ccd_build_deflector_hache(ob,sb->scratch->colliderhash); } + sb->scratch->needstobuildcollider=0; + } + + if (sb->solver_ID < 2) { + /* special case of 2nd order Runge-Kutta type AKA Heun */ + int mid_flags=0; + float err = 0; + float forcetimemax = 1.0f; + float forcetimemin = 0.001f; + float timedone =0.0; /* how far did we get without violating error condition */ + /* loops = counter for emergency brake + * we don't want to lock up the system if physics fail + */ + int loops =0 ; + SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ + if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; + + if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops; + + if(sb->solver_ID>0) mid_flags |= MID_PRESERVE; + + //forcetime = dtime; /* hope for integrating in one step */ + forcetime =forcetimemax; /* hope for integrating in one step */ + while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) + { + /* set goals in time */ + interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); + + sb->scratch->flag &= ~SBF_DOFUZZY; + /* do predictive euler step */ + softbody_calc_forces(ob, forcetime,timedone/dtime,0); + softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); + - for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { - if(sb->particles) { - if(key == pa->hair + pa->totkey) { - pa++; - key = pa->hair; + /* crop new slope values to do averaged slope step */ + softbody_calc_forces(ob, forcetime,timedone/dtime,0); + softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); - psys_mat_hair_to_global(ob, psmd->dm, sb->particles->part->from, pa, hairmat); + softbody_apply_goalsnap(ob); + + if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */ + + if (forcetime > forcetimemin){ + forcetime = MAX2(forcetime / 2.0f,forcetimemin); + softbody_restore_prev_step(ob); + //printf("down,"); + } + else { + timedone += forcetime; } - VECCOPY(bp->pos, key->co); - Mat4MulVecfl(hairmat, bp->pos); - key++; } else { - VECCOPY(bp->pos, vertexCos[a]); - Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ + float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */ + + if (sb->scratch->flag & SBF_DOFUZZY){ + //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ + newtime = forcetime; + //} + } + else { + if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */ + newtime = forcetime; + } + } + timedone += forcetime; + newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); + //if (newtime > forcetime) printf("up,"); + if (forcetime > 0.0) + forcetime = MIN2(dtime - timedone,newtime); + else + forcetime = MAX2(dtime - timedone,newtime); } - VECCOPY(bp->origS, bp->pos); - VECCOPY(bp->origE, bp->pos); - VECCOPY(bp->origT, bp->pos); - bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; - - /* the bp->prev*'s are for rolling back from a canceled try to propagate in time - adaptive step size algo in a nutshell: - 1. set sheduled time step to new dtime - 2. try to advance the sheduled time step, beeing optimistic execute it - 3. check for success - 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so! - 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2. - 4. check if we did reach dtime - 4.a nope we need to do some more at 2. - 4.b yup we're done - */ + loops++; + if(sb->solverflags & SBSO_MONITOR ){ + sct=PIL_check_seconds_timer(); + if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone); + } + /* ask for user break */ + if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; - VECCOPY(bp->prevpos, bp->pos); - VECCOPY(bp->prevvec, bp->vec); - VECCOPY(bp->prevdx, bp->vec); - VECCOPY(bp->prevdv, bp->vec); } - /* make a nice clean scratch struc */ - free_scratch(sb); /* clear if any */ - sb_new_scratch(sb); /* make a new */ - sb->scratch->needstobuildcollider=1; - - if((sb->particles)==0) { - /* copy some info to scratch */ - switch(ob->type) { - case OB_MESH: - if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); - break; - case OB_LATTICE: - break; - case OB_CURVE: - case OB_SURF: - break; - default: - break; - } + /* move snapped to final position */ + interpolate_exciter(ob, 2, 2); + softbody_apply_goalsnap(ob); + + // if(G.f & G_DEBUG){ + if(sb->solverflags & SBSO_MONITOR ){ + if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ + printf("\r needed %d steps/frame ",loops); } - - ob->softflag &= ~OB_SB_RESET; + } - else if(dtime>0.0) { - double sct,sst=PIL_check_seconds_timer(); - ccd_update_deflector_hache(ob,sb->scratch->colliderhash); + else if (sb->solver_ID == 2) + {/* do semi "fake" implicit euler */ + //removed + }/*SOLVER SELECT*/ + else if (sb->solver_ID == 4) + { + /* do semi "fake" implicit euler */ + }/*SOLVER SELECT*/ + else if (sb->solver_ID == 3){ + /* do "stupid" semi "fake" implicit euler */ + //removed + }/*SOLVER SELECT*/ + else{ + printf("softbody no valid solver ID!"); + }/*SOLVER SELECT*/ + if(sb->plastic){ apply_spring_memory(ob);} - if(sb->scratch->needstobuildcollider){ - if (query_external_colliders(ob)){ - ccd_build_deflector_hache(ob,sb->scratch->colliderhash); - } - sb->scratch->needstobuildcollider=0; - } + if(sb->solverflags & SBSO_MONITOR ){ + sct=PIL_check_seconds_timer(); + if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name); + } +} +/* simulates one step. framenr is in frames */ +void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) +{ + ParticleSystemModifierData *psmd=0; + ParticleData *pa=0; + SoftBody *sb= ob->soft; + PointCache *cache; + PTCacheID pid; + float dtime, timescale; + int framedelta, framenr, startframe, endframe; - if (sb->solver_ID < 2) { - /* special case of 2nd order Runge-Kutta type AKA Heun */ - int mid_flags=0; - float err = 0; - float forcetimemax = 1.0f; - float forcetimemin = 0.001f; - float timedone =0.0; /* how far did we get without violating error condition */ - /* loops = counter for emergency brake - * we don't want to lock up the system if physics fail - */ - int loops =0 ; - SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ - if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; - - if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops; + cache= sb->pointcache; - if(sb->solver_ID>0) mid_flags |= MID_PRESERVE; - - //forcetime = dtime; /* hope for integrating in one step */ - forcetime =forcetimemax; /* hope for integrating in one step */ - while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) - { - /* set goals in time */ - interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); - - sb->scratch->flag &= ~SBF_DOFUZZY; - /* do predictive euler step */ - softbody_calc_forces(ob, forcetime,timedone/dtime,0); - softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); + framenr= (int)cfra; + framedelta= framenr - cache->simframe; + BKE_ptcache_id_from_softbody(&pid, ob, sb); + BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, ×cale); - /* crop new slope values to do averaged slope step */ - softbody_calc_forces(ob, forcetime,timedone/dtime,0); - softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); + /* check for changes in mesh, should only happen in case the mesh + * structure changes during an animation */ + if(sb->bpoint && numVerts != sb->totpoint) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; - softbody_apply_goalsnap(ob); - - if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */ - - if (forcetime > forcetimemin){ - forcetime = MAX2(forcetime / 2.0f,forcetimemin); - softbody_restore_prev_step(ob); - //printf("down,"); - } - else { - timedone += forcetime; - } - } - else { - float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */ - - if (sb->scratch->flag & SBF_DOFUZZY){ - //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - //} - } - else { - if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - } - } - timedone += forcetime; - newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); - //if (newtime > forcetime) printf("up,"); - if (forcetime > 0.0) - forcetime = MIN2(dtime - timedone,newtime); - else - forcetime = MAX2(dtime - timedone,newtime); - } - loops++; - if(sb->solverflags & SBSO_MONITOR ){ - sct=PIL_check_seconds_timer(); - if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone); - } - /* ask for user break */ - if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; + return; + } - } - /* move snapped to final position */ - interpolate_exciter(ob, 2, 2); - softbody_apply_goalsnap(ob); - - // if(G.f & G_DEBUG){ - if(sb->solverflags & SBSO_MONITOR ){ - if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ - printf("\r needed %d steps/frame ",loops); - } - - } - else if (sb->solver_ID == 2) - { - /* do semi "fake" implicit euler */ - float *predict_vel=NULL,*predict_pos=NULL; /* for BDF style stepping */ - NLContext *sb_nlc = NULL; - int npredict=0,predict_mem_size; - int nvar = 3*2*sb->totpoint; - int loops =0 ; - float forcetimemax = 1.0f; // this one needs 5 steps as a minimum - float forcetimemin = 0.001f; - float timedone =0.0; /* how far did we get without violating error condition */ - /* loops = counter for emergency brake - * we don't want to lock up the system if physics fail - */ - SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ - if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; - if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops; - + /* clamp frame ranges */ + if(framenr < startframe) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; - forcetime =forcetimemax; /* hope for integrating as fast as possible */ - - //allocate predictor buffers - npredict =1; - predict_mem_size =3*sizeof(float)*npredict*sb->totpoint; - predict_pos = MEM_mallocN(predict_mem_size,"SB_predict_pos"); - predict_vel = MEM_mallocN(predict_mem_size,"SB_predict_vel"); - - - while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ){ - float loss_of_accuracy=0; - // create new solver context for this loop - sb_nlc = (NLContext*)nlNewContext(); - /* hum it smells like threading trouble */ - nlSolverParameteri(NL_NB_VARIABLES, nvar); - nlSolverParameteri(NL_LEAST_SQUARES, NL_FALSE); - - interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); - softbody_store_step(ob); /* used for rolling back step guessing */ - softbody_store_state(ob,predict_pos,predict_vel); - softbody_calc_forces(ob, forcetime,timedone/dtime,NLF_BUILD|NLF_SOLVE); - // go full step - softbody_apply_fake_implicit_forces(ob, forcetime, NULL,NULL,NULL); - - // restore old situation and store 1rst solution to predictors - softbody_swap_state(ob,predict_pos,predict_vel); - // the following is to find out how good we were - // may be we can do smarter - // so now using the forces and jacobian we calculated before - // go only 1/2 - softbody_apply_fake_implicit_forces(ob, forcetime/2.0f, NULL,NULL,NULL); - // explore situation here without redoing the jacobian - softbody_calc_forces(ob, forcetime,timedone/dtime,NLF_SOLVE); - // go next 1/2 - softbody_apply_fake_implicit_forces(ob, forcetime/2.0f,&loss_of_accuracy,predict_pos,predict_vel ); - // now we have "loss_of_accuracy" - - softbody_apply_goalsnap(ob); - - if (loss_of_accuracy > SoftHeunTol) { /* error needs to be scaled to some quantity */ - - if (forcetime > forcetimemin){ - forcetime = MAX2(forcetime / 2.0f,forcetimemin); - softbody_restore_prev_step(ob); - //printf("down,"); - } - else { - timedone += forcetime; - } - } - else { - float newtime = forcetime * 1.5f; /* hope for 1.1 times better conditions in next step */ - // all that 1/2 stepping was useless ... hum we know now .. - softbody_swap_state(ob,predict_pos,predict_vel); - if (0){//(sb->scratch->flag & SBF_DOFUZZY){ - //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - //} - } - else { - if (loss_of_accuracy > SoftHeunTol/1.1f) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - } - } + return; + } + else if(framenr > endframe) { + framenr = endframe; + } - timedone += forcetime; - newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); - //if (newtime > forcetime) printf("up,"); - if (forcetime > 0.0) - forcetime = MIN2(dtime - timedone,newtime); - else - forcetime = MAX2(dtime - timedone,newtime); - } - loops++; - // give away solver context within loop - if (sb_nlc) - { - if (sb_nlc != nlGetCurrent())printf("Aye NL context mismatch! in softbody.c !\n"); - nlDeleteContext(sb_nlc); - sb_nlc = NULL; - } + /* verify if we need to create the softbody data */ + if(sb->bpoint == NULL || + ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) { - if(sb->solverflags & SBSO_MONITOR ){ - sct=PIL_check_seconds_timer(); - if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone); - } + if(sb->particles){ + particles_to_softbody(ob); + } + else { + switch(ob->type) { + case OB_MESH: + mesh_to_softbody(ob); + break; + case OB_LATTICE: + lattice_to_softbody(ob); + break; + case OB_CURVE: + case OB_SURF: + curve_surf_to_softbody(ob); + break; + default: + renew_softbody(ob, numVerts, 0); + break; + } + } - /* ask for user break */ - if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; - } + softbody_update_positions(ob, sb, vertexCos, numVerts); + softbody_reset(ob, sb, vertexCos, numVerts); + } - // give away buffers - if (predict_pos) MEM_freeN(predict_pos); - if (predict_vel) MEM_freeN(predict_vel); + /* continue physics special case */ + if(BKE_ptcache_get_continue_physics()) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; - if(sb->solverflags & SBSO_MONITOR ){ - if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ - printf("\r needed %d steps/frame ",loops); - } + /* do simulation */ + dtime = timescale; + softbody_update_positions(ob, sb, vertexCos, numVerts); + softbody_step(ob, sb, dtime); - }/*SOLVER SELECT*/ - else if (sb->solver_ID == 4) - { - /* do semi "fake" implicit euler */ - NLContext *sb_nlc = NULL; - int nvar = 3*2*sb->totpoint; - int loops =0 ; - float forcetimemax = 1.0f; // this one needs 5 steps as a minimum - float forcetimemin = 0.001f; - float timedone =0.0; /* how far did we get without violating error condition */ - /* loops = counter for emergency brake - * we don't want to lock up the system if physics fail - */ - SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ - if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; - if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops; - + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, 0); - forcetime =forcetimemax; /* hope for integrating as fast as possible */ - while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ){ - float loss_of_accuracy=0; - // create new solver context for this loop - sb_nlc = (NLContext*)nlNewContext(); - /* hum it smells like threading trouble */ - nlSolverParameteri(NL_NB_VARIABLES, nvar); - nlSolverParameteri(NL_LEAST_SQUARES, NL_FALSE); - - - interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); - softbody_store_step(ob); /* used for rolling back step guessing */ - softbody_calc_forces(ob, forcetime,timedone/dtime,NLF_BUILD|NLF_SOLVE); - softbody_apply_fake_implicit_forces(ob, forcetime,&loss_of_accuracy,NULL,NULL); - softbody_apply_goalsnap(ob); - - if (loss_of_accuracy > SoftHeunTol) { /* error needs to be scaled to some quantity */ - - if (forcetime > forcetimemin){ - forcetime = MAX2(forcetime / 2.0f,forcetimemin); - softbody_restore_prev_step(ob); - //printf("down,"); - } - else { - timedone += forcetime; - } - } - else { - float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */ - if (0){//(sb->scratch->flag & SBF_DOFUZZY){ - //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - //} - } - else { - if (loss_of_accuracy > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */ - newtime = forcetime; - } - } + return; + } - timedone += forcetime; - newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); - //if (newtime > forcetime) printf("up,"); - if (forcetime > 0.0) - forcetime = MIN2(dtime - timedone,newtime); - else - forcetime = MAX2(dtime - timedone,newtime); - } - loops++; - // give away solver context within loop - if (sb_nlc) - { - if (sb_nlc != nlGetCurrent())printf("Aye NL context mismatch! in softbody.c !\n"); - nlDeleteContext(sb_nlc); - sb_nlc = NULL; - } + /* still no points? go away */ + if(sb->totpoint==0) return; - if(sb->solverflags & SBSO_MONITOR ){ - sct=PIL_check_seconds_timer(); - if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone); - } + if(sb->particles){ + psmd= psys_get_modifier(ob, sb->particles); + pa= sb->particles->particles; + } - /* ask for user break */ - if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; - } + /* try to read from cache */ + if(softbody_read_cache(ob, framenr)) { + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, sb->local); + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; - if(sb->solverflags & SBSO_MONITOR ){ - if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ - printf("\r needed %d steps/frame ",loops); - } + return; + } + else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { + /* if baked and nothing in cache, do nothing */ + if(cache->flag & PTCACHE_SIMULATION_VALID) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } + return; + } - }/*SOLVER SELECT*/ - else if (sb->solver_ID == 3){ - /* do "stupid" semi "fake" implicit euler */ - NLContext *sb_nlc = NULL; - int nvar = 3*2*sb->totpoint; - int loops =0 ; - float forcetimemax = 1.0f; // this one needs 5 steps as a minimum - float timedone =0.0; /* how far did we get without violating error condition */ - /* loops = counter for emergency brake - * we don't want to lock up the system if physics fail - */ - if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops; - + if(framenr == startframe) { + /* first frame, no simulation to do, just set the positions */ + softbody_update_positions(ob, sb, vertexCos, numVerts); - forcetime =forcetimemax; /* hope for integrating as fast as possible */ + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; - while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ){ + /* don't write cache on first frame, but on second frame write + * cache for frame 1 and 2 */ + } + else if(framedelta == 1) { + /* if on second frame, write cache for first frame */ + if(framenr == startframe+1) + sbWriteCache(ob, startframe); - sb_nlc = (NLContext*)nlNewContext(); - /* hum it smells like threading trouble */ - nlSolverParameteri(NL_NB_VARIABLES, nvar); - nlSolverParameteri(NL_LEAST_SQUARES, NL_FALSE); + softbody_update_positions(ob, sb, vertexCos, numVerts); - interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime))); - softbody_calc_forces(ob, forcetime,timedone/dtime,NLF_BUILD|NLF_SOLVE); - softbody_apply_fake_implicit_forces(ob, forcetime, NULL,NULL,NULL); - softbody_apply_goalsnap(ob); - timedone += forcetime; - loops++; - if (sb_nlc) - { - if (sb_nlc != nlGetCurrent())printf("Aye NL context mismatch! in softbody.c !\n"); - nlDeleteContext(sb_nlc); - sb_nlc = NULL; - } - /* ask for user break */ - if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; - } + /* do simulation */ + cache->flag |= PTCACHE_SIMULATION_VALID; + cache->simframe= framenr; + /* checking time: */ + dtime = framedelta*timescale; + softbody_step(ob, sb, dtime); - }/*SOLVER SELECT*/ - else{ - printf("softbody no valid solver ID!"); - }/*SOLVER SELECT*/ + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, 0); - if(sb->solverflags & SBSO_MONITOR ){ - sct=PIL_check_seconds_timer(); - if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name); - } + sbWriteCache(ob, framenr); + } + else { + /* time step backwards or too large forward - do nothing */ + if(cache->flag & PTCACHE_SIMULATION_VALID) { + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + } } - - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, 0); - sb->ctime= ctime; - - softbody_write_cache(ob, framenr); } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 3b14cb8adac..2c5b49246fb 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -109,13 +109,13 @@ PackedFile* sound_find_packedfile(bSound *sound) // convert sound->name to abolute filename strcpy(soundname, sound->name); - BLI_convertstringcode(soundname, G.sce, G.scene->r.cfra); + BLI_convertstringcode(soundname, G.sce); search = G.main->sound.first; while (search) { if (search->sample && search->sample->packedfile) { strcpy(searchname, search->sample->name); - BLI_convertstringcode(searchname, G.sce, G.scene->r.cfra); + BLI_convertstringcode(searchname, G.sce); if (BLI_streq(searchname, soundname)) { pf = search->sample->packedfile; @@ -125,7 +125,7 @@ PackedFile* sound_find_packedfile(bSound *sound) if (search->newpackedfile) { strcpy(searchname, search->name); - BLI_convertstringcode(searchname, G.sce, G.scene->r.cfra); + BLI_convertstringcode(searchname, G.sce); if (BLI_streq(searchname, soundname)) { pf = search->newpackedfile; break; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 0b1563beced..bba79bd6d28 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -27,7 +24,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdlib.h> @@ -42,16 +39,18 @@ #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BKE_bad_level_calls.h" #include "BKE_cdderivedmesh.h" #include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_displist.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_scene.h" #include "BKE_subsurf.h" -#include "BKE_displist.h" -#include "BKE_DerivedMesh.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" @@ -222,7 +221,7 @@ static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGV break; } - fverts[j]= (CCGVertHDL)(nv->f*4 + nv->tfindex); + fverts[j]= SET_INT_IN_POINTER(nv->f*4 + nv->tfindex); } } @@ -239,7 +238,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, EdgeHash *ehash; float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss); - limit[0]= limit[1]= 0.0001f; + limit[0]= limit[1]= STD_UV_CONNECT_LIMIT; vmap= make_uv_vert_map(mface, tface, totface, totvert, 0, limit); if (!vmap) return 0; @@ -260,7 +259,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, for (v=get_uv_map_vert(vmap, i); v; v=v->next) { if (v->separate) { CCGVert *ssv; - CCGVertHDL vhdl = (CCGVertHDL)(v->f*4 + v->tfindex); + CCGVertHDL vhdl = SET_INT_IN_POINTER(v->f*4 + v->tfindex); float uv[3]; uv[0]= (tface+v->f)->uv[v->tfindex][0]; @@ -278,20 +277,20 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, for (i=0; i<totface; i++) { MFace *mf = &((MFace*) mface)[i]; int nverts= mf->v4? 4: 3; - CCGFace *origf= ccgSubSurf_getFace(origss, (CCGFaceHDL)i); + CCGFace *origf= ccgSubSurf_getFace(origss, SET_INT_IN_POINTER(i)); unsigned int *fv = &mf->v1; get_face_uv_map_vert(vmap, mf, i, fverts); for (j=0; j<nverts; j++) { - int v0 = (int)fverts[j]; - int v1 = (int)fverts[(j+1)%nverts]; + int v0 = GET_INT_FROM_POINTER(fverts[j]); + int v1 = GET_INT_FROM_POINTER(fverts[(j+1)%nverts]); MVert *mv0 = mvert + *(fv+j); MVert *mv1 = mvert + *(fv+((j+1)%nverts)); if (!BLI_edgehash_haskey(ehash, v0, v1)) { CCGEdge *e, *orige= ccgSubSurf_getFaceEdge(origss, origf, j); - CCGEdgeHDL ehdl= (CCGEdgeHDL)(i*4 + j); + CCGEdgeHDL ehdl= SET_INT_IN_POINTER(i*4 + j); float crease; if ((mv0->flag&mv1->flag) & ME_VERT_MERGED) @@ -314,7 +313,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, CCGFace *f; get_face_uv_map_vert(vmap, mf, i, fverts); - ccgSubSurf_syncFace(ss, (CCGFaceHDL)i, nverts, fverts, &f); + ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), nverts, fverts, &f); } free_uv_vert_map(vmap); @@ -356,7 +355,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, fi = ccgSubSurf_getFaceIterator(uvss); for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { CCGFace *f = ccgFaceIterator_getCurrent(fi); - faceMap[(int) ccgSubSurf_getFaceFaceHandle(uvss, f)] = f; + faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(uvss, f))] = f; } ccgFaceIterator_free(fi); @@ -500,7 +499,7 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { CCGVert *v = ccgVertIterator_getCurrent(vi); - vertMap2[(int) ccgSubSurf_getVertVertHandle(ss, v)] = v; + vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v))] = v; } ccgVertIterator_free(vi); @@ -510,7 +509,7 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(ei); - edgeMap2[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)] = e; + edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(ss, e))] = e; } totface = ccgSubSurf_getNumFaces(ss); @@ -519,7 +518,7 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { CCGFace *f = ccgFaceIterator_getCurrent(fi); - faceMap2[(int) ccgSubSurf_getFaceFaceHandle(ss, f)] = f; + faceMap2[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f))] = f; } ccgFaceIterator_free(fi); @@ -547,7 +546,7 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, for(S = 0; S < numVerts; S++) { CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); - vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); } DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i); @@ -611,9 +610,9 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, CCGVert *v; v = ccgSubSurf_getEdgeVert0(ss, e); - vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); v = ccgSubSurf_getEdgeVert1(ss, e); - vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); for(x = 1; x < edgeSize - 1; x++) { float w[2]; @@ -636,7 +635,7 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, CCGVert *v = vertMap2[index]; int vertIdx; - vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); DM_copy_vert_data(dm, result, vertIdx, i, 1); VecCopyf(mvert->co, ccgSubSurf_getVertData(ss, v)); @@ -697,7 +696,7 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, for(index = 0; index < totedge; index++) { CCGEdge *e = edgeMap2[index]; unsigned int flags = 0; - int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(ss, e)); if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; @@ -731,7 +730,7 @@ DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, int mat_nr; int flag; int mapIndex = ccgDM_getFaceMapIndex(NULL, ss, f); - int faceIdx = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + int faceIdx = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f)); if(!ssFromEditmesh) { MFace origMFace; @@ -835,9 +834,9 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, CCGVert *v; if(vertexCos) { - ccgSubSurf_syncVert(ss, (CCGVertHDL)i, vertexCos[i], 0, &v); + ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), vertexCos[i], 0, &v); } else { - ccgSubSurf_syncVert(ss, (CCGVertHDL)i, mv->co, 0, &v); + ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), mv->co, 0, &v); } ((int*)ccgSubSurf_getVertUserData(ss, v))[1] = *index; @@ -852,8 +851,8 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, crease = useFlatSubdiv ? creaseFactor : me->crease * creaseFactor / 255.0f; - ccgSubSurf_syncEdge(ss, (CCGEdgeHDL)i, (CCGVertHDL)me->v1, - (CCGVertHDL)me->v2, crease, &e); + ccgSubSurf_syncEdge(ss, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(me->v1), + SET_INT_IN_POINTER(me->v2), crease, &e); ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = *index; } @@ -863,16 +862,16 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, for (i = 0; i < totface; i++, mf++, index++) { CCGFace *f; - fVerts[0] = (CCGVertHDL) mf->v1; - fVerts[1] = (CCGVertHDL) mf->v2; - fVerts[2] = (CCGVertHDL) mf->v3; - fVerts[3] = (CCGVertHDL) mf->v4; + fVerts[0] = SET_INT_IN_POINTER(mf->v1); + fVerts[1] = SET_INT_IN_POINTER(mf->v2); + fVerts[2] = SET_INT_IN_POINTER(mf->v3); + fVerts[3] = SET_INT_IN_POINTER(mf->v4); // this is very bad, means mesh is internally consistent. // it is not really possible to continue without modifying // other parts of code significantly to handle missing faces. // since this really shouldn't even be possible we just bail. - if(ccgSubSurf_syncFace(ss, (CCGFaceHDL)i, fVerts[3] ? 4 : 3, + if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fVerts[3] ? 4 : 3, fVerts, &f) == eCCGError_InvalidValue) { static int hasGivenError = 0; @@ -1270,7 +1269,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) CCGEdge *e = ccgdm->edgeMap[index].edge; unsigned int flags = 0; int x; - int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(ss, e)); if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; @@ -1354,7 +1353,7 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) { for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { CCGVert *v = ccgVertIterator_getCurrent(vi); - vertMap2[(int) ccgSubSurf_getVertVertHandle(ss, v)] = v; + vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v))] = v; } ccgVertIterator_free(vi); @@ -1364,7 +1363,7 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) { for (i=0; !ccgEdgeIterator_isStopped(ei); i++,ccgEdgeIterator_next(ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(ei); - edgeMap2[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)] = e; + edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(ss, e))] = e; } totface = ccgSubSurf_getNumFaces(ss); @@ -1373,7 +1372,7 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) { for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { CCGFace *f = ccgFaceIterator_getCurrent(fi); - faceMap2[(int) ccgSubSurf_getFaceFaceHandle(ss, f)] = f; + faceMap2[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f))] = f; } ccgFaceIterator_free(fi); @@ -1610,7 +1609,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int)) { for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { CCGFace *f = ccgFaceIterator_getCurrent(fi); int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); - int index = (int) ccgSubSurf_getFaceFaceHandle(ss, f); + int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f)); int drawSmooth, mat_nr; if(faceFlags) { @@ -1750,7 +1749,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); int drawSmooth, index = ccgDM_getFaceMapIndex(ccgdm, ss, f); - int origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f)); unsigned char *cp= NULL; int mat_nr; @@ -1908,7 +1907,6 @@ static void ccgDM_drawUVEdges(DerivedMesh *dm) } static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) { - GLubyte act_face_stipple[32*32/8] = DM_FACE_STIPPLE; CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; CCGSubSurf *ss = ccgdm->ss; CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); @@ -1921,7 +1919,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u int drawSmooth, index = ccgDM_getFaceMapIndex(ccgdm, ss, f); int origIndex; - origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f)); if(faceFlags) drawSmooth = (faceFlags[origIndex*4] & ME_SMOOTH); else drawSmooth = 1; @@ -1933,7 +1931,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u if (draw) { if (draw==2) { glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple(act_face_stipple); + glPolygonStipple(stipple_quarttone); } for (S=0; S<numVerts; S++) { @@ -2164,7 +2162,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { CCGVert *v = ccgVertIterator_getCurrent(vi); - ccgdm->vertMap[(int) ccgSubSurf_getVertVertHandle(ss, v)].vert = v; + ccgdm->vertMap[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v))].vert = v; } ccgVertIterator_free(vi); @@ -2174,7 +2172,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { CCGEdge *e = ccgEdgeIterator_getCurrent(ei); - ccgdm->edgeMap[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)].edge = e; + ccgdm->edgeMap[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(ss, e))].edge = e; } totface = ccgSubSurf_getNumFaces(ss); @@ -2183,7 +2181,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { CCGFace *f = ccgFaceIterator_getCurrent(fi); - ccgdm->faceMap[(int) ccgSubSurf_getFaceFaceHandle(ss, f)].face = f; + ccgdm->faceMap[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f))].face = f; } ccgFaceIterator_free(fi); @@ -2216,7 +2214,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges); int mapIndex = ccgDM_getFaceMapIndex(ccgdm, ss, f); - int origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f)); FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; int S, x, y; int vertIdx[4]; @@ -2231,7 +2229,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, for(S = 0; S < numVerts; S++) { CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); - vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); } DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, weight[0][0], @@ -2337,13 +2335,13 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int mapIndex = ccgDM_getEdgeMapIndex(ccgdm, ss, e); int x; int vertIdx[2]; - int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(ss, e)); CCGVert *v; v = ccgSubSurf_getEdgeVert0(ss, e); - vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); v = ccgSubSurf_getEdgeVert1(ss, e); - vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); ccgdm->edgeMap[index].startVert = vertNum; ccgdm->edgeMap[index].startEdge = edgeNum; @@ -2377,7 +2375,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int mapIndex = ccgDM_getVertMapIndex(ccgdm, ccgdm->ss, v); int vertIdx; - vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v); + vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); ccgdm->vertMap[index].startVert = vertNum; @@ -2421,7 +2419,14 @@ struct DerivedMesh *subsurf_make_derived_from_derived( useSubsurfUv, dm); } else if(useRenderParams) { /* Do not use cache in render mode. */ - CCGSubSurf *ss = _getSubSurf(NULL, smd->renderLevels, 0, 1, useSimple); + CCGSubSurf *ss; + int levels; + + levels= get_render_subsurf_level(&G.scene->r, smd->renderLevels); + if(levels == 0) + return dm; + + ss = _getSubSurf(NULL, levels, 0, 1, useSimple); ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); @@ -2503,7 +2508,7 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]) vi = ccgSubSurf_getVertIterator(ss); for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { CCGVert *v = ccgVertIterator_getCurrent(vi); - int idx = (int) ccgSubSurf_getVertVertHandle(ss, v); + int idx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(ss, v)); int N = ccgSubSurf_getVertNumEdges(ss, v); int numFaces = ccgSubSurf_getVertNumFaces(ss, v); float *co; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index ea0dabe1e81..872f81ead63 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <string.h> /* strstr */ @@ -215,15 +212,14 @@ int reopen_text(Text *text) int i, llen, len; unsigned char *buffer; TextLine *tmp; - char sdir[FILE_MAXDIR]; char sfile[FILE_MAXFILE]; char str[FILE_MAXDIR+FILE_MAXFILE]; if (!text || !text->name) return 0; BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE); - BLI_convertstringcode(str, G.sce, G.scene->r.cfra); - BLI_split_dirfile(str, sdir, sfile); + BLI_convertstringcode(str, G.sce); + BLI_split_dirfile_basic(str, NULL, sfile); fp= fopen(str, "r"); if(fp==NULL) return 0; @@ -315,14 +311,13 @@ Text *add_text(char *file) unsigned char *buffer; TextLine *tmp; Text *ta; - char sdir[FILE_MAXDIR]; char sfile[FILE_MAXFILE]; char str[FILE_MAXDIR+FILE_MAXFILE]; BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE); if (G.scene) /* can be NULL (bg mode) */ - BLI_convertstringcode(str, G.sce, G.scene->r.cfra); - BLI_split_dirfile(str, sdir, sfile); + BLI_convertstringcode(str, G.sce); + BLI_split_dirfile_basic(str, NULL, sfile); fp= fopen(str, "r"); if(fp==NULL) return NULL; @@ -1033,7 +1028,8 @@ int txt_find_string(Text *text, char *findstr) void txt_cut_sel (Text *text) { - txt_copy_sel(text); + if (!G.background) /* Python uses txt_cut_sel, which it should not, working around for now */ + txt_copy_clipboard(text); txt_delete_sel(text); txt_make_dirty(text); @@ -2041,6 +2037,7 @@ void txt_delete_char (Text *text) if (txt_has_sel(text)) { /* deleting a selection */ txt_delete_sel(text); + return; } else if (text->curc== text->curl->len) { /* Appending two lines */ if (text->curl->next) { @@ -2075,6 +2072,7 @@ void txt_backspace_char (Text *text) if (txt_has_sel(text)) { /* deleting a selection */ txt_delete_sel(text); + return; } else if (text->curc==0) { /* Appending two lines */ if (text->curl->prev) { @@ -2352,7 +2350,7 @@ int setcurr_tab (Text *text) int test = 0; char *word = ":"; char *comm = "#"; - char back_words[3][7] = {"return", "break", "pass"}; + char back_words[4][7] = {"return", "break", "pass", "yield"}; if (!text) return 0; if (!text->curl) return 0; @@ -2369,16 +2367,25 @@ int setcurr_tab (Text *text) if(strstr(text->curl->line, word)) { //if we find a : then add a tab but not if it is in a comment - if(strcspn(text->curl->line, word) < strcspn(text->curl->line, comm)) + int a, indent = 0; + for(a=0; text->curl->line[a] != '\0'; a++) { + if (text->curl->line[a]=='#') { + break; + } else if (text->curl->line[a]==':') { + indent = 1; + } else if (text->curl->line[a]==']') { + indent = 0; + } + } + if (indent) { i++; - } } - while(test < 3) + for(test=0; test < 4; test++) { - //if there are these 3 key words then remove a tab because we are done with the block + //if there are these 4 key words then remove a tab because we are done with the block if(strstr(text->curl->line, back_words[test]) && i > 0) { if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm)) @@ -2386,7 +2393,6 @@ int setcurr_tab (Text *text) i--; } } - test++; } return i; } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index d4a085ff8bd..37804bf68ac 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -3,15 +3,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,7 +26,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <stdio.h> @@ -55,6 +52,7 @@ #include "DNA_image_types.h" #include "DNA_world_types.h" #include "DNA_brush_types.h" +#include "DNA_node_types.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -75,6 +73,7 @@ #include "BKE_icons.h" #include "BKE_ipo.h" #include "BKE_brush.h" +#include "BKE_node.h" /* ------------------------------------------------------------------------- */ @@ -107,6 +106,7 @@ void open_plugin_tex(PluginTex *pit) pit->result= 0; pit->cfra= 0; pit->version= 0; + pit->instance_init= 0; /* clear the error list */ PIL_dynlib_get_error_as_string(NULL); @@ -126,7 +126,7 @@ void open_plugin_tex(PluginTex *pit) if (version != 0) { pit->version= version(); - if (pit->version>=2 && pit->version<=5) { + if( pit->version >= 2 && pit->version <=6) { int (*info_func)(PluginInfo *); PluginInfo *info= (PluginInfo*) MEM_mallocN(sizeof(PluginInfo), "plugin_info"); @@ -728,6 +728,7 @@ Tex *give_current_texture(Object *ob, int act) Lamp *la = 0; MTex *mtex = 0; Tex *tex = 0; + bNode *node; if(ob==0) return 0; if(ob->totcol==0) return 0; @@ -738,7 +739,6 @@ Tex *give_current_texture(Object *ob, int act) mtex= la->mtex[(int)(la->texact)]; if(mtex) tex= mtex->tex; } - else tex= 0; } else { if(act>ob->totcol) act= ob->totcol; else if(act==0) act= 1; @@ -751,13 +751,25 @@ Tex *give_current_texture(Object *ob, int act) if(matarar && *matarar) ma= (*matarar)[act-1]; else ma= 0; - + } + + if(ma && ma->use_nodes && ma->nodetree) { + node= nodeGetActiveID(ma->nodetree, ID_TE); + + if(node) { + tex= (Tex *)node->id; + ma= NULL; + } + else { + node= nodeGetActiveID(ma->nodetree, ID_MA); + if(node) + ma= (Material*)node->id; + } } if(ma) { mtex= ma->mtex[(int)(ma->texact)]; if(mtex) tex= mtex->tex; } - else tex= 0; } return tex; diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c index 5f2c48b5221..24295cd3ad0 100644 --- a/source/blender/blenkernel/intern/verse_bitmap_node.c +++ b/source/blender/blenkernel/intern/verse_bitmap_node.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,7 +19,7 @@ * * Contributor(s): Jiri Hnidek. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef WITH_VERSE diff --git a/source/blender/blenkernel/intern/verse_geometry_node.c b/source/blender/blenkernel/intern/verse_geometry_node.c index 613d4eadbec..010e42d5cb7 100644 --- a/source/blender/blenkernel/intern/verse_geometry_node.c +++ b/source/blender/blenkernel/intern/verse_geometry_node.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,7 +19,7 @@ * * Contributor(s): Jiri Hnidek. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef WITH_VERSE diff --git a/source/blender/blenkernel/intern/verse_method.c b/source/blender/blenkernel/intern/verse_method.c index 89b5282acfd..30886782019 100644 --- a/source/blender/blenkernel/intern/verse_method.c +++ b/source/blender/blenkernel/intern/verse_method.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,7 +19,7 @@ * * Contributor(s): Nathan Letwory. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef WITH_VERSE diff --git a/source/blender/blenkernel/intern/verse_node.c b/source/blender/blenkernel/intern/verse_node.c index fd5a25598d3..1fe86f24d6e 100644 --- a/source/blender/blenkernel/intern/verse_node.c +++ b/source/blender/blenkernel/intern/verse_node.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,7 +19,7 @@ * * Contributor(s): Jiri Hnidek. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef WITH_VERSE diff --git a/source/blender/blenkernel/intern/verse_object_node.c b/source/blender/blenkernel/intern/verse_object_node.c index d8be38cd00f..89f9f0edcbd 100644 --- a/source/blender/blenkernel/intern/verse_object_node.c +++ b/source/blender/blenkernel/intern/verse_object_node.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,7 +19,7 @@ * * Contributor(s): Jiri Hnidek. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef WITH_VERSE diff --git a/source/blender/blenkernel/intern/verse_session.c b/source/blender/blenkernel/intern/verse_session.c index 1226fffd929..28a9ef85536 100644 --- a/source/blender/blenkernel/intern/verse_session.c +++ b/source/blender/blenkernel/intern/verse_session.c @@ -1,15 +1,12 @@ /** * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -22,7 +19,7 @@ * * Contributor(s): Jiri Hnidek. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #ifdef WITH_VERSE diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 8d3234475a4..814d6f8baf1 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -4,15 +4,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): none yet. * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** */ #include <string.h> diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index bd6859973b1..44004eeee80 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -4,15 +4,12 @@ * * $Id$ * - * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. The Blender - * Foundation also sells licenses for use in proprietary software under - * the Blender License. See http://www.blender.org/BL/ for information - * about this. + * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,7 +27,7 @@ * * Contributor(s): Robert Wenzlaff * - * ***** END GPL/BL DUAL LICENSE BLOCK ***** + * ***** END GPL LICENSE BLOCK ***** * */ @@ -123,7 +120,7 @@ void makeavistring (RenderData *rd, char *string) if (string==0) return; strcpy(string, rd->pic); - BLI_convertstringcode(string, G.sce, rd->cfra); + BLI_convertstringcode(string, G.sce); BLI_make_existing_file(string); diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index cbaf1f8c605..e79e36a1498 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -41,6 +41,12 @@ #define FFMPEG_CODEC_TIME_BASE 1 #endif +#if LIBAVFORMAT_VERSION_INT >= (52 << 16) +#define OUTFILE_PB (outfile->pb) +#else +#define OUTFILE_PB (&outfile->pb) +#endif + #if defined(WIN32) && (!(defined snprintf)) #define snprintf _snprintf #endif @@ -214,6 +220,10 @@ static const char** get_file_extensions(int format) static const char * rv[] = { ".avi", NULL }; return rv; } + case FFMPEG_FLV: { + static const char * rv[] = { ".flv", NULL }; + return rv; + } default: return NULL; } @@ -593,6 +603,9 @@ void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) case FFMPEG_XVID: fmt->video_codec = CODEC_ID_XVID; break; + case FFMPEG_FLV: + fmt->video_codec = CODEC_ID_FLV1; + break; case FFMPEG_MPEG4: default: fmt->video_codec = CODEC_ID_MPEG4; @@ -618,6 +631,9 @@ void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) return; } } + + fmt->audio_codec = ffmpeg_audio_codec; + if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; if (ffmpeg_multiplex_audio @@ -679,7 +695,8 @@ void makeffmpegstring(char* string) { if (!string || !exts) return; strcpy(string, G.scene->r.pic); - BLI_convertstringcode(string, G.sce, G.scene->r.cfra); + BLI_convertstringcode(string, G.sce); + BLI_convertstringframe(string, G.scene->r.cfra); BLI_make_existing_file(string); @@ -751,7 +768,7 @@ void append_ffmpeg(int frame, int *pixels, int rectx, int recty) write_video_frame(generate_video_frame((unsigned char*) pixels)); if (ffmpeg_autosplit) { - if (url_ftell(&outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) { + if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) { end_ffmpeg(); ffmpeg_autosplit_count++; start_ffmpeg_impl(ffmpeg_renderdata, @@ -798,7 +815,7 @@ void end_ffmpeg(void) } if (outfile && outfile->oformat) { if (!(outfile->oformat->flags & AVFMT_NOFILE)) { - url_fclose(&outfile->pb); + url_fclose(OUTFILE_PB); } } if (outfile) { |