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