=bmesh=
[blender.git] / source / blender / bmesh / intern / bmesh_interp.c
1 /**
2  * BME_interp.c    August 2008
3  *
4  *      BM interpolation functions.
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * about this.  
13  *
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.
18  *
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.
22  *
23  * The Original Code is Copyright (C) 2007 Blender Foundation.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): Geoffrey Bantle.
29  *
30  * ***** END GPL LICENSE BLOCK *****
31  */
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_mesh_types.h"
36 #include "DNA_meshdata_types.h"
37
38 #include "BKE_customdata.h" 
39 #include "BKE_utildefines.h"
40
41 #include "BLI_array.h"
42 #include "BLI_math.h"
43
44 #include "bmesh.h"
45 #include "bmesh_private.h"
46
47 /*
48  * BME_INTERP.C
49  *
50  * Functions for interpolating data across the surface of a mesh.
51  *
52 */
53
54 /**
55  *                      bmesh_data_interp_from_verts
56  *
57  *  Interpolates per-vertex data from two sources to a target.
58  * 
59  *  Returns -
60  *      Nothing
61  */
62 void BM_Data_Interp_From_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, float fac)
63 {
64         void *src[2];
65         float w[2];
66         if (v1->head.data && v2->head.data) {
67                 src[0]= v1->head.data;
68                 src[1]= v2->head.data;
69                 w[0] = 1.0f-fac;
70                 w[1] = fac;
71                 CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->head.data);
72         }
73 }
74
75 /*
76     BM Data Vert Average
77
78     Sets all the customdata (e.g. vert, loop) associated with a vert
79     to the average of the face regions surrounding it.
80 */
81
82
83 void BM_Data_Vert_Average(BMesh *bm, BMFace *f)
84 {
85         BMIter iter;
86 }
87
88 /**
89  *                      bmesh_data_facevert_edgeinterp
90  *
91  *  Walks around the faces of an edge and interpolates the per-face-edge
92  *  data between two sources to a target.
93  * 
94  *  Returns -
95  *      Nothing
96 */
97  
98 void BM_Data_Facevert_Edgeinterp(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, BMEdge *e1, float fac){
99         void *src[2];
100         float w[2];
101         BMLoop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
102         
103         w[1] = 1.0f - fac;
104         w[0] = fac;
105
106         if(!e1->l) return;
107         l = e1->l;
108         do{
109                 if(l->v == v1){ 
110                         v1loop = l;
111                         vloop = (BMLoop*)(v1loop->next);
112                         v2loop = (BMLoop*)(vloop->next);
113                 }else if(l->v == v){
114                         v1loop = (BMLoop*)(l->next);
115                         vloop = l;
116                         v2loop = (BMLoop*)(l->prev);
117                         
118                 }
119
120                 src[0] = v1loop->head.data;
121                 src[1] = v2loop->head.data;                                     
122
123                 CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->head.data);                          
124                 l = l->radial_next;
125         }while(l!=e1->l);
126 }
127
128 void BM_loops_to_corners(BMesh *bm, Mesh *me, int findex,
129                          BMFace *f, int numTex, int numCol) 
130 {
131         BMLoop *l;
132         BMIter iter;
133         MTFace *texface;
134         MTexPoly *texpoly;
135         MCol *mcol;
136         MLoopCol *mloopcol;
137         MLoopUV *mloopuv;
138         int i, j;
139
140         for(i=0; i < numTex; i++){
141                 texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
142                 texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
143                 
144                 texface->tpage = texpoly->tpage;
145                 texface->flag = texpoly->flag;
146                 texface->transp = texpoly->transp;
147                 texface->mode = texpoly->mode;
148                 texface->tile = texpoly->tile;
149                 texface->unwrap = texpoly->unwrap;
150
151                 j = 0;
152                 BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
153                         mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
154                         texface->uv[j][0] = mloopuv->uv[0];
155                         texface->uv[j][1] = mloopuv->uv[1];
156
157                         j++;
158                 }
159
160         }
161
162         for(i=0; i < numCol; i++){
163                 mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
164
165                 j = 0;
166                 BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
167                         mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
168                         mcol[j].r = mloopcol->r;
169                         mcol[j].g = mloopcol->g;
170                         mcol[j].b = mloopcol->b;
171                         mcol[j].a = mloopcol->a;
172
173                         j++;
174                 }
175         }
176 }
177
178
179
180 /**
181  *                      BM_data_interp_from_face
182  *
183  *  projects target onto source, and pulls interpolated customdata from
184  *  source.
185  * 
186  *  Returns -
187  *      Nothing
188 */
189 void BM_face_interp_from_face(BMesh *bm, BMFace *target, BMFace *source)
190 {
191         BMLoop *l1, *l2;
192         void **blocks=NULL;
193         float (*cos)[3]=NULL, *w=NULL;
194         BLI_array_staticdeclare(cos, 64);
195         BLI_array_staticdeclare(w, 64);
196         BLI_array_staticdeclare(blocks, 64);
197         
198         BM_Copy_Attributes(bm, bm, source, target);
199         
200         l2 = bm_firstfaceloop(source);
201         do {
202                 BLI_array_growone(cos);
203                 copy_v3_v3(cos[BLI_array_count(cos)-1], l2->v->co);
204                 BLI_array_growone(w);
205                 BLI_array_append(blocks, l2->head.data);
206                 l2 = l2->next;
207         } while (l2 != bm_firstfaceloop(source));
208
209         l1 = bm_firstfaceloop(target);
210         do {
211                 interp_weights_poly_v3(w, cos, source->len, l1->v->co);
212                 CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, BLI_array_count(blocks), l1->head.data);
213                 l1 = l1->next;
214         } while (l1 != bm_firstfaceloop(target));
215
216         BLI_array_free(cos);
217         BLI_array_free(w);
218         BLI_array_free(blocks);
219 }
220
221 void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source)
222 {
223         BMLoop *l;
224         void **blocks=NULL;
225         float (*cos)[3]=NULL, *w=NULL, cent[3] = {0.0f, 0.0f, 0.0f};
226         BLI_array_staticdeclare(cos, 64);
227         BLI_array_staticdeclare(w, 64);
228         BLI_array_staticdeclare(blocks, 64);
229         int i;
230         
231         BM_Copy_Attributes(bm, bm, source, target->f);
232         
233         l = bm_firstfaceloop(source);
234         do {
235                 BLI_array_growone(cos);
236                 copy_v3_v3(cos[BLI_array_count(cos)-1], l->v->co);
237                 add_v3_v3(cent, cos[BLI_array_count(cos)-1]);
238                 
239                 BLI_array_append(w, 0.0f);
240                 BLI_array_append(blocks, l->head.data);
241                 l = l->next;
242         } while (l != bm_firstfaceloop(source));
243
244         /*scale source face coordinates a bit, so points sitting directonly on an
245       edge will work.*/
246         mul_v3_fl(cent, 1.0/source->len);
247         for (i=0; i<source->len; i++) {
248                 float vec[3];
249                 sub_v3_v3v3(vec, cent, cos[i]);
250                 mul_v3_fl(vec, 0.01);
251                 add_v3_v3(cos[i], vec);
252         }
253         
254         /*interpolate*/
255         interp_weights_poly_v3(w, cos, source->len, target->v->co);
256         CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, source->len, target->head.data);
257         
258         BLI_array_free(cos);
259         BLI_array_free(w);
260         BLI_array_free(blocks);
261 }
262
263 static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
264 {
265         BMIter iter;
266         BLI_mempool *oldpool = olddata->pool;
267         void *block;
268
269         CustomData_bmesh_init_pool(data, data==&bm->ldata ? 2048 : 512);
270
271         if (data == &bm->vdata) {
272                 BMVert *eve;
273                 
274                 BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
275                         block = NULL;
276                         CustomData_bmesh_set_default(data, &block);
277                         CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block);
278                         CustomData_bmesh_free_block(olddata, &eve->head.data);
279                         eve->head.data= block;
280                 }
281         }
282         else if (data == &bm->edata) {
283                 BMEdge *eed;
284
285                 BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
286                         block = NULL;
287                         CustomData_bmesh_set_default(data, &block);
288                         CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
289                         CustomData_bmesh_free_block(olddata, &eed->head.data);
290                         eed->head.data= block;
291                 }
292         }
293         else if (data == &bm->pdata || data == &bm->ldata) {
294                 BMIter liter;
295                 BMFace *efa;
296                 BMLoop *l;
297
298                 BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
299                         if (data == &bm->pdata) {
300                                 block = NULL;
301                                 CustomData_bmesh_set_default(data, &block);
302                                 CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
303                                 CustomData_bmesh_free_block(olddata, &efa->head.data);
304                                 efa->head.data= block;
305                         }
306
307                         if (data == &bm->ldata) {
308                                 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
309                                         block = NULL;
310                                         CustomData_bmesh_set_default(data, &block);
311                                         CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
312                                         CustomData_bmesh_free_block(olddata, &l->head.data);
313                                         l->head.data= block;
314                                 }
315                         }
316                 }
317         }
318 }
319
320
321 void BM_add_data_layer(BMesh *bm, CustomData *data, int type)
322 {
323         CustomData olddata;
324
325         olddata= *data;
326         olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
327         CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0);
328
329         update_data_blocks(bm, &olddata, data);
330         if (olddata.layers) MEM_freeN(olddata.layers);
331 }
332
333 void BM_add_data_layer_named(BMesh *bm, CustomData *data, int type, char *name)
334 {
335         CustomData olddata;
336
337         olddata= *data;
338         olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
339         CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name);
340
341         update_data_blocks(bm, &olddata, data);
342         if (olddata.layers) MEM_freeN(olddata.layers);
343 }
344
345 void BM_free_data_layer(BMesh *bm, CustomData *data, int type)
346 {
347         CustomData olddata;
348
349         olddata= *data;
350         olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
351         CustomData_free_layer_active(data, type, 0);
352
353         update_data_blocks(bm, &olddata, data);
354         if (olddata.layers) MEM_freeN(olddata.layers);
355 }
356
357 float BM_GetCDf(CustomData *cd, void *element, int type)
358 {
359         if (CustomData_has_layer(cd, type)) {
360                 float *f = CustomData_bmesh_get(cd, ((BMHeader*)element)->data, type);
361                 return *f;
362         }
363
364         return 0.0;
365 }
366
367 void BM_SetCDf(CustomData *cd, void *element, int type, float val)
368 {
369         if (CustomData_has_layer(cd, type)) {
370                 float *f = CustomData_bmesh_get(cd, ((BMHeader*)element)->data, type);
371                 *f = val;
372         }
373
374         return;
375 }