Fix for #12526: still didn't get dupli transform in envmaps correct.
[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, NULL, &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->totstrand= re->totstrand;
152         envre->totlamp= re->totlamp;
153         envre->sortedhalos= re->sortedhalos;
154         envre->lights= re->lights;
155         envre->objecttable= re->objecttable;
156         envre->customdata_names= re->customdata_names;
157         envre->raytree= re->raytree;
158         envre->totinstance= re->totinstance;
159         envre->instancetable= re->instancetable;
160         envre->objectinstance= re->objectinstance;
161         envre->qmcsamplers= re->qmcsamplers;
162         
163         return envre;
164 }
165
166 static void envmap_free_render_copy(Render *envre)
167 {
168
169         envre->totvlak= 0;
170         envre->totvert= 0;
171         envre->tothalo= 0;
172         envre->totstrand= 0;
173         envre->totlamp= 0;
174         envre->totinstance= 0;
175         envre->sortedhalos= NULL;
176         envre->lights.first= envre->lights.last= NULL;
177         envre->objecttable.first= envre->objecttable.last= NULL;
178         envre->customdata_names.first= envre->customdata_names.last= NULL;
179         envre->raytree= NULL;
180         envre->instancetable.first= envre->instancetable.last= NULL;
181         envre->objectinstance= NULL;
182         envre->qmcsamplers= NULL;
183         
184         RE_FreeRender(envre);
185 }
186
187 /* ------------------------------------------------------------------------- */
188
189 static void envmap_transmatrix(float mat[][4], int part)
190 {
191         float tmat[4][4], eul[3], rotmat[4][4];
192         
193         eul[0]= eul[1]= eul[2]= 0.0;
194         
195         if(part==0) {                   /* neg z */
196                 ;
197         } else if(part==1) {    /* pos z */
198                 eul[0]= M_PI;
199         } else if(part==2) {    /* pos y */
200                 eul[0]= M_PI/2.0;
201         } else if(part==3) {    /* neg x */
202                 eul[0]= M_PI/2.0;
203                 eul[2]= M_PI/2.0;
204         } else if(part==4) {    /* neg y */
205                 eul[0]= M_PI/2.0;
206                 eul[2]= M_PI;
207         } else {                                /* pos x */
208                 eul[0]= M_PI/2.0;
209                 eul[2]= -M_PI/2.0;
210         }
211         
212         MTC_Mat4CpyMat4(tmat, mat);
213         EulToMat4(eul, rotmat);
214         MTC_Mat4MulSerie(mat, tmat, rotmat,
215                                          0,   0,    0,
216                                          0,   0,    0);
217 }
218
219 /* ------------------------------------------------------------------------- */
220
221 static void env_rotate_scene(Render *re, float mat[][4], int mode)
222 {
223         GroupObject *go;
224         ObjectRen *obr;
225         ObjectInstanceRen *obi;
226         LampRen *lar = NULL;
227         HaloRen *har = NULL;
228         float imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3], tmpmat[4][4];
229         int a;
230         
231         if(mode==0) {
232                 MTC_Mat4Invert(tmat, mat);
233                 MTC_Mat3CpyMat4(imat, tmat);
234         }
235         else {
236                 MTC_Mat4CpyMat4(tmat, mat);
237                 MTC_Mat3CpyMat4(imat, mat);
238         }
239
240         for(obi=re->instancetable.first; obi; obi=obi->next) {
241                 /* append or set matrix depending on dupli */
242                 if(obi->flag & R_DUPLI_TRANSFORMED) {
243                         Mat4CpyMat4(tmpmat, obi->mat);
244                         Mat4MulMat4(obi->mat, tmpmat, tmat);
245                 }
246                 else if(mode==1)
247                         Mat4CpyMat4(obi->mat, tmat);
248                 else
249                         Mat4One(obi->mat);
250
251                 Mat3CpyMat4(cmat, obi->mat);
252                 Mat3Inv(obi->nmat, cmat);
253                 Mat3Transp(obi->nmat);
254
255                 /* indicate the renderer has to use transform matrices */
256                 if(mode==0)
257                         obi->flag &= ~R_ENV_TRANSFORMED;
258                 else
259                         obi->flag |= R_ENV_TRANSFORMED;
260         }
261         
262
263         for(obr=re->objecttable.first; obr; obr=obr->next) {
264                 for(a=0; a<obr->tothalo; a++) {
265                         if((a & 255)==0) har= obr->bloha[a>>8];
266                         else har++;
267                 
268                         MTC_Mat4MulVecfl(tmat, har->co);
269                 }
270         }
271         
272         for(go=re->lights.first; go; go= go->next) {
273                 lar= go->lampren;
274                 
275                 /* removed here some horrible code of someone in NaN who tried to fix
276                    prototypes... just solved by introducing a correct cmat[3][3] instead
277                    of using smat. this works, check square spots in reflections  (ton) */
278                 Mat3CpyMat3(cmat, lar->imat); 
279                 Mat3MulMat3(lar->imat, cmat, imat); 
280
281                 MTC_Mat3MulVecfl(imat, lar->vec);
282                 MTC_Mat4MulVecfl(tmat, lar->co);
283
284                 lar->sh_invcampos[0]= -lar->co[0];
285                 lar->sh_invcampos[1]= -lar->co[1];
286                 lar->sh_invcampos[2]= -lar->co[2];
287                 MTC_Mat3MulVecfl(lar->imat, lar->sh_invcampos);
288                 lar->sh_invcampos[2]*= lar->sh_zfac;
289                 
290                 if(lar->shb) {
291                         if(mode==1) {
292                                 MTC_Mat4Invert(pmat, mat);
293                                 MTC_Mat4MulMat4(smat, pmat, lar->shb->viewmat);
294                                 MTC_Mat4MulMat4(lar->shb->persmat, smat, lar->shb->winmat);
295                         }
296                         else MTC_Mat4MulMat4(lar->shb->persmat, lar->shb->viewmat, lar->shb->winmat);
297                 }
298         }
299         
300 }
301
302 /* ------------------------------------------------------------------------- */
303
304 static void env_layerflags(Render *re, unsigned int notlay)
305 {
306         ObjectRen *obr;
307         VlakRen *vlr = NULL;
308         int a;
309         
310         /* invert notlay, so if face is in multiple layers it will still be visible,
311            unless all 'notlay' bits match the face bits.
312            face: 0110
313            not:  0100
314            ~not: 1011
315            now (face & ~not) is true
316         */
317         
318         notlay= ~notlay;
319         
320         for(obr=re->objecttable.first; obr; obr=obr->next) {
321                 if((obr->lay & notlay)==0) {
322                         for(a=0; a<obr->totvlak; a++) {
323                                 if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
324                                 else vlr++;
325
326                                 vlr->flag |= R_HIDDEN;
327                         }
328                 }
329         }
330 }
331
332 static void env_hideobject(Render *re, Object *ob)
333 {
334         ObjectRen *obr;
335         VlakRen *vlr = NULL;
336         int a;
337         
338         for(obr=re->objecttable.first; obr; obr=obr->next) {
339                 for(a=0; a<obr->totvlak; a++) {
340                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
341                         else vlr++;
342
343                         if(obr->ob == ob)
344                                 vlr->flag |= R_HIDDEN;
345                 }
346         }
347 }
348
349 static void env_showobjects(Render *re)
350 {
351         ObjectRen *obr;
352         VlakRen *vlr = NULL;
353         int a;
354         
355         for(obr=re->objecttable.first; obr; obr=obr->next) {
356                 for(a=0; a<obr->totvlak; a++) {
357                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak;
358                         else vlr++;
359
360                         vlr->flag &= ~R_HIDDEN;
361                 }
362         }
363 }
364
365 /* ------------------------------------------------------------------------- */
366
367 static void env_set_imats(Render *re)
368 {
369         Base *base;
370         float mat[4][4];
371         
372         base= G.scene->base.first;
373         while(base) {
374                 MTC_Mat4MulMat4(mat, base->object->obmat, re->viewmat);
375                 MTC_Mat4Invert(base->object->imat, mat);
376                 
377                 base= base->next;
378         }
379
380 }       
381
382 /* ------------------------------------------------------------------------- */
383
384 static void render_envmap(Render *re, EnvMap *env)
385 {
386         /* only the cubemap and planar map is implemented */
387         Render *envre;
388         ImBuf *ibuf;
389         float orthmat[4][4];
390         float oldviewinv[4][4], mat[4][4], tmat[4][4];
391         short part;
392         
393         /* need a recalc: ortho-render has no correct viewinv */
394         MTC_Mat4Invert(oldviewinv, re->viewmat);
395
396         envre= envmap_render_copy(re, env);
397         
398         /* precalc orthmat for object */
399         MTC_Mat4CpyMat4(orthmat, env->object->obmat);
400         MTC_Mat4Ortho(orthmat);
401         
402         /* need imat later for texture imat */
403         MTC_Mat4MulMat4(mat, orthmat, re->viewmat);
404         MTC_Mat4Invert(tmat, mat);
405         MTC_Mat3CpyMat4(env->obimat, tmat);
406
407         for(part=0; part<6; part++) {
408                 if(env->type==ENV_PLANE && part!=1)
409                         continue;
410                 
411                 re->display_clear(envre->result);
412                 
413                 MTC_Mat4CpyMat4(tmat, orthmat);
414                 envmap_transmatrix(tmat, part);
415                 MTC_Mat4Invert(mat, tmat);
416                 /* mat now is the camera 'viewmat' */
417
418                 MTC_Mat4CpyMat4(envre->viewmat, mat);
419                 MTC_Mat4CpyMat4(envre->viewinv, tmat);
420                 
421                 /* we have to correct for the already rotated vertexcoords */
422                 MTC_Mat4MulMat4(tmat, oldviewinv, envre->viewmat);
423                 MTC_Mat4Invert(env->imat, tmat);
424                 
425                 env_rotate_scene(envre, tmat, 1);
426                 init_render_world(envre);
427                 project_renderdata(envre, projectverto, 0, 0, 1);
428                 env_layerflags(envre, env->notlay);
429                 env_hideobject(envre, env->object);
430                 env_set_imats(envre);
431                                 
432                 if(re->test_break()==0) {
433                         RE_TileProcessor(envre, 0, 0);
434                 }
435                 
436                 /* rotate back */
437                 env_showobjects(envre);
438                 env_rotate_scene(envre, tmat, 0);
439
440                 if(re->test_break()==0) {
441                         RenderLayer *rl= envre->result->layers.first;
442                         
443                         ibuf= IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect, 0);
444                         ibuf->rect_float= rl->rectf;
445                         IMB_rect_from_float(ibuf);
446                         ibuf->rect_float= NULL;
447                                 
448                         env->cube[part]= ibuf;
449                 }
450                 
451                 if(re->test_break()) break;
452
453         }
454         
455         if(re->test_break()) BKE_free_envmapdata(env);
456         else {
457                 if(envre->r.mode & R_OSA) env->ok= ENV_OSA;
458                 else env->ok= ENV_NORMAL;
459                 env->lastframe= G.scene->r.cfra;        /* hurmf */
460         }
461         
462         /* restore */
463         envmap_free_render_copy(envre);
464         env_set_imats(re);
465
466 }
467
468 /* ------------------------------------------------------------------------- */
469
470 void make_envmaps(Render *re)
471 {
472         Tex *tex;
473         int do_init= 0, depth= 0, trace;
474         
475         if (!(re->r.mode & R_ENVMAP)) return;
476         
477         /* we dont raytrace, disabling the flag will cause ray_transp render solid */
478         trace= (re->r.mode & R_RAYTRACE);
479         re->r.mode &= ~R_RAYTRACE;
480
481         re->i.infostr= "Creating Environment maps";
482         re->stats_draw(&re->i);
483         
484         /* 5 = hardcoded max recursion level */
485         while(depth<5) {
486                 tex= G.main->tex.first;
487                 while(tex) {
488                         if(tex->id.us && tex->type==TEX_ENVMAP) {
489                                 if(tex->env && tex->env->object) {
490                                         EnvMap *env= tex->env;
491                                         
492                                         if(env->object->lay & G.scene->lay) {
493                                                 if(env->stype==ENV_LOAD) {
494                                                         float orthmat[4][4], mat[4][4], tmat[4][4];
495                                                         
496                                                         /* precalc orthmat for object */
497                                                         MTC_Mat4CpyMat4(orthmat, env->object->obmat);
498                                                         MTC_Mat4Ortho(orthmat);
499                                                         
500                                                         /* need imat later for texture imat */
501                                                         MTC_Mat4MulMat4(mat, orthmat, re->viewmat);
502                                                         MTC_Mat4Invert(tmat, mat);
503                                                         MTC_Mat3CpyMat4(env->obimat, tmat);
504                                                 }
505                                                 else {
506                                                         
507                                                         /* decide if to render an envmap (again) */
508                                                         if(env->depth >= depth) {
509                                                                 
510                                                                 /* set 'recalc' to make sure it does an entire loop of recalcs */
511                                                                 
512                                                                 if(env->ok) {
513                                                                                 /* free when OSA, and old one isn't OSA */
514                                                                         if((re->r.mode & R_OSA) && env->ok==ENV_NORMAL) 
515                                                                                 BKE_free_envmapdata(env);
516                                                                                 /* free when size larger */
517                                                                         else if(env->lastsize < re->r.size) 
518                                                                                 BKE_free_envmapdata(env);
519                                                                                 /* free when env is in recalcmode */
520                                                                         else if(env->recalc)
521                                                                                 BKE_free_envmapdata(env);
522                                                                 }
523                                                                 
524                                                                 if(env->ok==0 && depth==0) env->recalc= 1;
525                                                                 
526                                                                 if(env->ok==0) {
527                                                                         do_init= 1;
528                                                                         render_envmap(re, env);
529                                                                         
530                                                                         if(depth==env->depth) env->recalc= 0;
531                                                                 }
532                                                         }
533                                                 }
534                                         }
535                                 }
536                         }
537                         tex= tex->id.next;
538                 }
539                 depth++;
540         }
541
542         if(do_init) {
543                 re->display_init(re->result);
544                 re->display_clear(re->result);
545                 // re->flag |= R_REDRAW_PRV;
546         }       
547         // restore
548         re->r.mode |= trace;
549
550 }
551
552 /* ------------------------------------------------------------------------- */
553
554 static int envcube_isect(EnvMap *env, float *vec, float *answ)
555 {
556         float labda;
557         int face;
558         
559         if(env->type==ENV_PLANE) {
560                 face= 1;
561                 
562                 labda= 1.0/vec[2];
563                 answ[0]= env->viewscale*labda*vec[0];
564                 answ[1]= -env->viewscale*labda*vec[1];
565         }
566         else {
567                 /* which face */
568                 if( vec[2]<=-fabs(vec[0]) && vec[2]<=-fabs(vec[1]) ) {
569                         face= 0;
570                         labda= -1.0/vec[2];
571                         answ[0]= labda*vec[0];
572                         answ[1]= labda*vec[1];
573                 }
574                 else if( vec[2]>=fabs(vec[0]) && vec[2]>=fabs(vec[1]) ) {
575                         face= 1;
576                         labda= 1.0/vec[2];
577                         answ[0]= labda*vec[0];
578                         answ[1]= -labda*vec[1];
579                 }
580                 else if( vec[1]>=fabs(vec[0]) ) {
581                         face= 2;
582                         labda= 1.0/vec[1];
583                         answ[0]= labda*vec[0];
584                         answ[1]= labda*vec[2];
585                 }
586                 else if( vec[0]<=-fabs(vec[1]) ) {
587                         face= 3;
588                         labda= -1.0/vec[0];
589                         answ[0]= labda*vec[1];
590                         answ[1]= labda*vec[2];
591                 }
592                 else if( vec[1]<=-fabs(vec[0]) ) {
593                         face= 4;
594                         labda= -1.0/vec[1];
595                         answ[0]= -labda*vec[0];
596                         answ[1]= labda*vec[2];
597                 }
598                 else {
599                         face= 5;
600                         labda= 1.0/vec[0];
601                         answ[0]= -labda*vec[1];
602                         answ[1]= labda*vec[2];
603                 }
604         }
605         
606         answ[0]= 0.5+0.5*answ[0];
607         answ[1]= 0.5+0.5*answ[1];
608         return face;
609 }
610
611 /* ------------------------------------------------------------------------- */
612
613 static void set_dxtdyt(float *dxts, float *dyts, float *dxt, float *dyt, int face)
614 {
615         if(face==2 || face==4) {
616                 dxts[0]= dxt[0];
617                 dyts[0]= dyt[0];
618                 dxts[1]= dxt[2];
619                 dyts[1]= dyt[2];
620         }
621         else if(face==3 || face==5) {
622                 dxts[0]= dxt[1];
623                 dxts[1]= dxt[2];
624                 dyts[0]= dyt[1];
625                 dyts[1]= dyt[2];
626         }
627         else {
628                 dxts[0]= dxt[0];
629                 dyts[0]= dyt[0];
630                 dxts[1]= dxt[1];
631                 dyts[1]= dyt[1];
632         }
633 }
634
635 /* ------------------------------------------------------------------------- */
636
637 int envmaptex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
638 {
639         extern Render R;                                /* only in this call */
640         /* texvec should be the already reflected normal */
641         EnvMap *env;
642         ImBuf *ibuf;
643         float fac, vec[3], sco[3], dxts[3], dyts[3], w[3];
644         int face, face1;
645         
646         env= tex->env;
647         if(env==NULL || (env->stype!=ENV_LOAD && env->object==NULL)) {
648                 texres->tin= 0.0;
649                 return 0;
650         }
651         if(env->stype==ENV_LOAD) {
652                 env->ima= tex->ima;
653                 if(env->ima && env->ima->ok) {
654                         if(env->cube[0]==NULL) {
655                                 ImBuf *ibuf= BKE_image_get_ibuf(env->ima, NULL);
656                                 if(ibuf)
657                                         envmap_split_ima(env, ibuf);
658                                 else
659                                         env->ok= 0;
660                         }
661                 }
662         }
663
664         if(env->ok==0) {
665                 
666                 texres->tin= 0.0;
667                 return 0;
668         }
669         
670         /* rotate to envmap space, if object is set */
671         VECCOPY(vec, texvec);
672         if(env->object) MTC_Mat3MulVecfl(env->obimat, vec);
673         else MTC_Mat4Mul3Vecfl(R.viewinv, vec);
674         
675         face= envcube_isect(env, vec, sco);
676         ibuf= env->cube[face];
677         
678         if(osatex) {
679                 if(env->object) {
680                         MTC_Mat3MulVecfl(env->obimat, dxt);
681                         MTC_Mat3MulVecfl(env->obimat, dyt);
682                 }
683                 else {
684                         MTC_Mat4Mul3Vecfl(R.viewinv, dxt);
685                         MTC_Mat4Mul3Vecfl(R.viewinv, dyt);
686                 }
687                 set_dxtdyt(dxts, dyts, dxt, dyt, face);
688                 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres);
689                 
690                 /* edges? */
691                 
692                 if(texres->ta<1.0) {
693                         TexResult texr1, texr2;
694         
695                         texr1.nor= texr2.nor= NULL;
696
697                         VecAddf(vec, vec, dxt);
698                         face1= envcube_isect(env, vec, sco);
699                         VecSubf(vec, vec, dxt);
700                         
701                         if(face!=face1) {
702                                 ibuf= env->cube[face1];
703                                 set_dxtdyt(dxts, dyts, dxt, dyt, face1);
704                                 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1);
705                         }
706                         else texr1.tr= texr1.tg= texr1.tb= texr1.ta= 0.0;
707                         
708                         /* here was the nasty bug! results were not zero-ed. FPE! */
709                         
710                         VecAddf(vec, vec, dyt);
711                         face1= envcube_isect(env, vec, sco);
712                         VecSubf(vec, vec, dyt);
713                         
714                         if(face!=face1) {
715                                 ibuf= env->cube[face1];
716                                 set_dxtdyt(dxts, dyts, dxt, dyt, face1);
717                                 imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2);
718                         }
719                         else texr2.tr= texr2.tg= texr2.tb= texr2.ta= 0.0;
720                         
721                         fac= (texres->ta+texr1.ta+texr2.ta);
722                         if(fac!=0.0) {
723                                 fac= 1.0/fac;
724
725                                 /* weight contributions based on alpha */
726                                 w[0]= texres->ta*fac;
727                                 w[1]= texr1.ta*fac;
728                                 w[2]= texr2.ta*fac;
729                                 
730                                 /* interpolate premultiplied result (imagewraposa returns key) */
731                                 texres->tr= (w[0]*texres->ta*texres->tr + w[1]*texr1.ta*texr1.tr + w[2]*texr2.ta*texr2.tr);
732                                 texres->tg= (w[0]*texres->ta*texres->tg + w[1]*texr1.ta*texr1.tg + w[2]*texr2.ta*texr2.tg);
733                                 texres->tb= (w[0]*texres->ta*texres->tb + w[1]*texr1.ta*texr1.tb + w[2]*texr2.ta*texr2.tb);
734                         }
735                         texres->ta= 1.0;
736                 }
737         }
738         else {
739                 imagewrap(tex, NULL, ibuf, sco, texres);
740         }
741         
742         return 1;
743 }
744
745 /* ------------------------------------------------------------------------- */
746
747 /* eof */