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