4
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version 2
9
* of the License, or (at your option) any later version. The Blender
10
* Foundation also sells licenses for use in proprietary software under
11
* the Blender License. See http://www.blender.org/BL/ for information
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software Foundation,
21
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
* The Original Code is Copyright (C) 2004 by NaN Holding BV.
24
* All rights reserved.
26
* The Original Code is: all of this file.
28
* Contributor(s): none yet.
30
* ***** END GPL/BL DUAL LICENSE BLOCK *****
35
meshtools.c: no editmode, tools operating on meshes
39
void fasterdraw(void);
40
void slowerdraw(void);
42
void vertexnormals_mesh(Mesh *me, float *extverts);
43
void sort_faces(void);
55
#include "MEM_guardedalloc.h"
57
#include "DNA_mesh_types.h"
58
#include "DNA_meshdata_types.h"
59
#include "DNA_object_types.h"
60
#include "DNA_material_types.h"
61
#include "DNA_scene_types.h"
62
#include "DNA_screen_types.h"
63
#include "DNA_view3d_types.h"
65
#include "BLI_blenlib.h"
66
#include "BLI_arithb.h"
68
#include "BKE_displist.h"
69
#include "BKE_global.h"
70
#include "BKE_library.h"
73
#include "BKE_material.h"
74
#include "BKE_object.h"
75
#include "BKE_utildefines.h"
77
#include "BIF_editmesh.h"
78
#include "BIF_graphics.h"
79
#include "BIF_mywindow.h"
80
#include "BIF_screen.h"
81
#include "BIF_space.h"
82
#include "BIF_toolbox.h"
83
#include "BIF_editconstraint.h"
85
#include "BDR_editobject.h"
86
#include "BDR_editface.h"
91
#include "BIF_meshtools.h" /* include ourself for prototypes */
94
/* * ********************** no editmode!!! *********** */
97
/** tests whether selected mesh objects have tfaces */
98
static int testSelected_TfaceMesh(void)
106
if(base->object->type==OB_MESH) {
107
me= base->object->data;
121
Material **matar, *ma;
123
MVert *mvert, *mvertmain;
124
MEdge *medge = NULL, *medgemain;
125
MFace *mface = NULL, *mfacemain;
126
TFace *tface = NULL, *tfacemain;
127
unsigned int *mcol=NULL, *mcolmain;
128
float imat[4][4], cmat[4][4];
129
int a, b, totcol, totedge=0, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT];
131
int i, j, index, haskey=0, hasdefgroup=0;
132
bDeformGroup *dg, *odg;
133
MDeformVert *dvert, *dvertmain;
138
if(!ob || ob->type!=OB_MESH) return;
143
if TESTBASELIB(base) {
144
if(base->object->type==OB_MESH) {
145
me= base->object->data;
146
totvert+= me->totvert;
147
totface+= me->totface;
148
if(me->medge) hasedges= 1;
150
if(base->object == ob) ok= 1;
162
error("Can't join meshes with vertex keys");
165
/* that way the active object is always selected */
168
if(totvert==0 || totvert>MESH_MAX_VERTS) return;
170
if(okee("Join selected meshes")==0) return;
173
/* if needed add edges to other meshes */
175
for(base= FIRSTBASE; base; base= base->next) {
176
if TESTBASELIB(base) {
177
if(base->object->type==OB_MESH) {
178
me= base->object->data;
179
if(me->medge==NULL) make_edges(me);
180
totedge += me->totedge;
186
/* new material indices and material array */
187
matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh");
190
/* obact materials in new main array, is nicer start! */
191
for(a=1; a<=ob->totcol; a++) {
192
matar[a-1]= give_current_material(ob, a);
193
id_us_plus((ID *)matar[a-1]);
194
/* increase id->us : will be lowered later */
199
if TESTBASELIB(base) {
200
if(ob!=base->object && base->object->type==OB_MESH) {
201
me= base->object->data;
203
// Join this object's vertex groups to the base one's
204
for (dg=base->object->defbase.first; dg; dg=dg->next){
207
/* See if this group exists in the object */
208
for (odg=ob->defbase.first; odg; odg=odg->next){
209
if (!strcmp(odg->name, dg->name)){
214
odg = MEM_callocN (sizeof(bDeformGroup), "deformGroup");
215
memcpy (odg, dg, sizeof(bDeformGroup));
216
BLI_addtail(&ob->defbase, odg);
220
if (ob->defbase.first && ob->actdef==0)
224
for(a=1; a<=base->object->totcol; a++) {
225
ma= give_current_material(base->object, a);
227
for(b=0; b<totcol; b++) {
228
if(ma == matar[b]) break;
235
if(totcol>=MAXMAT-1) break;
240
if(totcol>=MAXMAT-1) break;
246
mvert= mvertmain= MEM_mallocN(totvert*sizeof(MVert), "joinmesh vert");
248
if(totedge) medge= medgemain= MEM_callocN(totedge*sizeof(MEdge), "joinmesh edge");
249
else medgemain= NULL;
251
if (totface) mface= mfacemain= MEM_mallocN(totface*sizeof(MFace), "joinmesh face");
252
else mfacemain= NULL;
254
if(me->mcol) mcol= mcolmain= MEM_callocN(totface*4*sizeof(int), "joinmesh mcol");
257
/* if active object doesn't have Tfaces, but one in the selection does,
258
make TFaces for active, so we don't lose texture information in the
260
if(me->tface || testSelected_TfaceMesh()) tface= tfacemain= MEM_callocN(totface*4*sizeof(TFace), "joinmesh4");
261
else tfacemain= NULL;
263
if(me->dvert || hasdefgroup)
264
dvert= dvertmain= MEM_callocN(totvert*sizeof(MDeformVert), "joinmesh5");
265
else dvert=dvertmain= NULL;
269
/* inverse transorm all selected meshes in this object */
270
Mat4Invert(imat, ob->obmat);
275
if TESTBASELIB(base) {
276
if(base->object->type==OB_MESH) {
278
me= base->object->data;
282
memcpy(mvert, me->mvert, me->totvert*sizeof(MVert));
284
copy_dverts(dvert, me->dvert, me->totvert);
288
for (i=0; i<me->totvert; i++){
289
for (j=0; j<dvert[i].totweight; j++){
290
// Find the old vertex group
291
odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr);
293
// Search for a match in the new object
294
for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){
295
if (!strcmp(dg->name, odg->name)){
296
dvert[i].dw[j].def_nr = index;
306
if(base->object != ob) {
307
/* watch this: switch matmul order really goes wrong */
308
Mat4MulMat4(cmat, base->object->obmat, imat);
312
Mat4MulVecfl(cmat, mvert->co);
316
else mvert+= me->totvert;
319
if(me->mcol) memcpy(mcol, me->mcol, me->totface*4*4);
320
mcol+= 4*me->totface;
325
/* make mapping for materials */
326
memset(map, 0, 4*MAXMAT);
327
for(a=1; a<=base->object->totcol; a++) {
328
ma= give_current_material(base->object, a);
330
for(b=0; b<totcol; b++) {
339
memcpy(mface, me->mface, me->totface*sizeof(MFace));
345
if(mface->v3) mface->v3+= vertofs;
346
if(mface->v4) mface->v4+= vertofs;
348
mface->mat_nr= map[(int)mface->mat_nr];
355
memcpy(tface, me->tface, me->totface*sizeof(TFace));
359
for(a=0; a<me->totface; a++, tface++) {
360
default_tface(tface);
368
memcpy(medge, me->medge, me->totedge*sizeof(MEdge));
378
vertofs+= me->totvert;
380
if(base->object!=ob) {
381
free_and_unlink_base(base);
390
if(me->mvert) MEM_freeN(me->mvert);
391
me->mvert= mvertmain;
393
if(me->medge) MEM_freeN(me->medge);
394
me->medge= medgemain;
396
if(me->mface) MEM_freeN(me->mface);
397
me->mface= mfacemain;
399
if(me->dvert) free_dverts(me->dvert, me->totvert);
400
me->dvert = dvertmain;
402
if(me->mcol) MEM_freeN(me->mcol);
403
me->mcol= (MCol *)mcolmain;
405
if(me->tface) MEM_freeN(me->tface);
406
me->tface= tfacemain;
408
me->totvert= totvert;
409
me->totedge= totedge;
410
me->totface= totface;
412
/* old material array */
413
for(a=1; a<=ob->totcol; a++) {
417
for(a=1; a<=me->totcol; a++) {
421
if(ob->mat) MEM_freeN(ob->mat);
422
if(me->mat) MEM_freeN(me->mat);
427
ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
429
else MEM_freeN(matar);
431
ob->totcol= me->totcol= totcol;
434
/* other mesh users */
435
test_object_materials((ID *)me);
438
exit_editmode(1); // freedata, but no undo
440
test_scene_constraints(); // always call after delete object (stupid!)
442
allqueue(REDRAWVIEW3D, 0);
443
allqueue(REDRAWBUTSSHADING, 0);
446
BIF_undo_push("Join Mesh");
450
void fasterdraw(void)
460
me= G.main->mesh.first;
462
me->flag &= ~ME_ISDONE;
468
if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
469
me= base->object->data;
470
if(me->id.lib==0 && (me->flag & ME_ISDONE)==0) {
471
me->flag |= ME_ISDONE;
474
for(a=0; a<me->totface; a++) {
475
if( (mface->edcode & ME_V1V2) && ( (toggle++) & 1) ) {
476
mface->edcode-= ME_V1V2;
478
if( (mface->edcode & ME_V2V3) && ( (toggle++) & 1)) {
479
mface->edcode-= ME_V2V3;
481
if( (mface->edcode & ME_V3V1) && ( (toggle++) & 1)) {
482
mface->edcode-= ME_V3V1;
484
if( (mface->edcode & ME_V4V1) && ( (toggle++) & 1)) {
485
mface->edcode-= ME_V4V1;
487
if( (mface->edcode & ME_V3V4) && ( (toggle++) & 1)) {
488
mface->edcode-= ME_V3V4;
497
/* important?: reset flags again */
498
me= G.main->mesh.first;
500
me->flag &= ~ME_ISDONE;
504
allqueue(REDRAWVIEW3D, 0);
507
void slowerdraw(void) /* reset fasterdraw */
518
if( TESTBASELIB(base) && (base->object->type==OB_MESH)) {
519
me= base->object->data;
524
for(a=0; a<me->totface; a++) {
526
mface->edcode |= ME_V1V2|ME_V2V3;
534
allqueue(REDRAWVIEW3D, 0);
537
/* ***************** */
539
/* this one for NOT in editmode
541
(only used by external modules, that is, until now by the
544
TODO: Probably it's better to convert the mesh into a EditMesh, call
545
vertexnormals() and convert it back to a Mesh again.
549
static int contrpuntnorm(float *n, float *puno) /* dutch: check vertex normal */
553
inp= n[0]*puno[0]+n[1]*puno[1]+n[2]*puno[2];
555
/* angles 90 degrees: dont flip */
556
if(inp> -0.000001) return 0;
561
void vertexnormals_mesh(Mesh *me, float *extverts)
565
float n1[3], n2[3], n3[3], n4[3], co[4], fac1, fac2, fac3, fac4, *temp;
566
float *f1, *f2, *f3, *f4, xn, yn, zn, *normals;
567
float *v1, *v2, *v3, *v4, len, vnor[3];
570
if(me->totvert==0) return;
572
testflip= (me->flag & ME_NOPUNOFLIP)==0;
573
if((me->flag & ME_TWOSIDED)==0) testflip= 0; /* large angles */
576
/* fake vertex normals for 'halopuno' (render option) */
578
for(a=0; a<me->totvert; a++, mvert++) {
579
VECCOPY(n1, mvert->co);
581
mvert->no[0]= 32767.0*n1[0];
582
mvert->no[1]= 32767.0*n1[1];
583
mvert->no[2]= 32767.0*n1[2];
588
normals= MEM_callocN(me->totvert*3*sizeof(float), "normals");
590
/* calculate cosine angles, and add to vertex normal */
593
for(a=0; a<me->totface; a++, mface++) {
595
if(mface->v3==0) continue;
598
v1= extverts+3*mface->v1;
599
v2= extverts+3*mface->v2;
600
v3= extverts+3*mface->v3;
601
v4= extverts+3*mface->v4;
604
v1= (mvert+mface->v1)->co;
605
v2= (mvert+mface->v2)->co;
606
v3= (mvert+mface->v3)->co;
607
v4= (mvert+mface->v4)->co;
619
co[0]= saacos(-n3[0]*n1[0]-n3[1]*n1[1]-n3[2]*n1[2]);
620
co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
621
co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
630
co[0]= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
631
co[1]= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
632
co[2]= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
633
co[3]= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
636
CalcNormFloat(v1, v2, v3, vnor);
638
temp= normals+3*mface->v1;
639
if(testflip && contrpuntnorm(vnor, temp) ) co[0]= -co[0];
640
temp[0]+= co[0]*vnor[0];
641
temp[1]+= co[0]*vnor[1];
642
temp[2]+= co[0]*vnor[2];
644
temp= normals+3*mface->v2;
645
if(testflip && contrpuntnorm(vnor, temp) ) co[1]= -co[1];
646
temp[0]+= co[1]*vnor[0];
647
temp[1]+= co[1]*vnor[1];
648
temp[2]+= co[1]*vnor[2];
650
temp= normals+3*mface->v3;
651
if(testflip && contrpuntnorm(vnor, temp) ) co[2]= -co[2];
652
temp[0]+= co[2]*vnor[0];
653
temp[1]+= co[2]*vnor[1];
654
temp[2]+= co[2]*vnor[2];
657
temp= normals+3*mface->v4;
658
if(testflip && contrpuntnorm(vnor, temp) ) co[3]= -co[3];
659
temp[0]+= co[3]*vnor[0];
660
temp[1]+= co[3]*vnor[1];
661
temp[2]+= co[3]*vnor[2];
665
/* normalize vertex normals */
667
for(a=0; a<me->totvert; a++, mvert++) {
668
len= Normalise(normals+3*a);
670
VECCOPY(n1, normals+3*a);
673
mvert->no[0]= 32767.0*n1[0];
674
mvert->no[1]= 32767.0*n1[1];
675
mvert->no[2]= 32767.0*n1[2];
679
/* vertex normal flipping flags, for during render */
682
for(a=0; a<me->totface; a++, mface++) {
685
if(mface->v3==0) continue;
688
v1= extverts+3*mface->v1;
689
v2= extverts+3*mface->v2;
690
v3= extverts+3*mface->v3;
693
v1= (mvert+mface->v1)->co;
694
v2= (mvert+mface->v2)->co;
695
v3= (mvert+mface->v3)->co;
698
CalcNormFloat(v1, v2, v3, vnor);
701
f1= normals + 3*mface->v1;
702
f2= normals + 3*mface->v2;
703
f3= normals + 3*mface->v3;
705
fac1= vnor[0]*f1[0] + vnor[1]*f1[1] + vnor[2]*f1[2];
707
mface->puno = ME_FLIPV1;
709
fac2= vnor[0]*f2[0] + vnor[1]*f2[1] + vnor[2]*f2[2];
711
mface->puno += ME_FLIPV2;
713
fac3= vnor[0]*f3[0] + vnor[1]*f3[1] + vnor[2]*f3[2];
715
mface->puno += ME_FLIPV3;
718
f4= normals + 3*mface->v4;
719
fac4= vnor[0]*f4[0] + vnor[1]*f4[1] + vnor[2]*f4[2];
721
mface->puno += ME_FLIPV4;
725
/* proj for cubemap! */
730
if(zn>xn && zn>yn) mface->puno += ME_PROJXY;
731
else if(yn>xn && yn>zn) mface->puno += ME_PROJXZ;
732
else mface->puno += ME_PROJYZ;
741
/* ********************** SORT FACES ******************* */
743
static void permutate(void *list, int num, int size, int *index)
751
buf = MEM_mallocN(len, "permutate");
752
memcpy(buf, list, len);
754
for (i = 0; i < num; i++) {
755
memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
760
static MVert *mvertbase;
761
static MFace *mfacebase;
763
static int verg_mface(const void *v1, const void *v2)
770
i1 = ((int *) v1)[0];
771
i2 = ((int *) v2)[0];
776
ve1= mvertbase+x1->v1;
777
ve2= mvertbase+x2->v1;
779
if( ve1->co[2] > ve2->co[2] ) return 1;
780
else if( ve1->co[2] < ve2->co[2]) return -1;
785
void sort_faces(void)
794
if(ob->type!=OB_MESH) return;
796
if(okee("Sort faces in Z axis")==0) return;
798
if(me->totface==0) return;
800
/* create index list */
801
index = (int *) MEM_mallocN(sizeof(int) * me->totface, "sort faces");
802
for (i = 0; i < me->totface; i++) {
805
mvertbase= me->mvert;
806
mfacebase = me->mface;
808
/* sort index list instead of faces itself
809
and apply this permutation to the face list plus
810
to the texture faces */
811
qsort(index, me->totface, sizeof(int), verg_mface);
813
permutate(mfacebase, me->totface, sizeof(MFace), index);
815
permutate(me->tface, me->totface, sizeof(TFace), index);
819
allqueue(REDRAWVIEW3D, 0);
820
makeDispList(G.obedit);