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