Orange branch: Revived hidden treasure, the Groups!
[blender.git] / source / blender / render / intern / source / pixelshading.c
1 /**
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  * Shading of pixels
31  *
32  * 11-09-2000 nzc
33  *
34  * $Id$
35  *
36  */
37
38 #include <math.h>
39 #include "BLI_arithb.h"
40
41 /* External modules: */
42 #include "IMB_imbuf_types.h"
43 #include "IMB_imbuf.h"
44 #include "MTC_matrixops.h"
45 #include "MTC_vectorops.h"
46
47 #include "DNA_camera_types.h"
48 #include "DNA_group_types.h"
49 #include "DNA_material_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_image_types.h"
52 #include "DNA_texture_types.h"
53 #include "DNA_lamp_types.h"
54
55 #include "BKE_image.h"
56 #include "BKE_global.h"
57 #include "BKE_texture.h"
58 #include "BKE_utildefines.h"
59
60 #include "render.h"
61 #include "texture.h"
62
63 #include "vanillaRenderPipe_types.h"
64 #include "pixelblending.h"
65 #include "rendercore.h" /* for some shading functions... */
66 #include "shadbuf.h"
67 #include "zbufferdatastruct.h"
68
69 #include "renderHelp.h"
70
71 #include "gammaCorrectionTables.h"
72 #include "errorHandler.h"
73 #include "pixelshading.h"
74
75
76 /* ton: 
77   - unified render now uses face render routines from rendercore.c
78   - todo still: shalo render and sky routines */
79
80
81 /* ------------------------------------------------------------------------- */
82 static int calcHaloZ(HaloRen *har, int zz)
83 {
84         
85         if(har->type & HA_ONLYSKY) {
86                 if(zz!=0x7FFFFFFF) zz= - 0x7FFFFF;
87         }
88         else {
89                 zz= (zz>>8);
90         }
91         return zz;
92 }
93
94 static void *renderHaloPixel(RE_COLBUFTYPE *collector, float x, float y, int haloNr) 
95 {
96     HaloRen *har = NULL;
97     float dist = 0.0;
98     int zz = 0;
99         
100     /* Find har to go with haloNr */
101     har = RE_findOrAddHalo(haloNr);
102         
103     /* zz is a strange number... This call should effect that halo's are  */
104     /* never cut? Seems a bit strange to me now...   (nzc)                */
105         /* it checks for sky... which is info not available in unified (ton) */
106     zz = calcHaloZ(har, 0x7FFFFFFF);
107         if(zz> har->zs) {
108         
109                 /* distance of this point wrt. the halo center. Maybe xcor is also needed? */
110                 dist = ((x - har->xs) * (x - har->xs)) 
111                         +  ((y - har->ys) * (y - har->ys) * R.ycor * R.ycor) ;
112                 
113                 collector[0] = 0.0f; collector[1] = 0.0f; 
114                 collector[2] = 0.0f; collector[3] = 0.0f;
115                 
116                 if (dist < har->radsq) {
117                         shadeHaloFloat(har, collector, zz, dist, 
118                                                    (x - har->xs), (y - har->ys) * R.ycor, har->flarec);
119                 }; /* else: this pixel is not rendered for this halo: no colour */
120         }
121     return (void*) har;
122
123 } /* end of void* renderHaloPixel(float x, float y, int haloNr) */
124
125
126
127 /* ------------------------------------------------------------------------- */
128
129 void *renderPixel(RE_COLBUFTYPE *collector, float x, float y, int *obdata, int mask)
130 {
131     void *data = NULL;
132         float rco[3];   /* not used (yet?) */
133     
134     if (obdata[3] & RE_POLY) {
135                 data = shadepixel(x, y, obdata[0], obdata[1], mask, collector, rco);
136     }
137     else if (obdata[3] & RE_HALO) {
138         data = renderHaloPixel(collector, x, y, obdata[1]);
139     }
140         else if( obdata[1] == 0 ) {     
141                 /* for lamphalo, but doesn't seem to be called? Actually it is, and  */
142                 /* it returns NULL pointers. */
143         data = shadepixel(x, y, obdata[0], obdata[1], mask, collector, rco);
144         }
145     return data;
146    
147 } /* end of void renderPixel(float x, float y, int *obdata) */
148
149 /* ------------------------------------------------------------------------- */
150
151 void renderSpotHaloPixel(float x, float y, float* fcol)
152 {
153         float rco[3];   /* unused */
154         shadepixel(x, y, 0, 0, 0, fcol, rco);
155 }
156
157
158 /* ------------------------------------------------------------------------- */
159
160 extern float hashvectf[];
161
162 static void render_lighting_halo(HaloRen *har, float *colf)
163 {
164         GroupObject *go;
165         LampRen *lar;
166         float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
167         float ir, ig, ib, shadfac, soft, lacol[3];
168         
169         ir= ig= ib= 0.0;
170         
171         VECCOPY(rco, har->co);  
172         dco[0]=dco[1]=dco[2]= 1.0/har->rad;
173         
174         vn= har->no;
175         
176         for(go=R.lights.first; go; go= go->next) {
177                 lar= go->lampren;
178                 
179                 /* test for lamplayer */
180                 if(lar->mode & LA_LAYER) if((lar->lay & har->lay)==0) continue;
181                 
182                 /* lampdist cacluation */
183                 if(lar->type==LA_SUN || lar->type==LA_HEMI) {
184                         VECCOPY(lv, lar->vec);
185                         lampdist= 1.0;
186                 }
187                 else {
188                         lv[0]= rco[0]-lar->co[0];
189                         lv[1]= rco[1]-lar->co[1];
190                         lv[2]= rco[2]-lar->co[2];
191                         ld= sqrt(lv[0]*lv[0]+lv[1]*lv[1]+lv[2]*lv[2]);
192                         lv[0]/= ld;
193                         lv[1]/= ld;
194                         lv[2]/= ld;
195                         
196                         /* ld is re-used further on (texco's) */
197                         
198                         if(lar->mode & LA_QUAD) {
199                                 t= 1.0;
200                                 if(lar->ld1>0.0)
201                                         t= lar->dist/(lar->dist+lar->ld1*ld);
202                                 if(lar->ld2>0.0)
203                                         t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
204                                 
205                                 lampdist= t;
206                         }
207                         else {
208                                 lampdist= (lar->dist/(lar->dist+ld));
209                         }
210                         
211                         if(lar->mode & LA_SPHERE) {
212                                 t= lar->dist - ld;
213                                 if(t<0.0) continue;
214                                 
215                                 t/= lar->dist;
216                                 lampdist*= (t);
217                         }
218                         
219                 }
220                 
221                 lacol[0]= lar->r;
222                 lacol[1]= lar->g;
223                 lacol[2]= lar->b;
224                 
225                 if(lar->mode & LA_TEXTURE) {
226                         ShadeInput shi;
227                         VECCOPY(shi.co, rco);
228                         shi.osatex= 0;
229                         do_lamp_tex(lar, lv, &shi, lacol);
230                 }
231                 
232                 if(lar->type==LA_SPOT) {
233                         
234                         if(lar->mode & LA_SQUARE) {
235                                 if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) {
236                                         float x, lvrot[3];
237                                         
238                                         /* rotate view to lampspace */
239                                         VECCOPY(lvrot, lv);
240                                         MTC_Mat3MulVecfl(lar->imat, lvrot);
241                                         
242                                         x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
243                                         /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
244                                         
245                                         inpr= 1.0/(sqrt(1.0+x*x));
246                                 }
247                                 else inpr= 0.0;
248                         }
249                         else {
250                                 inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
251                         }
252                         
253                         t= lar->spotsi;
254                         if(inpr<t) continue;
255                         else {
256                                 t= inpr-t;
257                                 i= 1.0;
258                                 soft= 1.0;
259                                 if(t<lar->spotbl && lar->spotbl!=0.0) {
260                                         /* soft area */
261                                         i= t/lar->spotbl;
262                                         t= i*i;
263                                         soft= (3.0*t-2.0*t*i);
264                                         inpr*= soft;
265                                 }
266                                 if(lar->mode & LA_ONLYSHADOW) {
267                                         /* if(ma->mode & MA_SHADOW) { */
268                                         /* dot product positive: front side face! */
269                                         inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
270                                         if(inp>0.0) {
271                                                 /* testshadowbuf==0.0 : 100% shadow */
272                                                 shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
273                                                 if( shadfac>0.0 ) {
274                                                         shadfac*= inp*soft*lar->energy;
275                                                         ir -= shadfac;
276                                                         ig -= shadfac;
277                                                         ib -= shadfac;
278                                                         
279                                                         continue;
280                                                 }
281                                         }
282                                         /* } */
283                                 }
284                                 lampdist*=inpr;
285                         }
286                         if(lar->mode & LA_ONLYSHADOW) continue;
287                         
288                 }
289                 
290                 /* dot product and  reflectivity*/
291                 
292                 inp= 1.0-fabs(vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]);
293                 
294                 /* inp= cos(0.5*M_PI-acos(inp)); */
295                 
296                 i= inp;
297                 
298                 if(lar->type==LA_HEMI) {
299                         i= 0.5*i+0.5;
300                 }
301                 if(i>0.0) {
302                         i*= lampdist;
303                 }
304                 
305                 /* shadow  */
306                 if(i> -0.41) {                  /* heuristic valua! */
307                         shadfac= 1.0;
308                         if(lar->shb) {
309                                 shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
310                                 if(shadfac==0.0) continue;
311                                 i*= shadfac;
312                         }
313                 }
314                 
315                 if(i>0.0) {
316                         ir+= i*lacol[0];
317                         ig+= i*lacol[1];
318                         ib+= i*lacol[2];
319                 }
320         }
321         
322         if(ir<0.0) ir= 0.0;
323         if(ig<0.0) ig= 0.0;
324         if(ib<0.0) ib= 0.0;
325
326         colf[0]*= ir;
327         colf[1]*= ig;
328         colf[2]*= ib;
329         
330 }
331
332
333
334 void shadeHaloFloat(HaloRen *har,  float *col, int zz, 
335                                         float dist, float xn,  float yn, short flarec)
336 {
337         /* fill in col */
338         float t, zn, radist, ringf=0.0, linef=0.0, alpha, si, co;
339         int a;
340    
341         if(R.wrld.mode & WO_MIST) {
342        if(har->type & HA_ONLYSKY) {
343            /* stars but no mist */
344            alpha= har->alfa;
345        }
346        else {
347            /* a bit patchy... */
348            alpha= mistfactor(-har->co[2], har->co)*har->alfa;
349        }
350         }
351         else alpha= har->alfa;
352         
353         if(alpha==0.0) {
354                 col[0] = 0.0;
355                 col[1] = 0.0;
356                 col[2] = 0.0;
357                 col[3] = 0.0;
358                 return;
359         }
360
361         radist= sqrt(dist);
362
363         /* watch it: not used nicely: flarec is set at zero in pixstruct */
364         if(flarec) har->pixels+= (int)(har->rad-radist);
365
366         if(har->ringc) {
367                 float *rc, fac;
368                 int ofs;
369                 
370                 /* per ring an antialised circle */
371                 ofs= har->seed;
372                 
373                 for(a= har->ringc; a>0; a--, ofs+=2) {
374                         
375                         rc= hashvectf + (ofs % 768);
376                         
377                         fac= fabs( rc[1]*(har->rad*fabs(rc[0]) - radist) );
378                         
379                         if(fac< 1.0) {
380                                 ringf+= (1.0-fac);
381                         }
382                 }
383         }
384
385         if(har->type & HA_VECT) {
386                 dist= fabs( har->cos*(yn) - har->sin*(xn) )/har->rad;
387                 if(dist>1.0) dist= 1.0;
388                 if(har->tex) {
389                         zn= har->sin*xn - har->cos*yn;
390                         yn= har->cos*xn + har->sin*yn;
391                         xn= zn;
392                 }
393         }
394         else dist= dist/har->radsq;
395
396         if(har->type & HA_FLARECIRC) {
397                 
398                 dist= 0.5+fabs(dist-0.5);
399                 
400         }
401
402         if(har->hard>=30) {
403                 dist= sqrt(dist);
404                 if(har->hard>=40) {
405                         dist= sin(dist*M_PI_2);
406                         if(har->hard>=50) {
407                                 dist= sqrt(dist);
408                         }
409                 }
410         }
411         else if(har->hard<20) dist*=dist;
412
413         dist=(1.0-dist);
414         
415         if(har->linec) {
416                 float *rc, fac;
417                 int ofs;
418                 
419                 /* per starpoint an antialiased line */
420                 ofs= har->seed;
421                 
422                 for(a= har->linec; a>0; a--, ofs+=3) {
423                         
424                         rc= hashvectf + (ofs % 768);
425                         
426                         fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
427                         
428                         if(fac< 1.0 ) {
429                                 linef+= (1.0-fac);
430                         }
431                 }
432                 
433                 linef*= dist;
434                 
435         }
436
437         if(har->starpoints) {
438                 float ster, hoek;
439                 /* rotation */
440                 hoek= atan2(yn, xn);
441                 hoek*= (1.0+0.25*har->starpoints);
442                 
443                 co= cos(hoek);
444                 si= sin(hoek);
445                 
446                 hoek= (co*xn+si*yn)*(co*yn-si*xn);
447                 
448                 ster= fabs(hoek);
449                 if(ster>1.0) {
450                         ster= (har->rad)/(ster);
451                         
452                         if(ster<1.0) dist*= sqrt(ster);
453                 }
454         }
455         
456         /* halo being intersected? */
457         if(har->zs> zz-har->zd) {
458                 t= ((float)(zz-har->zs))/(float)har->zd;
459                 alpha*= sqrt(sqrt(t));
460         }
461
462         dist*= alpha;
463         ringf*= dist;
464         linef*= alpha;
465         
466         if(dist<0.003) {
467                 col[0] = 0.0;
468                 col[1] = 0.0;
469                 col[2] = 0.0;
470                 col[3] = 0.0;
471                 return;
472         }
473
474         /* The colour is either the rgb spec-ed by the user, or extracted from   */
475         /* the texture                                                           */
476         if(har->tex) {
477                 col[0]= har->r; 
478                 col[1]= har->g; 
479                 col[2]= har->b;
480                 col[3]= dist;
481                 
482                 do_halo_tex(har, xn, yn, col);
483                 
484                 col[0]*= col[3];
485                 col[1]*= col[3];
486                 col[2]*= col[3];
487                 
488         }
489         else {
490                 col[0]= dist*har->r;
491                 col[1]= dist*har->g;
492                 col[2]= dist*har->b;
493                 if(har->type & HA_XALPHA) col[3]= dist*dist;
494                 else col[3]= dist;
495         }
496
497         if(har->mat) {
498                 if(har->mat->mode & MA_HALO_SHADE) {
499                         /* we test for lights because of preview... */
500                         if(R.lights.first) render_lighting_halo(har, col);
501                 }
502
503                 /* Next, we do the line and ring factor modifications. */
504                 if(linef!=0.0) {
505                         Material *ma= har->mat;
506                         
507                         col[0]+= linef * ma->specr;
508                         col[1]+= linef * ma->specg;
509                         col[2]+= linef * ma->specb;
510                         
511                         if(har->type & HA_XALPHA) col[3]+= linef*linef;
512                         else col[3]+= linef;
513                 }
514                 if(ringf!=0.0) {
515                         Material *ma= har->mat;
516
517                         col[0]+= ringf * ma->mirr;
518                         col[1]+= ringf * ma->mirg;
519                         col[2]+= ringf * ma->mirb;
520                         
521                         if(har->type & HA_XALPHA) col[3]+= ringf*ringf;
522                         else col[3]+= ringf;
523                 }
524         }
525 }
526
527 /* ------------------------------------------------------------------------- */
528 /*
529   
530   There are three different modes for blending sky behind a picture:       
531   1. sky    = blend in sky directly                                        
532   2. premul = don't do sky, but apply alpha (so pretend the picture ends   
533      exactly at it's boundaries)                                  
534   3. key    = don't do anything                                            
535   Now the stupid thing is that premul means do nothing for us, and key     
536   we have to adjust a bit...
537
538 */
539
540 /* Sky vars. */
541 enum RE_SkyAlphaBlendingType keyingType = RE_ALPHA_SKY; /* The blending type    */
542
543 void setSkyBlendingMode(enum RE_SkyAlphaBlendingType mode) {
544         if ((RE_ALPHA_NODEF < mode) && (mode < RE_ALPHA_MAX) ) {
545                 keyingType = mode;
546         } else {
547                 /* error: false mode received */
548                 keyingType = RE_ALPHA_SKY;
549         }
550 }
551
552 enum RE_SkyAlphaBlendingType getSkyBlendingMode() {
553         return keyingType;
554 }
555
556 /* This one renders into collector, as always.                               */
557 void renderSkyPixelFloat(RE_COLBUFTYPE *collector, float x, float y, float *rco)
558 {
559
560         switch (keyingType) {
561         case RE_ALPHA_PREMUL:
562         case RE_ALPHA_KEY:
563                 /* Premul or key: don't fill, and don't change the values! */
564                 /* key alpha used to fill in color in 'empty' pixels, doesn't work anymore this way */
565                 collector[0] = 0.0; 
566                 collector[1] = 0.0; 
567                 collector[2] = 0.0; 
568                 collector[3] = 0.0; 
569                 break;
570         case RE_ALPHA_SKY:
571                 /* Fill in the sky as if it were a normal face. */
572                 shadeSkyPixel(collector, x, y, rco);
573                 collector[3]= 0.0;
574                 break;
575         default:
576                 ; /* Error: illegal alpha blending state */
577         }
578 }
579
580
581
582 /*
583   Stuff the sky colour into the collector.
584  */
585 void shadeSkyPixel(RE_COLBUFTYPE *collector, float fx, float fy, float *rco) 
586 {
587         float view[3], dxyview[2];
588         
589         /*
590           The rules for sky:
591           1. Draw an image, if a background image was provided. Stop
592           2. get texture and colour blend, and combine these.
593         */
594
595         float fac;
596
597         /* 1. Do a backbuffer image: */ 
598         if(R.r.bufflag & 1) {
599                 fillBackgroundImage(collector, fx, fy);
600                 return;
601         } else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
602                 /*
603                   2. Test for these types of sky. The old renderer always had to check for
604                   coverage, but we don't need that anymore                                 
605                   - SKYBLEND or SKYTEX disabled: fill in a flat colour                     
606                   - otherwise, do the appropriate mapping (tex or colour blend)            
607                   There used to be cached chars here, but they are not useful anymore
608                 */
609                 collector[0] = R.wrld.horr;
610                 collector[1] = R.wrld.horg;
611                 collector[2] = R.wrld.horb;
612                 collector[3] = 1.0f;
613         } else {
614                 /*
615                   3. Which type(s) is(are) this (these)? This has to be done when no simple
616                   way of determining the colour exists.
617                 */
618
619                 /* This one true because of the context of this routine  */
620 /*              if(rect[3] < 254) {  */
621                 if(R.wrld.skytype & WO_SKYPAPER) {
622                         view[0]= (fx+(R.xstart))/(float)R.afmx;
623                         view[1]= (fy+(R.ystart))/(float)R.afmy;
624                         view[2]= 0.0;
625                         
626                         dxyview[0]= 1.0/(float)R.afmx;
627                         dxyview[1]= 1.0/(float)R.afmy;
628                 }
629                 else {
630                         /* Wasn't this some pano stuff? */
631                         view[0]= (fx+(R.xstart)+1.0);
632                         
633                         if(R.flag & R_SEC_FIELD) {
634                                 if(R.r.mode & R_ODDFIELD) view[1]= (fy+R.ystart+0.5)*R.ycor;
635                                 else view[1]= (fy+R.ystart+1.5)*R.ycor;
636                         }
637                         else view[1]= (fy+R.ystart+1.0)*R.ycor;
638                         
639                         view[2]= -R.viewfac;
640                         
641                         fac= Normalise(view);
642                         if(R.wrld.skytype & WO_SKYTEX) {
643                                 dxyview[0]= 1.0/fac;
644                                 dxyview[1]= R.ycor/fac;
645                         }
646                 }
647                 
648                 if(R.r.mode & R_PANORAMA) {
649                         float panoco, panosi;
650                         float u, v;
651                         
652                         panoco = getPanovCo();
653                         panosi = getPanovSi();
654                         u= view[0]; v= view[2];
655                         
656                         view[0]= panoco*u + panosi*v;
657                         view[2]= -panosi*u + panoco*v;
658                 }
659         
660                 /* get sky colour in the collector */
661                 shadeSkyPixelFloat(collector, rco, view, dxyview);
662                 collector[3] = 1.0f;
663         }
664 }
665
666 /* Only view vector is important here. Result goes to colf[3] */
667 void shadeSkyPixelFloat(float *colf, float *rco, float *view, float *dxyview)
668 {
669         float lo[3], zen[3], hor[3], blend, blendm;
670         
671         /* Why is this setting forced? Seems silly to me. It is tested in the texture unit. */
672         R.wrld.skytype |= WO_ZENUP;
673         
674         /* Some view vector stuff. */
675         if(R.wrld.skytype & WO_SKYREAL) {
676         
677                 blend= view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2];
678
679                 if(blend<0.0) R.wrld.skytype-= WO_ZENUP;
680                 blend= fabs(blend);
681         }
682         else if(R.wrld.skytype & WO_SKYPAPER) {
683                 blend= 0.5+ 0.5*view[1];
684         }
685         else {
686                 /* the fraction of how far we are above the bottom of the screen */
687                 blend= fabs(0.5+ view[1]);
688         }
689
690         hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
691         zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
692         
693         /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If           */
694         /* SKYBLEND is active, the texture and colour blend are added.           */
695         if(R.wrld.skytype & WO_SKYTEX) {
696                 VECCOPY(lo, view);
697                 if(R.wrld.skytype & WO_SKYREAL) {
698                         
699                         MTC_Mat3MulVecfl(R.imat, lo);
700
701                         SWAP(float, lo[1],  lo[2]);
702                         
703                 }
704                 do_sky_tex(rco, lo, dxyview, hor, zen, &blend);
705         }
706
707         if(blend>1.0) blend= 1.0;
708         blendm= 1.0-blend;
709
710         /* No clipping, no conversion! */
711         if(R.wrld.skytype & WO_SKYBLEND) {
712                 colf[0] = (blendm*hor[0] + blend*zen[0]);
713                 colf[1] = (blendm*hor[1] + blend*zen[1]);
714                 colf[2] = (blendm*hor[2] + blend*zen[2]);
715         } else {
716                 /* Done when a texture was grabbed. */
717                 colf[0]= hor[0];
718                 colf[1]= hor[1];
719                 colf[2]= hor[2];
720         }
721 }
722
723
724 /*
725   Render pixel (x,y) from the backbuffer into the collector
726           
727   backbuf is type Image, backbuf->ibuf is an ImBuf.  ibuf->rect is the
728   rgba data (32 bit total), in ibuf->x by ibuf->y pixels. Copying
729   should be really easy. I hope I understand the way ImBuf works
730   correctly. (nzc)
731 */
732 void fillBackgroundImageChar(char *col, float x, float y)
733 {
734
735         int iy, ix;
736         unsigned int* imBufPtr;
737         
738         /* check to be sure... */
739         if (R.backbuf==NULL || R.backbuf->ok==0) {
740                 /* bail out */
741                 col[0] = 0;
742                 col[1] = 0;
743                 col[2] = 0;
744                 col[3] = 255;
745                 return;
746         }
747         /* load image if not already done?*/
748         if(R.backbuf->ibuf==0) {
749                 R.backbuf->ok= 0;
750                 return;
751         }
752
753         tag_image_time(R.backbuf);
754
755         /* Now for the real extraction: */
756         /* Get the y-coordinate of the scanline? */
757         iy= (int) ((y+R.afmy+R.ystart)*R.backbuf->ibuf->y)/(2*R.afmy);
758         ix= (int) ((x+R.afmx+R.xstart)*R.backbuf->ibuf->x)/(2*R.afmx);
759         
760         /* correct in case of fields rendering: */
761         if(R.flag & R_SEC_FIELD) {
762                 if((R.r.mode & R_ODDFIELD)==0) {
763                         if( iy<R.backbuf->ibuf->y) iy++;
764                 }
765                 else {
766                         if( iy>0) iy--;
767                 }
768         }
769
770         /* Offset into the buffer: start of scanline y: */
771         imBufPtr = R.backbuf->ibuf->rect
772                 + (iy * R.backbuf->ibuf->x)
773                 + ix;
774
775         *( (int *)col) = *imBufPtr;
776         
777 }
778
779 void fillBackgroundImage(RE_COLBUFTYPE *collector, float x, float y)
780 {
781         char col[4];
782         
783         fillBackgroundImageChar(col, x, y);
784         cpCharColV2FloatColV(col, collector);
785         
786 }
787
788 /* eof */