Subsurface scattering:
[blender.git] / source / blender / render / intern / source / envmap.c
1 /* 
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributors: 2004/2005/2006 Blender Foundation, full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <math.h>
29 #include <string.h>
30
31 /* external modules: */
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_arithb.h"
35 #include "BLI_blenlib.h"
36 #include "BLI_threads.h"
37
38 #include "IMB_imbuf_types.h"
39 #include "IMB_imbuf.h"        /* for rectcpy */
40
41 #include "DNA_group_types.h"
42 #include "DNA_image_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_texture_types.h"
46
47 #include "BKE_library.h"
48 #include "BKE_main.h"
49 #include "BKE_global.h"
50 #include "BKE_image.h"   // BKE_write_ibuf 
51 #include "BKE_texture.h"
52 #include "BKE_utildefines.h"
53
54 #include "MTC_matrixops.h"
55
56 /* this module */
57 #include "render_types.h"
58 #include "renderpipeline.h"
59 #include "envmap.h"
60 #include "rendercore.h" 
61 #include "renderdatabase.h" 
62 #include "texture.h"
63 #include "zbuf.h"
64 #include "initrender.h"
65
66
67 /* ------------------------------------------------------------------------- */
68
69 static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
70 {
71         int dx, part;
72         
73         BKE_free_envmapdata(env);       
74         
75         dx= ibuf->y;
76         dx/= 2;
77         if(3*dx != ibuf->x) {
78                 printf("Incorrect envmap size\n");
79                 env->ok= 0;
80                 env->ima->ok= 0;
81         }
82         else {
83                 for(part=0; part<6; part++) {
84                         env->cube[part]= IMB_allocImBuf(dx, dx, 24, IB_rect, 0);
85                 }
86                 IMB_rectcpy(env->cube[0], ibuf, 
87                         0, 0, 0, 0, dx, dx);
88                 IMB_rectcpy(env->cube[1], ibuf, 
89                         0, 0, dx, 0, dx, dx);
90                 IMB_rectcpy(env->cube[2], ibuf, 
91                         0, 0, 2*dx, 0, dx, dx);
92                 IMB_rectcpy(env->cube[3], ibuf, 
93                         0, 0, 0, dx, dx, dx);
94                 IMB_rectcpy(env->cube[4], ibuf, 
95                         0, 0, dx, dx, dx, dx);
96                 IMB_rectcpy(env->cube[5], ibuf, 
97                         0, 0, 2*dx, dx, dx, dx);
98                 env->ok= ENV_OSA;
99         }
100 }
101
102 /* ------------------------------------------------------------------------- */
103 /* ****************** RENDER ********************** */
104
105 /* copy current render */
106 static Render *envmap_render_copy(Render *re, EnvMap *env)
107 {
108         Render *envre;
109         int cuberes;
110         
111         envre= RE_NewRender("Envmap");
112         
113         env->lastsize= re->r.size;
114         cuberes = (env->cuberes * re->r.size) / 100;
115         cuberes &= 0xFFFC;
116         
117         /* this flag has R_ZTRA in it for example */
118         envre->flag= re->flag;
119         
120         /* set up renderdata */
121         envre->r= re->r;
122         envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
123         envre->r.layers.first= envre->r.layers.last= NULL;
124         envre->r.filtertype= 0;
125         envre->r.xparts= envre->r.yparts= 2;
126         envre->r.bufflag= 0;
127         envre->r.size= 100;
128         envre->r.yasp= envre->r.xasp= 1;
129         
130         RE_InitState(envre, &envre->r, cuberes, cuberes, NULL);
131         envre->scene= re->scene;        /* unsure about this... */
132
133         /* view stuff in env render */
134         envre->lens= 16.0f;
135         if(env->type==ENV_PLANE)
136                 envre->lens*= env->viewscale;
137         envre->ycor= 1.0f; 
138         envre->clipsta= env->clipsta;   /* render_scene_set_window() respects this for now */
139         envre->clipend= env->clipend;
140         
141         RE_SetCamera(envre, env->object);
142         
143         /* callbacks */
144         envre->display_draw= re->display_draw;
145         envre->test_break= re->test_break;
146         
147         /* and for the evil stuff; copy the database... */
148         envre->totvlak= re->totvlak;
149         envre->totvert= re->totvert;
150         envre->tothalo= re->tothalo;
151         envre->totlamp= re->totlamp;
152         envre->lights= re->lights;
153         envre->vertnodeslen= re->vertnodeslen;
154         envre->vertnodes= re->vertnodes;
155         envre->blohalen= re->blohalen;
156         envre->bloha= re->bloha;
157         envre->vlaknodeslen= re->vlaknodeslen;
158         envre->vlaknodes= re->vlaknodes;
159         envre->customdata_names= re->customdata_names;
160         envre->oc= re->oc;
161         
162         return envre;
163 }
164
165 static void envmap_free_render_copy(Render *envre)
166 {
167
168         envre->totvlak= 0;
169         envre->totvert= 0;
170         envre->tothalo= 0;
171         envre->totlamp= 0;
172         envre->lights.first= envre->lights.last= NULL;
173         envre->vertnodeslen= 0;
174         envre->vertnodes= NULL;
175         envre->blohalen= 0;
176         envre->bloha= NULL;
177         envre->vlaknodeslen= 0;
178         envre->vlaknodes= NULL;
179         envre->customdata_names.first= envre->customdata_names.last= NULL;
180         envre->oc.adrbranch= NULL;
181         envre->oc.adrnode= NULL;
182         
183         RE_FreeRender(envre);
184 }
185
186 /* ------------------------------------------------------------------------- */
187
188 static void envmap_transmatrix(float mat[][4], int part)
189 {
190         float tmat[4][4], eul[3], rotmat[4][4];
191         
192         eul[0]= eul[1]= eul[2]= 0.0;
193         
194         if(part==0) {                   /* neg z */
195                 ;
196         } else if(part==1) {    /* pos z */
197                 eul[0]= M_PI;
198         } else if(part==2) {    /* pos y */
199                 eul[0]= M_PI/2.0;
200         } else if(part==3) {    /* neg x */
201                 eul[0]= M_PI/2.0;
202                 eul[2]= M_PI/2.0;
203         } else if(part==4) {    /* neg y */
204                 eul[0]= M_PI/2.0;
205                 eul[2]= M_PI;
206         } else {                                /* pos x */
207                 eul[0]= M_PI/2.0;
208                 eul[2]= -M_PI/2.0;
209         }
210         
211         MTC_Mat4CpyMat4(tmat, mat);
212         EulToMat4(eul, rotmat);
213         MTC_Mat4MulSerie(mat, tmat, rotmat,
214                                          0,   0,    0,
215                                          0,   0,    0);
216 }
217
218 /* ------------------------------------------------------------------------- */
219
220 static void env_rotate_scene(Render *re, float mat[][4], int mode)
221 {
222         GroupObject *go;
223         VlakRen *vlr = NULL;
224         VertRen *ver = NULL;
225         LampRen *lar = NULL;
226         HaloRen *har = NULL;
227         float xn, yn, zn, imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3];
228         int a;
229         
230         if(mode==0) {
231                 MTC_Mat4Invert(tmat, mat);
232                 MTC_Mat3CpyMat4(imat, tmat);
233         }
234         else {
235                 MTC_Mat4CpyMat4(tmat, mat);
236                 MTC_Mat3CpyMat4(imat, mat);
237         }
238         
239         for(a=0; a<re->totvert; a++) {
240                 if((a & 255)==0) ver= RE_findOrAddVert(re, a);
241                 else ver++;
242                 
243                 MTC_Mat4MulVecfl(tmat, ver->co);
244                 
245                 xn= ver->n[0];
246                 yn= ver->n[1];
247                 zn= ver->n[2];
248                 /* no transpose ! */
249                 ver->n[0]= imat[0][0]*xn+imat[1][0]*yn+imat[2][0]*zn;
250                 ver->n[1]= imat[0][1]*xn+imat[1][1]*yn+imat[2][1]*zn;
251                 ver->n[2]= imat[0][2]*xn+imat[1][2]*yn+imat[2][2]*zn;
252                 Normalize(ver->n);
253         }
254         
255         for(a=0; a<re->tothalo; a++) {
256                 if((a & 255)==0) har= re->bloha[a>>8];
257                 else har++;
258         
259                 MTC_Mat4MulVecfl(tmat, har->co);
260         }
261                 
262         for(a=0; a<re->totvlak; a++) {
263                 if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
264                 else vlr++;
265                 
266                 xn= vlr->n[0];
267                 yn= vlr->n[1];
268                 zn= vlr->n[2];
269                 /* no transpose ! */
270                 vlr->n[0]= imat[0][0]*xn+imat[1][0]*yn+imat[2][0]*zn;
271                 vlr->n[1]= imat[0][1]*xn+imat[1][1]*yn+imat[2][1]*zn;
272                 vlr->n[2]= imat[0][2]*xn+imat[1][2]*yn+imat[2][2]*zn;
273                 Normalize(vlr->n);
274         }
275         
276         set_normalflags(re);
277         
278         for(go=re->lights.first; go; go= go->next) {
279                 lar= go->lampren;
280                 
281                 /* removed here some horrible code of someone in NaN who tried to fix
282                    prototypes... just solved by introducing a correct cmat[3][3] instead
283                    of using smat. this works, check square spots in reflections  (ton) */
284                 Mat3CpyMat3(cmat, lar->imat); 
285                 Mat3MulMat3(lar->imat, cmat, imat); 
286
287                 MTC_Mat3MulVecfl(imat, lar->vec);
288                 MTC_Mat4MulVecfl(tmat, lar->co);
289
290                 lar->sh_invcampos[0]= -lar->co[0];
291                 lar->sh_invcampos[1]= -lar->co[1];
292                 lar->sh_invcampos[2]= -lar->co[2];
293                 MTC_Mat3MulVecfl(lar->imat, lar->sh_invcampos);
294                 lar->sh_invcampos[2]*= lar->sh_zfac;
295                 
296                 if(lar->shb) {
297                         if(mode==1) {
298                                 MTC_Mat4Invert(pmat, mat);
299                                 MTC_Mat4MulMat4(smat, pmat, lar->shb->viewmat);
300                                 MTC_Mat4MulMat4(lar->shb->persmat, smat, lar->shb->winmat);
301                         }
302                         else MTC_Mat4MulMat4(lar->shb->persmat, lar->shb->viewmat, lar->shb->winmat);
303                 }
304         }
305         
306 }
307
308 /* ------------------------------------------------------------------------- */
309
310 static void env_layerflags(Render *re, unsigned int notlay)
311 {
312         VlakRen *vlr = NULL;
313         int a;
314         
315         /* invert notlay, so if face is in multiple layers it will still be visible,
316            unless all 'notlay' bits match the face bits.
317            face: 0110
318            not:  0100
319            ~not: 1011
320            now (face & ~not) is true
321         */
322         
323         notlay= ~notlay;
324         
325         for(a=0; a<re->totvlak; a++) {
326                 if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
327                 else vlr++;
328                 if((vlr->lay & notlay)==0)
329                         vlr->flag &= ~R_VISIBLE;
330         }
331 }
332
333 static void env_hideobject(Render *re, Object *ob)
334 {
335         VlakRen *vlr = NULL;
336         int a;
337         
338         for(a=0; a<re->totvlak; a++) {
339                 if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
340                 else vlr++;
341                 if(vlr->ob == ob) vlr->flag &= ~R_VISIBLE;
342         }
343 }
344
345 /* ------------------------------------------------------------------------- */
346
347 static void env_set_imats(Render *re)
348 {
349         Base *base;
350         float mat[4][4];
351         
352         base= G.scene->base.first;
353         while(base) {
354                 MTC_Mat4MulMat4(mat, base->object->obmat, re->viewmat);
355                 MTC_Mat4Invert(base->object->imat, mat);
356                 
357                 base= base->next;
358         }
359
360 }       
361
362 /* ------------------------------------------------------------------------- */
363
364 static void render_envmap(Render *re, EnvMap *env)
365 {
366         /* only the cubemap and planar map is implemented */
367         Render *envre;
368         ImBuf *ibuf;
369         float orthmat[4][4];
370         float oldviewinv[4][4], mat[4][4], tmat[4][4];
371         short part;
372         
373         /* need a recalc: ortho-render has no correct viewinv */
374         MTC_Mat4Invert(oldviewinv, re->viewmat);
375
376         envre= envmap_render_copy(re, env);
377         
378         /* precalc orthmat for object */
379         MTC_Mat4CpyMat4(orthmat, env->object->obmat);
380         MTC_Mat4Ortho(orthmat);
381         
382         /* need imat later for texture imat */
383         MTC_Mat4MulMat4(mat, orthmat, re->viewmat);
384         MTC_Mat4Invert(tmat, mat);
385         MTC_Mat3CpyMat4(env->obimat, tmat);
386
387         for(part=0; part<6; part++) {
388                 if(env->type==ENV_PLANE && part!=1)
389                         continue;
390                 
391                 re->display_clear(envre->result);
392                 
393                 MTC_Mat4CpyMat4(tmat, orthmat);
394                 envmap_transmatrix(tmat, part);
395                 MTC_Mat4Invert(mat, tmat);
396                 /* mat now is the camera 'viewmat' */
397
398                 MTC_Mat4CpyMat4(envre->viewmat, mat);
399                 MTC_Mat4CpyMat4(envre->viewinv, tmat);
400                 
401                 /* we have to correct for the already rotated vertexcoords */
402                 MTC_Mat4MulMat4(tmat, oldviewinv, envre->viewmat);
403                 MTC_Mat4Invert(env->imat, tmat);
404                 
405                 env_rotate_scene(envre, tmat, 1);
406                 init_render_world(envre);
407                 project_renderdata(envre, projectverto, 0, 0);
408                 env_layerflags(envre, env->notlay);
409                 env_hideobject(envre, env->object);
410                 env_set_imats(envre);
411                                 
412                 if(re->test_break()==0) {
413                         RE_TileProcessor(envre, 0, 0);
414                 }
415                 
416                 /* rotate back */
417                 env_rotate_scene(envre, tmat, 0);
418
419                 if(re->test_break()==0) {
420                         RenderLayer *rl= envre->result->layers.first;
421                         
422                         ibuf= IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect, 0);
423                         ibuf->rect_float= rl->rectf;
424                         IMB_rect_from_float(ibuf);
425                         ibuf->rect_float= NULL;
426                                 
427                         env->cube[part]= ibuf;
428                 }
429                 
430                 if(re->test_break()) break;
431
432         }
433         
434         if(re->test_break()) BKE_free_envmapdata(env);
435         else {
436                 if(envre->r.mode & R_OSA) env->ok= ENV_OSA;
437                 else env->ok= ENV_NORMAL;
438                 env->lastframe= G.scene->r.cfra;        /* hurmf */
439         }
440         
441         /* restore */
442         envmap_free_render_copy(envre);
443         env_set_imats(re);
444
445 }
446
447 /* ------------------------------------------------------------------------- */
448
449 void make_envmaps(Render *re)
450 {
451         Tex *tex;
452         int do_init= 0, depth= 0, trace;
453         
454         if (!(re->r.mode & R_ENVMAP)) return;
455         
456         /* we dont raytrace, disabling the flag will cause ray_transp render solid */
457         trace= (re->r.mode & R_RAYTRACE);
458         re->r.mode &= ~R_RAYTRACE;
459
460         re->i.infostr= "Creating Environment maps";
461         re->stats_draw(&re->i);
462         
463         /* 5 = hardcoded max recursion level */
464         while(depth<5) {
465                 tex= G.main->tex.first;
466                 while(tex) {
467                         if(tex->id.us && tex->type==TEX_ENVMAP) {
468                                 if(tex->env && tex->env->object) {
469                                         EnvMap *env= tex->env;
470                                         
471                                         if(env->object->lay & G.scene->lay) {
472                                                 if(env->stype==ENV_LOAD) {
473                                                         float orthmat[4][4], mat[4][4], tmat[4][4];
474                                                         
475                                                         /* precalc orthmat for object */
476                                                         MTC_Mat4CpyMat4(orthmat, env->object->obmat);
477                                                         MTC_Mat4Ortho(orthmat);
478                                                         
479                                                         /* need imat later for texture imat */
480                                                         MTC_Mat4MulMat4(mat, orthmat, re->viewmat);
481                                                         MTC_Mat4Invert(tmat, mat);
482                                                         MTC_Mat3CpyMat4(env->obimat, tmat);
483                                                 }
484                                                 else {
485                                                         
486                                                         /* decide if to render an envmap (again) */
487                                                         if(env->depth >= depth) {
488                                                                 
489                                                                 /* set 'recalc' to make sure it does an entire loop of recalcs */
490                                                                 
491                                                                 if(env->ok) {
492                                                                                 /* free when OSA, and old one isn't OSA */
493                                                                         if((re->r.mode & R_OSA) && env->ok==ENV_NORMAL) 
494                                                                                 BKE_free_envmapdata(env);
495                                                                                 /* free when size larger */
496                                                                         else if(env->lastsize < re->r.size) 
497                                                                                 BKE_free_envmapdata(env);
498                                                                                 /* free when env is in recalcmode */
499                                                                         else if(env->recalc)
500                                                                                 BKE_free_envmapdata(env);
501                                                                 }
502                                                                 
503                                                                 if(env->ok==0 && depth==0) env->recalc= 1;
504                                                                 
505                                                                 if(env->ok==0) {
506                                                                         do_init= 1;
507                                                                         render_envmap(re, env);
508                                                                         
509                                                                         if(depth==env->depth) env->recalc= 0;
510                                                                 }
511                                                         }
512                                                 }
513                                         }
514                                 }
515                         }
516                         tex= tex->id.next;
517                 }
518                 depth++;
519         }
520
521         if(do_init) {
522                 re->display_init(re->result);
523                 re->display_clear(re->result);
524                 // re->flag |= R_REDRAW_PRV;
525         }       
526         // restore
527         re->r.mode |= trace;
528
529 }
530
531 /* ------------------------------------------------------------------------- */
532
533 static int envcube_isect(EnvMap *env, float *vec, float *answ)
534 {
535         float labda;
536         int face;
537         
538         if(env->type==ENV_PLANE) {
539                 face= 1;
540                 
541                 labda= 1.0/vec[2];
542                 answ[0]= env->viewscale*labda*vec[0];
543                 answ[1]= -env->viewscale*labda*vec[1];
544         }
545         else {
546                 /* which face */
547                 if( vec[2]<=-fabs(vec[0]) && vec[2]<=-fabs(vec[1]) ) {
548                         face= 0;
549                         labda= -1.0/vec[2];
550                         answ[0]= labda*vec[0];
551                         answ[1]= labda*vec[1];
552                 }
553                 else if( vec[2]>=fabs(vec[0]) && vec[2]>=fabs(vec[1]) ) {
554                         face= 1;
555                         labda= 1.0/vec[2];
556                         answ[0]= labda*vec[0];
557                         answ[1]= -labda*vec[1];
558                 }
559                 else if( vec[1]>=fabs(vec[0]) ) {
560                         face= 2;
561                         labda= 1.0/vec[1];
562                         answ[0]= labda*vec[0];
563                         answ[1]= labda*vec[2];
564                 }
565                 else if( vec[0]<=-fabs(vec[1]) ) {
566                         face= 3;
567                         labda= -1.0/vec[0];
568                         answ[0]= labda*vec[1];
569                         answ[1]= labda*vec[2];
570                 }
571                 else if( vec[1]<=-fabs(vec[0]) ) {
572                         face= 4;
573                         labda= -1.0/vec[1];
574                         answ[0]= -labda*vec[0];
575                         answ[1]= labda*vec[2];
576                 }
577                 else {
578                         face= 5;
579                         labda= 1.0/vec[0];
580                         answ[0]= -labda*vec[1];
581                         answ[1]= labda*vec[2];
582                 }
583         }
584         
585         answ[0]= 0.5+0.5*answ[0];
586         answ[1]= 0.5+0.5*answ[1];
587         return face;
588 }
589
590 /* ------------------------------------------------------------------------- */
591
592 static void set_dxtdyt(float *dxts, float *dyts, float *dxt, float *dyt, int face)
593 {
594         if(face==2 || face==4) {
595                 dxts[0]= dxt[0];
596                 dyts[0]= dyt[0];
597                 dxts[1]= dxt[2];
598                 dyts[1]= dyt[2];
599         }
600         else if(face==3 || face==5) {
601                 dxts[0]= dxt[1];
602                 dxts[1]= dxt[2];
603                 dyts[0]= dyt[1];
604                 dyts[1]= dyt[2];
605         }
606         else {
607                 dxts[0]= dxt[0];
608                 dyts[0]= dyt[0];
609                 dxts[1]= dxt[1];
610                 dyts[1]= dyt[1];
611         }
612 }
613
614 /* ------------------------------------------------------------------------- */
615
616 int envmaptex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
617 {
618         extern Render R;                                /* only in this call */
619         /* texvec should be the already reflected normal */
620         EnvMap *env;
621         ImBuf *ibuf;
622         float fac, vec[3], sco[3], dxts[3], dyts[3];
623         int face, face1;
624         
625         env= tex->env;
626         if(env==NULL || (env->stype!=ENV_LOAD && env->object==NULL)) {
627                 texres->tin= 0.0;
628                 return 0;
629         }
630         if(env->stype==ENV_LOAD) {
631                 env->ima= tex->ima;
632                 if(env->ima && env->ima->ok) {
633                         if(env->cube[0]==NULL) {
634                                 ImBuf *ibuf= BKE_image_get_ibuf(env->ima, NULL);
635                                 if(ibuf)
636                                         envmap_split_ima(env, ibuf);
637                                 else
638                                         env->ok= 0;
639                         }
640                 }
641         }
642
643         if(env->ok==0) {
644                 
645                 texres->tin= 0.0;
646                 return 0;
647         }
648         
649         /* rotate to envmap space, if object is set */
650         VECCOPY(vec, texvec);
651         if(env->object) MTC_Mat3MulVecfl(env->obimat, vec);
652         else MTC_Mat4Mul3Vecfl(R.viewinv, vec);
653         
654         face= envcube_isect(env, vec, sco);
655         ibuf= env->cube[face];
656         
657         if(osatex) {
658                 if(env->object) {
659                         MTC_Mat3MulVecfl(env->obimat, dxt);
660                         MTC_Mat3MulVecfl(env->obimat, dyt);
661                 }
662                 else {
663                         MTC_Mat4Mul3Vecfl(R.viewinv, dxt);
664                         MTC_Mat4Mul3Vecfl(R.viewinv, dyt);
665                 }
666                 set_dxtdyt(dxts, dyts, dxt, dyt, face);
667                 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres);
668                 
669                 /* edges? */
670                 
671                 if(texres->ta<1.0) {
672                         TexResult texr1, texr2;
673         
674                         texr1.nor= texr2.nor= NULL;
675
676                         VecAddf(vec, vec, dxt);
677                         face1= envcube_isect(env, vec, sco);
678                         VecSubf(vec, vec, dxt);
679                         
680                         if(face!=face1) {
681                                 ibuf= env->cube[face1];
682                                 set_dxtdyt(dxts, dyts, dxt, dyt, face1);
683                                 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1);
684                         }
685                         else texr1.tr= texr1.tg= texr1.tb= texr1.ta= 0.0;
686                         
687                         /* here was the nasty bug! results were not zero-ed. FPE! */
688                         
689                         VecAddf(vec, vec, dyt);
690                         face1= envcube_isect(env, vec, sco);
691                         VecSubf(vec, vec, dyt);
692                         
693                         if(face!=face1) {
694                                 ibuf= env->cube[face1];
695                                 set_dxtdyt(dxts, dyts, dxt, dyt, face1);
696                                 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2);
697                         }
698                         else texr2.tr= texr2.tg= texr2.tb= texr2.ta= 0.0;
699                         
700                         fac= (texres->ta+texr1.ta+texr2.ta);
701                         if(fac!=0.0) {
702                                 fac= 1.0/fac;
703                                 
704                                 texres->tr= fac*(texres->ta*texres->tr + texr1.ta*texr1.tr + texr2.ta*texr2.tr );
705                                 texres->tg= fac*(texres->ta*texres->tg + texr1.ta*texr1.tg + texr2.ta*texr2.tg );
706                                 texres->tb= fac*(texres->ta*texres->tb + texr1.ta*texr1.tb + texr2.ta*texr2.tb );
707                         }
708                         texres->ta= 1.0;
709                 }
710         }
711         else {
712                 imagewrap(tex, NULL, ibuf, sco, texres);
713         }
714         
715         return 1;
716 }
717
718 /* ------------------------------------------------------------------------- */
719
720 /* eof */