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