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