Deform with Curves didn't take the 'tilt' value into account.
[blender.git] / source / blender / blenkernel / intern / lattice.c
1 /**
2  * lattice.c
3  *
4  *
5  * $Id$
6  *
7  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version. The Blender
13  * Foundation also sells licenses for use in proprietary software under
14  * the Blender License.  See http://www.blender.org/BL/ for information
15  * about this.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
27  * All rights reserved.
28  *
29  * The Original Code is: all of this file.
30  *
31  * Contributor(s): none yet.
32  *
33  * ***** END GPL/BL DUAL LICENSE BLOCK *****
34  */
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <math.h>
39 #include <stdlib.h>
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_arithb.h"
45
46 #include "DNA_armature_types.h"
47 #include "DNA_mesh_types.h"
48 #include "DNA_meshdata_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_curve_types.h"
53 #include "DNA_key_types.h"
54 #include "DNA_ika_types.h"
55
56 #include "BKE_anim.h"
57 #include "BKE_armature.h"
58 #include "BKE_curve.h"
59 #include "BKE_deform.h"
60 #include "BKE_displist.h"
61 #include "BKE_global.h"
62 #include "BKE_ika.h"
63 #include "BKE_key.h"
64 #include "BKE_lattice.h"
65 #include "BKE_library.h"
66 #include "BKE_main.h"
67 #include "BKE_object.h"
68 #include "BKE_screen.h"
69 #include "BKE_utildefines.h"
70
71 #ifdef HAVE_CONFIG_H
72 #include <config.h>
73 #endif
74
75 #include "blendef.h"
76
77 Lattice *editLatt=0, *deformLatt=0;
78
79 float *latticedata=0, latmat[4][4];
80
81 void resizelattice(Lattice *lt)
82 {
83         BPoint *bp;
84         int u, v, w;
85         float vec[3], fu, fv, fw, du=0.0, dv=0.0, dw=0.0;
86         
87
88         MEM_freeN(lt->def);
89         lt->def= MEM_callocN(lt->pntsu*lt->pntsv*lt->pntsw*sizeof(BPoint), "lattice bp");
90         
91         bp= lt->def;
92         
93         while(lt->pntsu*lt->pntsv*lt->pntsw > 32000) {
94                 if( lt->pntsu>=lt->pntsv && lt->pntsu>=lt->pntsw) lt->pntsu--;
95                 else if( lt->pntsv>=lt->pntsu && lt->pntsv>=lt->pntsw) lt->pntsv--;
96                 else lt->pntsw--;
97         }
98         
99         calc_lat_fudu(lt->flag, lt->pntsu, &fu, &du);
100         calc_lat_fudu(lt->flag, lt->pntsv, &fv, &dv);
101         calc_lat_fudu(lt->flag, lt->pntsw, &fw, &dw);
102         
103         vec[2]= fw;
104         for(w=0; w<lt->pntsw; w++) {
105                 vec[1]= fv;
106                 for(v=0; v<lt->pntsv; v++) {
107                         vec[0]= fu;
108                         for(u=0; u<lt->pntsu; u++, bp++) {
109                                 VECCOPY(bp->vec, vec);
110                                 vec[0]+= du;
111                         }
112                         vec[1]+= dv;
113                 }
114                 vec[2]+= dw;
115         }
116 }
117
118 Lattice *add_lattice()
119 {
120         Lattice *lt;
121         
122         lt= alloc_libblock(&G.main->latt, ID_LT, "Lattice");
123         
124         lt->pntsu=lt->pntsv=lt->pntsw= 2;
125         lt->flag= LT_GRID;
126         
127         lt->typeu= lt->typev= lt->typew= KEY_BSPLINE;
128         
129         /* temporally */
130         lt->def= MEM_callocN(sizeof(BPoint), "lattvert");
131         
132         resizelattice(lt);      /* creates a uniform lattice */
133                 
134         return lt;
135 }
136
137 Lattice *copy_lattice(Lattice *lt)
138 {
139         Lattice *ltn;
140
141         ltn= copy_libblock(lt);
142         ltn->def= MEM_dupallocN(lt->def);
143                 
144         id_us_plus((ID *)ltn->ipo);
145
146         ltn->key= copy_key(ltn->key);
147         if(ltn->key) ltn->key->from= (ID *)ltn;
148         
149         return ltn;
150 }
151
152 void free_lattice(Lattice *lt)
153 {
154         if(lt->def) MEM_freeN(lt->def);
155 }
156
157
158 void make_local_lattice(Lattice *lt)
159 {
160         Object *ob;
161         Lattice *ltn;
162         int local=0, lib=0;
163
164         /* - only lib users: do nothing
165          * - only local users: set flag
166          * - mixed: make copy
167          */
168         
169         if(lt->id.lib==0) return;
170         if(lt->id.us==1) {
171                 lt->id.lib= 0;
172                 lt->id.flag= LIB_LOCAL;
173                 new_id(0, (ID *)lt, 0);
174                 return;
175         }
176         
177         ob= G.main->object.first;
178         while(ob) {
179                 if(ob->data==lt) {
180                         if(ob->id.lib) lib= 1;
181                         else local= 1;
182                 }
183                 ob= ob->id.next;
184         }
185         
186         if(local && lib==0) {
187                 lt->id.lib= 0;
188                 lt->id.flag= LIB_LOCAL;
189                 new_id(0, (ID *)lt, 0);
190         }
191         else if(local && lib) {
192                 ltn= copy_lattice(lt);
193                 ltn->id.us= 0;
194                 
195                 ob= G.main->object.first;
196                 while(ob) {
197                         if(ob->data==lt) {
198                                 
199                                 if(ob->id.lib==0) {
200                                         ob->data= ltn;
201                                         ltn->id.us++;
202                                         lt->id.us--;
203                                 }
204                         }
205                         ob= ob->id.next;
206                 }
207         }
208 }
209
210
211
212 void calc_lat_fudu(int flag, int res, float *fu, float *du)
213 {
214         
215         if(res==1) {
216                 *fu= 0.0;
217                 *du= 0.0;
218         }
219         else if(flag & LT_GRID) {
220                 *fu= -0.5f*(res-1);
221                 *du= 1.0f;
222         }
223         else {
224                 *fu= -1.0f;
225                 *du= 2.0f/(res-1);
226         }
227         
228 }
229
230 void init_latt_deform(Object *oblatt, Object *ob)
231 {
232         /* we make an array with all differences */
233         BPoint *bp;
234         float *fp, imat[4][4];
235         float vec[3], fu, fv, fw, du=0.0, dv=0.0, dw=0.0;
236         int u, v, w;
237         
238         if(oblatt==G.obedit) deformLatt= editLatt;
239         else deformLatt= oblatt->data;
240         
241         fp= latticedata= MEM_mallocN(sizeof(float)*3*deformLatt->pntsu*deformLatt->pntsv*deformLatt->pntsw, "latticedata");
242         
243         lattice_modifier(oblatt, 's');
244         bp= deformLatt->def;
245
246         //if(ob) where_is_object(ob); causes lag here, but why! (ton)
247
248         /* for example with a particle system: ob==0 */
249         if(ob==0) {
250                 /* in deformspace, calc matrix  */
251                 Mat4Invert(latmat, oblatt->obmat);
252         
253                 /* back: put in deform array */
254                 Mat4Invert(imat, latmat);
255         }
256         else {
257                 /* in deformspace, calc matrix */
258                 Mat4Invert(imat, oblatt->obmat);
259                 Mat4MulMat4(latmat, ob->obmat, imat);
260         
261                 /* back: put in deform array */
262                 Mat4Invert(imat, latmat);
263         }
264         calc_lat_fudu(deformLatt->flag, deformLatt->pntsu, &fu, &du);
265         calc_lat_fudu(deformLatt->flag, deformLatt->pntsv, &fv, &dv);
266         calc_lat_fudu(deformLatt->flag, deformLatt->pntsw, &fw, &dw);
267         
268         /* we keep calculating the u v w lattice coordinates, not enough reason to store that */
269         
270         vec[2]= fw;
271         for(w=0; w<deformLatt->pntsw; w++) {
272                 vec[1]= fv;
273                 for(v=0; v<deformLatt->pntsv; v++) {
274                         vec[0]= fu;
275                         for(u=0; u<deformLatt->pntsu; u++, bp++) {
276                                 
277                                 VecSubf(fp, bp->vec, vec);
278                                 Mat4Mul3Vecfl(imat, fp);
279                 
280                                 vec[0]+= du;
281                                 fp+= 3;
282                         }
283                         vec[1]+= dv;
284                 }
285                 vec[2]+= dw;
286         }
287
288         lattice_modifier(oblatt, 'e');
289
290 }
291
292 void calc_latt_deform(float *co)
293 {
294         Lattice *lt;
295         float fu, du, u, v, w, tu[4], tv[4], tw[4];
296         float *fpw, *fpv, *fpu, vec[3];
297         int ui, vi, wi, uu, vv, ww;
298         
299         if(latticedata==0) return;
300         
301         lt= deformLatt; /* just for shorter notation! */
302         
303         /* co is in local coords, treat with latmat */
304         
305         VECCOPY(vec, co);
306         Mat4MulVecfl(latmat, vec);
307         
308         /* u v w coords */
309         
310         if(lt->pntsu>1) {
311                 calc_lat_fudu(lt->flag, lt->pntsu, &fu, &du);
312                 u= (vec[0]-fu)/du;
313                 ui= (int)floor(u);
314                 u -= ui;
315                 set_four_ipo(u, tu, lt->typeu);
316         }
317         else {
318                 tu[0]= tu[2]= tu[3]= 0.0; tu[1]= 1.0;
319                 ui= 0;
320         }
321         
322         if(lt->pntsv>1) {
323                 calc_lat_fudu(lt->flag, lt->pntsv, &fu, &du);
324                 v= (vec[1]-fu)/du;
325                 vi= (int)floor(v);
326                 v -= vi;
327                 set_four_ipo(v, tv, lt->typev);
328         }
329         else {
330                 tv[0]= tv[2]= tv[3]= 0.0; tv[1]= 1.0;
331                 vi= 0;
332         }
333         
334         if(lt->pntsw>1) {
335                 calc_lat_fudu(lt->flag, lt->pntsw, &fu, &du);
336                 w= (vec[2]-fu)/du;
337                 wi= (int)floor(w);
338                 w -= wi;
339                 set_four_ipo(w, tw, lt->typew);
340         }
341         else {
342                 tw[0]= tw[2]= tw[3]= 0.0; tw[1]= 1.0;
343                 wi= 0;
344         }
345         
346         for(ww= wi-1; ww<=wi+2; ww++) {
347                 w= tw[ww-wi+1];
348                 
349                 if(w!=0.0) {
350                         if(ww>0) {
351                                 if(ww<lt->pntsw) fpw= latticedata + 3*ww*lt->pntsu*lt->pntsv;
352                                 else fpw= latticedata + 3*(lt->pntsw-1)*lt->pntsu*lt->pntsv;
353                         }
354                         else fpw= latticedata;
355                         
356                         for(vv= vi-1; vv<=vi+2; vv++) {
357                                 v= w*tv[vv-vi+1];
358                                 
359                                 if(v!=0.0) {
360                                         if(vv>0) {
361                                                 if(vv<lt->pntsv) fpv= fpw + 3*vv*lt->pntsu;
362                                                 else fpv= fpw + 3*(lt->pntsv-1)*lt->pntsu;
363                                         }
364                                         else fpv= fpw;
365                                         
366                                         for(uu= ui-1; uu<=ui+2; uu++) {
367                                                 u= v*tu[uu-ui+1];
368                                                 
369                                                 if(u!=0.0) {
370                                                         if(uu>0) {
371                                                                 if(uu<lt->pntsu) fpu= fpv + 3*uu;
372                                                                 else fpu= fpv + 3*(lt->pntsu-1);
373                                                         }
374                                                         else fpu= fpv;
375                                                         
376                                                         co[0]+= u*fpu[0];
377                                                         co[1]+= u*fpu[1];
378                                                         co[2]+= u*fpu[2];
379                                                 }
380                                         }
381                                 }
382                         }
383                 }
384         }
385 }
386
387 void end_latt_deform()
388 {
389
390         MEM_freeN(latticedata);
391         latticedata= 0;
392 }
393
394         /* calculations is in local space of deformed object
395            so we store in latmat transform from path coord inside object 
396          */
397 typedef struct {
398         float dmin[3], dmax[3], dsize, dloc[3];
399         float curvespace[4][4], objectspace[4][4];
400 } CurveDeform;
401
402 static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd)
403 {
404         Mat4Invert(ob->imat, ob->obmat);
405         Mat4MulMat4(cd->objectspace, par->obmat, ob->imat);
406         Mat4Invert(cd->curvespace, cd->objectspace);
407
408         // offset vector for 'no smear'
409         Mat4Invert(par->imat, par->obmat);
410         VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]);
411
412 }
413
414 /* this makes sure we can extend for non-cyclic. *vec needs 4 items! */
415 static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir)        /* returns OK */
416 {
417         Curve *cu= ob->data;
418         BevList *bl;
419         float ctime1;
420         int cycl=0;
421         
422         /* test for cyclic */
423         bl= cu->bev.first;
424         if(bl && bl->poly> -1) cycl= 1;
425
426         if(cycl==0) {
427                 ctime1= CLAMPIS(ctime, 0.0, 1.0);
428         }
429         else ctime1= ctime;
430         
431         /* vec needs 4 items */
432         if(where_on_path(ob, ctime1, vec, dir)) {
433                 
434                 if(cycl==0) {
435                         Path *path= cu->path;
436                         float dvec[3];
437                         
438                         if(ctime < 0.0) {
439                                 VecSubf(dvec, path->data+4, path->data);
440                                 VecMulf(dvec, ctime*(float)path->len);
441                                 VECADD(vec, vec, dvec);
442                         }
443                         else if(ctime > 1.0) {
444                                 VecSubf(dvec, path->data+4*path->len-4, path->data+4*path->len-8);
445                                 VecMulf(dvec, (ctime-1.0)*(float)path->len);
446                                 VECADD(vec, vec, dvec);
447                         }
448                 }
449                 return 1;
450         }
451         return 0;
452 }
453
454         /* for each point, rotate & translate to curve */
455         /* use path, since it has constant distances */
456         /* co: local coord, result local too */
457 static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd)
458 {
459         Curve *cu= par->data;
460         float fac, loc[4], dir[3], *quat, q[4], mat[3][3], cent[3];
461         short upflag, index;
462         
463         if(axis==OB_POSX || axis==OB_NEGX) {
464                 upflag= OB_POSZ;
465                 cent[0]= 0.0;
466                 cent[1]= co[1];
467                 cent[2]= co[2];
468                 index= 0;
469         }
470         else if(axis==OB_POSY || axis==OB_NEGY) {
471                 upflag= OB_POSZ;
472                 cent[0]= co[0];
473                 cent[1]= 0.0;
474                 cent[2]= co[2];
475                 index= 1;
476         }
477         else {
478                 upflag= OB_POSY;
479                 cent[0]= co[0];
480                 cent[1]= co[1];
481                 cent[2]= 0.0;
482                 index= 2;
483         }
484         /* to be sure */
485         if(cu->path==NULL) {
486                 calc_curvepath(par);
487                 if(cu->path==NULL) return;      // happens on append...
488         }
489         /* options */
490         if(cu->flag & CU_STRETCH)
491                 fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]);
492         else
493                 fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist);
494         
495         if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */
496
497                 quat= vectoquat(dir, axis, upflag);
498                 
499                 /* the tilt */
500                 if(loc[3]!=0.0) {
501                         Normalise(dir);
502                         q[0]= (float)cos(0.5*loc[3]);
503                         fac= (float)sin(0.5*loc[3]);
504                         q[1]= -fac*dir[0];
505                         q[2]= -fac*dir[1];
506                         q[3]= -fac*dir[2];
507                         QuatMul(quat, q, quat);
508                 }               
509                 QuatToMat3(quat, mat);
510         
511                 /* local rotation */
512                 Mat3MulVecfl(mat, cent);
513                 
514                 /* translation */
515                 VECADD(co, cent, loc);
516                 
517         }
518
519 }
520
521 /* Mesh now applies on mesh itself, others do displist */
522 static int _object_deform(Object *ob, int applyflag)
523 {
524         Mesh *me;
525         Curve *cu;
526         DispList *dl;
527         MVert *mvert;
528         float *fp;
529         int a, tot, flag;
530
531         if(ob->parent==NULL) return 0;
532         
533         /* always try to do the entire deform in this function: apply! */
534
535         if(ob->parent->type==OB_CURVE) {
536                 CurveDeform cd;
537                 
538                 if (ob->partype != PARSKEL){
539                         return 0;
540                 }
541                 cu= ob->parent->data;
542                 flag= cu->flag;
543                 cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist
544                 
545                 if(ob->type==OB_MESH) {
546                         
547                         me= ob->data;
548                         if(me->totvert==0) return 0;
549                         
550                         /* init deform */
551                         init_curve_deform(ob->parent, ob, &cd);
552                         
553                         /* transformation to curve space, and min max*/
554                         INIT_MINMAX(cd.dmin, cd.dmax);
555                         
556                         for(a=0, mvert=me->mvert; a<me->totvert; a++, mvert++) {
557                                 Mat4MulVecfl(cd.curvespace, mvert->co);
558                                 DO_MINMAX(mvert->co, cd.dmin, cd.dmax);
559                         }
560
561                         mvert= me->mvert;
562                         for(a=0; a<me->totvert; a++, mvert++) {
563                                 calc_curve_deform(ob->parent, mvert->co, ob->trackflag, &cd);
564                                 /* move coord back to objectspace */
565                                 Mat4MulVecfl(cd.objectspace, mvert->co);
566                         }
567                 }
568                 /* restore */
569                 cu->flag = flag;
570                 return 1;
571         }
572         else if(ob->parent->type==OB_LATTICE) {
573                 
574                 init_latt_deform(ob->parent, ob);
575                 
576                 if(ob->type==OB_MESH) {
577                         me= ob->data;
578                         
579                         mvert= me->mvert;
580                         for(a=0; a<me->totvert; a++, mvert++) {
581                                 calc_latt_deform(mvert->co);
582                         }
583                 }
584                 else if(ob->type==OB_MBALL) {
585                         dl=ob->disp.first;
586                         while(dl) {
587                                 fp = dl->verts;
588                                 for(a=0;a<dl->nr;a++,fp+=3)
589                                         calc_latt_deform(fp);
590                                 dl=dl->next;
591                         }
592                 }
593                 else if ELEM(ob->type, OB_CURVE, OB_SURF) {
594                 
595                         cu= ob->data;
596                         if(applyflag) {
597                                 Nurb *nu;
598                                 BPoint *bp;
599                                 BezTriple *bezt;
600                                 
601                                 nu= cu->nurb.first;
602                                 while(nu) {
603                                         if(nu->bp) {
604                                                 a= nu->pntsu*nu->pntsv;
605                                                 bp= nu->bp;
606                                                 while(a--) {
607                                                         calc_latt_deform(bp->vec);
608                                                         bp++;
609                                                 }
610                                         }
611                                         else if(nu->bezt) {
612                                                 a= nu->pntsu;
613                                                 bezt= nu->bezt;
614                                                 while(a--) {
615                                                         calc_latt_deform(bezt->vec[0]);
616                                                         calc_latt_deform(bezt->vec[1]);
617                                                         calc_latt_deform(bezt->vec[2]);
618                                                         bezt++;
619                                                 }
620                                                 test2DNurb(nu);
621                                         }
622                                         nu= nu->next;
623                                 }
624                         }
625                         else {
626                                 /* apply deform on displist */
627                                 dl= cu->disp.first;
628                                 while(dl) {
629                                         
630                                         fp= dl->verts;
631                                         
632                                         if(dl->type==DL_INDEX3) tot=dl->parts;
633                                         else tot= dl->nr*dl->parts;
634                                         
635                                         for(a=0; a<tot; a++, fp+=3) {
636                                                 calc_latt_deform(fp);
637                                         }
638                                         
639                                         dl= dl->next;
640                                 }
641                         }
642                 }
643                 end_latt_deform();
644                 return 1;
645         }
646         else if(ob->parent->type==OB_ARMATURE) {
647                 if (ob->partype != PARSKEL){
648                         return 0;
649                 }
650                 
651                 init_armature_deform (ob->parent, ob);
652
653                 switch (ob->type){
654                 case OB_MESH:
655                         me= ob->data;
656                         
657                         mvert= me->mvert;
658                         for(a=0; a<me->totvert; a++, mvert++) {
659                                 calc_armature_deform(ob->parent, mvert->co, a);
660                         }
661                         break;
662                 case OB_CURVE:
663                 case OB_SURF:
664                         break;
665                 }
666                 
667                 return 1;
668         }
669         
670         return 0;
671
672 }
673
674 int object_deform(Object *ob)
675 {
676         return _object_deform(ob, 0);
677 }
678
679
680 BPoint *latt_bp(Lattice *lt, int u, int v, int w)
681 {
682         return lt->def+ u + v*lt->pntsu + w*lt->pntsu*lt->pntsv;
683 }
684
685 void outside_lattice(Lattice *lt)
686 {
687         BPoint *bp, *bp1, *bp2;
688         int u, v, w;
689         float fac1, du=0.0, dv=0.0, dw=0.0;
690
691         bp= lt->def;
692
693         if(lt->pntsu>1) du= 1.0f/((float)lt->pntsu-1);
694         if(lt->pntsv>1) dv= 1.0f/((float)lt->pntsv-1);
695         if(lt->pntsw>1) dw= 1.0f/((float)lt->pntsw-1);
696                 
697         for(w=0; w<lt->pntsw; w++) {
698                 
699                 for(v=0; v<lt->pntsv; v++) {
700                 
701                         for(u=0; u<lt->pntsu; u++, bp++) {
702                                 if(u==0 || v==0 || w==0 || u==lt->pntsu-1 || v==lt->pntsv-1 || w==lt->pntsw-1);
703                                 else {
704                                 
705                                         bp->hide= 1;
706                                         bp->f1 &= ~SELECT;
707                                         
708                                         /* u extrema */
709                                         bp1= latt_bp(lt, 0, v, w);
710                                         bp2= latt_bp(lt, lt->pntsu-1, v, w);
711                                         
712                                         fac1= du*u;
713                                         bp->vec[0]= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0];
714                                         bp->vec[1]= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1];
715                                         bp->vec[2]= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2];
716                                         
717                                         /* v extrema */
718                                         bp1= latt_bp(lt, u, 0, w);
719                                         bp2= latt_bp(lt, u, lt->pntsv-1, w);
720                                         
721                                         fac1= dv*v;
722                                         bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0];
723                                         bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1];
724                                         bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2];
725                                         
726                                         /* w extrema */
727                                         bp1= latt_bp(lt, u, v, 0);
728                                         bp2= latt_bp(lt, u, v, lt->pntsw-1);
729                                         
730                                         fac1= dw*w;
731                                         bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0];
732                                         bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1];
733                                         bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2];
734                                         
735                                         VecMulf(bp->vec, 0.3333333f);
736                                         
737                                 }
738                         }
739                         
740                 }
741                 
742         }
743         
744 }