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