And there's another annoyance I got poked for:
[blender.git] / source / blender / render / intern / source / imagetexture.c
1 /**
2  *
3  * $Id:
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version. 
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22  * All rights reserved.
23  *
24  * Contributors: 2004/2005/2006 Blender Foundation, full recode
25  *
26  * ***** END GPL/BL DUAL LICENSE BLOCK *****
27  */
28
29
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #ifndef WIN32 
36 #include <unistd.h>
37 #else
38 #include <io.h>
39 #endif
40
41 #include "MEM_guardedalloc.h"
42
43 #include "IMB_imbuf_types.h"
44 #include "IMB_imbuf.h"
45
46 #include "DNA_image_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_texture_types.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_threads.h"
52
53 #include "BKE_utildefines.h"
54 #include "BKE_global.h"
55 #include "BKE_main.h"
56 #include "BKE_image.h"
57 #include "BKE_texture.h"
58 #include "BKE_library.h"
59
60 #include "renderpipeline.h"
61 #include "render_types.h"
62 #include "texture.h"
63
64 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
65 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
66 /* only to be used here in this file, it's for speed */
67 extern struct Render R;
68 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
69
70 /* *********** IMAGEWRAPPING ****************** */
71
72
73 /* x and y have to be checked for image size */
74 static void ibuf_get_color(float *col, struct ImBuf *ibuf, int x, int y)
75 {
76         int ofs = y * ibuf->x + x;
77         
78         if(ibuf->rect_float) {
79                 if(ibuf->channels==4) {
80                         float *fp= ibuf->rect_float + 4*ofs;
81                         QUATCOPY(col, fp);
82                 }
83                 else if(ibuf->channels==3) {
84                         float *fp= ibuf->rect_float + 3*ofs;
85                         VECCOPY(col, fp);
86                         col[3]= 1.0f;
87                 }
88                 else {
89                         float *fp= ibuf->rect_float + ofs;
90                         col[0]= col[1]= col[2]= col[3]= *fp;
91                 }
92         }
93         else {
94                 char *rect = (char *)( ibuf->rect+ ofs);
95
96                 col[0] = ((float)rect[0])/255.0f;
97                 col[1] = ((float)rect[1])/255.0f;
98                 col[2] = ((float)rect[2])/255.0f;
99                 col[3] = ((float)rect[3])/255.0f;
100         }       
101 }
102
103 int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, TexResult *texres)
104 {
105         float fx, fy, val1, val2, val3;
106         int x, y, retval;
107
108         texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
109         
110         /* we need to set retval OK, otherwise texture code generates normals itself... */
111         retval= texres->nor?3:1;
112         
113         /* quick tests */
114         if(ibuf==NULL && ima==NULL)
115                 return retval;
116         if(ima) {
117                 
118                 /* hack for icon render */
119                 if(ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD))
120                         return retval;
121                 
122                 ibuf= BKE_image_get_ibuf(ima, &tex->iuser);
123         }
124         if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL))
125                 return retval;
126         
127         /* setup mapping */
128         if(tex->imaflag & TEX_IMAROT) {
129                 fy= texvec[0];
130                 fx= texvec[1];
131         }
132         else {
133                 fx= texvec[0];
134                 fy= texvec[1];
135         }
136         
137         if(tex->extend == TEX_CHECKER) {
138                 int xs, ys;
139                 
140                 xs= (int)floor(fx);
141                 ys= (int)floor(fy);
142                 fx-= xs;
143                 fy-= ys;
144
145                 if( (tex->flag & TEX_CHECKER_ODD)==0) {
146                         if((xs+ys) & 1);else return retval;
147                 }
148                 if( (tex->flag & TEX_CHECKER_EVEN)==0) {
149                         if((xs+ys) & 1) return retval; 
150                 }
151                 /* scale around center, (0.5, 0.5) */
152                 if(tex->checkerdist<1.0) {
153                         fx= (fx-0.5)/(1.0-tex->checkerdist) +0.5;
154                         fy= (fy-0.5)/(1.0-tex->checkerdist) +0.5;
155                 }
156         }
157
158         x = (int)(fx*ibuf->x);
159         y = (int)(fy*ibuf->y);
160
161         if(tex->extend == TEX_CLIPCUBE) {
162                 if(x<0 || y<0 || x>=ibuf->x || y>=ibuf->y || texvec[2]<-1.0 || texvec[2]>1.0) {
163                         return retval;
164                 }
165         }
166         else if( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
167                 if(x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
168                         return retval;
169                 }
170         }
171         else {
172                 if(tex->extend==TEX_EXTEND) {
173                         if(x>=ibuf->x) x = ibuf->x-1;
174                         else if(x<0) x= 0;
175                 }
176                 else {
177                         x= x % ibuf->x;
178                         if(x<0) x+= ibuf->x;
179                 }
180                 if(tex->extend==TEX_EXTEND) {
181                         if(y>=ibuf->y) y = ibuf->y-1;
182                         else if(y<0) y= 0;
183                 }
184                 else {
185                         y= y % ibuf->y;
186                         if(y<0) y+= ibuf->y;
187                 }
188         }
189         
190         /* warning, no return before setting back! */
191         if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
192                 ibuf->rect+= (ibuf->x*ibuf->y);
193         }
194
195         ibuf_get_color(&texres->tr, ibuf, x, y);
196         
197         if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
198                 ibuf->rect-= (ibuf->x*ibuf->y);
199         }
200
201         if(tex->imaflag & TEX_USEALPHA) {
202                 if(tex->imaflag & TEX_CALCALPHA);
203                 else texres->talpha= 1;
204         }
205         
206         if(texres->nor) {
207                 if(tex->imaflag & TEX_NORMALMAP) {
208                         // qdn: normal from color
209                         texres->nor[0] = 2.f*(texres->tr - 0.5f);
210                         texres->nor[1] = 2.f*(0.5f - texres->tg);
211                         texres->nor[2] = 2.f*(texres->tb - 0.5f);
212                 }
213                 else {
214                         /* bump: take three samples */
215                         val1= texres->tr+texres->tg+texres->tb;
216
217                         if(x<ibuf->x-1) {
218                                 float col[4];
219                                 ibuf_get_color(col, ibuf, x+1, y);
220                                 val2= (col[0]+col[1]+col[2]);
221                         }
222                         else val2= val1;
223
224                         if(y<ibuf->y-1) {
225                                 float col[4];
226                                 ibuf_get_color(col, ibuf, x, y+1);
227                                 val3= (col[0]+col[1]+col[2]);
228                         }
229                         else val3= val1;
230
231                         /* do not mix up x and y here! */
232                         texres->nor[0]= (val1-val2);
233                         texres->nor[1]= (val1-val3);
234                 }
235         }
236
237         BRICONTRGB;
238
239         if(texres->talpha) texres->tin= texres->ta;
240         else if(tex->imaflag & TEX_CALCALPHA) {
241                 texres->ta= texres->tin= MAX3(texres->tr, texres->tg, texres->tb);
242         }
243         else texres->ta= texres->tin= 1.0;
244         
245         if(tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
246
247         /* de-premul, this is being premulled in shade_input_do_shade() */
248         if(texres->ta!=1.0f && texres->ta!=0.0f) {
249                 fx= 1.0f/texres->ta;
250                 texres->tr*= fx;
251                 texres->tg*= fx;
252                 texres->tb*= fx;
253         }
254         
255         return retval;
256 }
257
258 static void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2)
259 {
260         rctf *rf, *newrct;
261         short a;
262
263         a= *count;
264         rf= stack;
265         for(;a>0;a--) {
266                 if(rf->xmin<x1) {
267                         if(rf->xmax<x1) {
268                                 rf->xmin+= (x2-x1);
269                                 rf->xmax+= (x2-x1);
270                         }
271                         else {
272                                 if(rf->xmax>x2) rf->xmax= x2;
273                                 newrct= stack+ *count;
274                                 (*count)++;
275
276                                 newrct->xmax= x2;
277                                 newrct->xmin= rf->xmin+(x2-x1);
278                                 newrct->ymin= rf->ymin;
279                                 newrct->ymax= rf->ymax;
280                                 
281                                 if(newrct->xmin==newrct->xmax) (*count)--;
282                                 
283                                 rf->xmin= x1;
284                         }
285                 }
286                 else if(rf->xmax>x2) {
287                         if(rf->xmin>x2) {
288                                 rf->xmin-= (x2-x1);
289                                 rf->xmax-= (x2-x1);
290                         }
291                         else {
292                                 if(rf->xmin<x1) rf->xmin= x1;
293                                 newrct= stack+ *count;
294                                 (*count)++;
295
296                                 newrct->xmin= x1;
297                                 newrct->xmax= rf->xmax-(x2-x1);
298                                 newrct->ymin= rf->ymin;
299                                 newrct->ymax= rf->ymax;
300
301                                 if(newrct->xmin==newrct->xmax) (*count)--;
302
303                                 rf->xmax= x2;
304                         }
305                 }
306                 rf++;
307         }
308
309 }
310
311 static void clipy_rctf_swap(rctf *stack, short *count, float y1, float y2)
312 {
313         rctf *rf, *newrct;
314         short a;
315
316         a= *count;
317         rf= stack;
318         for(;a>0;a--) {
319                 if(rf->ymin<y1) {
320                         if(rf->ymax<y1) {
321                                 rf->ymin+= (y2-y1);
322                                 rf->ymax+= (y2-y1);
323                         }
324                         else {
325                                 if(rf->ymax>y2) rf->ymax= y2;
326                                 newrct= stack+ *count;
327                                 (*count)++;
328
329                                 newrct->ymax= y2;
330                                 newrct->ymin= rf->ymin+(y2-y1);
331                                 newrct->xmin= rf->xmin;
332                                 newrct->xmax= rf->xmax;
333
334                                 if(newrct->ymin==newrct->ymax) (*count)--;
335
336                                 rf->ymin= y1;
337                         }
338                 }
339                 else if(rf->ymax>y2) {
340                         if(rf->ymin>y2) {
341                                 rf->ymin-= (y2-y1);
342                                 rf->ymax-= (y2-y1);
343                         }
344                         else {
345                                 if(rf->ymin<y1) rf->ymin= y1;
346                                 newrct= stack+ *count;
347                                 (*count)++;
348
349                                 newrct->ymin= y1;
350                                 newrct->ymax= rf->ymax-(y2-y1);
351                                 newrct->xmin= rf->xmin;
352                                 newrct->xmax= rf->xmax;
353
354                                 if(newrct->ymin==newrct->ymax) (*count)--;
355
356                                 rf->ymax= y2;
357                         }
358                 }
359                 rf++;
360         }
361 }
362
363 static float square_rctf(rctf *rf)
364 {
365         float x, y;
366
367         x= rf->xmax- rf->xmin;
368         y= rf->ymax- rf->ymin;
369         return (x*y);
370 }
371
372 static float clipx_rctf(rctf *rf, float x1, float x2)
373 {
374         float size;
375
376         size= rf->xmax - rf->xmin;
377
378         if(rf->xmin<x1) {
379                 rf->xmin= x1;
380         }
381         if(rf->xmax>x2) {
382                 rf->xmax= x2;
383         }
384         if(rf->xmin > rf->xmax) {
385                 rf->xmin = rf->xmax;
386                 return 0.0;
387         }
388         else if(size!=0.0) {
389                 return (rf->xmax - rf->xmin)/size;
390         }
391         return 1.0;
392 }
393
394 static float clipy_rctf(rctf *rf, float y1, float y2)
395 {
396         float size;
397
398         size= rf->ymax - rf->ymin;
399
400         if(rf->ymin<y1) {
401                 rf->ymin= y1;
402         }
403         if(rf->ymax>y2) {
404                 rf->ymax= y2;
405         }
406
407         if(rf->ymin > rf->ymax) {
408                 rf->ymin = rf->ymax;
409                 return 0.0;
410         }
411         else if(size!=0.0) {
412                 return (rf->ymax - rf->ymin)/size;
413         }
414         return 1.0;
415
416 }
417
418 static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
419 {
420         /* sample box, is clipped already, and minx etc. have been set at ibuf size.
421        Enlarge with antialiased edges of the pixels */
422
423         float muly, mulx, div, col[4];
424         int x, y, startx, endx, starty, endy;
425
426         startx= (int)floor(rf->xmin);
427         endx= (int)floor(rf->xmax);
428         starty= (int)floor(rf->ymin);
429         endy= (int)floor(rf->ymax);
430
431         if(startx < 0) startx= 0;
432         if(starty < 0) starty= 0;
433         if(endx>=ibuf->x) endx= ibuf->x-1;
434         if(endy>=ibuf->y) endy= ibuf->y-1;
435
436         if(starty==endy && startx==endx) {
437                 ibuf_get_color(&texres->tr, ibuf, startx, starty);
438         }
439         else {
440                 div= texres->tr= texres->tg= texres->tb= texres->ta= 0.0;
441                 for(y=starty; y<=endy; y++) {
442                         
443                         muly= 1.0;
444
445                         if(starty==endy);
446                         else {
447                                 if(y==starty) muly= 1.0f-(rf->ymin - y);
448                                 if(y==endy) muly= (rf->ymax - y);
449                         }
450                         
451                         if(startx==endx) {
452                                 mulx= muly;
453                                 
454                                 ibuf_get_color(col, ibuf, startx, y);
455
456                                 texres->ta+= mulx*col[3];
457                                 texres->tr+= mulx*col[0];
458                                 texres->tg+= mulx*col[1];
459                                 texres->tb+= mulx*col[2];
460                                 div+= mulx;
461                         }
462                         else {
463                                 for(x=startx; x<=endx; x++) {
464                                         mulx= muly;
465                                         if(x==startx) mulx*= 1.0f-(rf->xmin - x);
466                                         if(x==endx) mulx*= (rf->xmax - x);
467
468                                         ibuf_get_color(col, ibuf, x, y);
469                                         
470                                         if(mulx==1.0) {
471                                                 texres->ta+= col[3];
472                                                 texres->tr+= col[0];
473                                                 texres->tg+= col[1];
474                                                 texres->tb+= col[2];
475                                                 div+= 1.0;
476                                         }
477                                         else {
478                                                 texres->ta+= mulx*col[3];
479                                                 texres->tr+= mulx*col[0];
480                                                 texres->tg+= mulx*col[1];
481                                                 texres->tb+= mulx*col[2];
482                                                 div+= mulx;
483                                         }
484                                 }
485                         }
486                 }
487                 if(div!=0.0) {
488                         div= 1.0f/div;
489                         texres->tb*= div;
490                         texres->tg*= div;
491                         texres->tr*= div;
492                         texres->ta*= div;
493                 }
494                 else {
495                         texres->tr= texres->tg= texres->tb= texres->ta= 0.0f;
496                 }
497         }
498 }
499
500 static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, TexResult *texres, int imaprepeat, int imapextend)
501 {
502         /* Sample box, performs clip. minx etc are in range 0.0 - 1.0 .
503      * Enlarge with antialiased edges of pixels.
504      * If variable 'imaprepeat' has been set, the
505      *  clipped-away parts are sampled as well.
506      */
507         /* note: actually minx etc isnt in the proper range... this due to filter size and offset vectors for bump */
508         TexResult texr;
509         rctf *rf, stack[8];
510         float opp, tot, alphaclip= 1.0;
511         short count=1;
512
513         rf= stack;
514         rf->xmin= minx*(ibuf->x);
515         rf->xmax= maxx*(ibuf->x);
516         rf->ymin= miny*(ibuf->y);
517         rf->ymax= maxy*(ibuf->y);
518
519         texr.talpha= texres->talpha;    /* is read by boxsample_clip */
520         
521         if(imapextend) {
522                 CLAMP(rf->xmin, 0.0f, ibuf->x-1);
523                 CLAMP(rf->xmax, 0.0f, ibuf->x-1);
524         }
525         else if(imaprepeat) 
526                 clipx_rctf_swap(stack, &count, 0.0, (float)(ibuf->x));
527         else {
528                 alphaclip= clipx_rctf(rf, 0.0, (float)(ibuf->x));
529
530                 if(alphaclip<=0.0) {
531                         texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
532                         return;
533                 }
534         }
535
536         if(imapextend) {
537                 CLAMP(rf->ymin, 0.0f, ibuf->y-1);
538                 CLAMP(rf->ymax, 0.0f, ibuf->y-1);
539         }
540         else if(imaprepeat) 
541                 clipy_rctf_swap(stack, &count, 0.0, (float)(ibuf->y));
542         else {
543                 alphaclip*= clipy_rctf(rf, 0.0, (float)(ibuf->y));
544
545                 if(alphaclip<=0.0) {
546                         texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
547                         return;
548                 }
549         }
550
551         if(count>1) {
552                 tot= texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
553                 while(count--) {
554                         boxsampleclip(ibuf, rf, &texr);
555                         
556                         opp= square_rctf(rf);
557                         tot+= opp;
558
559                         texres->tr+= opp*texr.tr;
560                         texres->tg+= opp*texr.tg;
561                         texres->tb+= opp*texr.tb;
562                         if(texres->talpha) texres->ta+= opp*texr.ta;
563                         rf++;
564                 }
565                 if(tot!= 0.0) {
566                         texres->tr/= tot;
567                         texres->tg/= tot;
568                         texres->tb/= tot;
569                         if(texres->talpha) texres->ta/= tot;
570                 }
571         }
572         else {
573                 boxsampleclip(ibuf, rf, texres);
574         }
575
576         if(texres->talpha==0) texres->ta= 1.0;
577         
578         if(alphaclip!=1.0) {
579                 /* this is for later investigation, premul or not? */
580                 /* texres->tr*= alphaclip; */
581                 /* texres->tg*= alphaclip; */
582                 /* texres->tb*= alphaclip; */
583                 texres->ta*= alphaclip;
584         }
585 }       
586
587 void image_sample(Image *ima, float fx, float fy, float dx, float dy, float *result)
588 {
589         TexResult texres;
590         ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
591         
592         if(ibuf==NULL) {
593                 result[0]= result[1]= result[2]= result[3]= 0.0f;
594                 return;
595         }
596         
597         if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
598                 ibuf->rect+= (ibuf->x*ibuf->y);
599         
600         boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1);
601         result[0]= texres.tr;
602         result[1]= texres.tg;
603         result[2]= texres.tb;
604         result[3]= texres.ta;
605
606         if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
607                 ibuf->rect-= (ibuf->x*ibuf->y);
608 }
609
610 void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result)
611 {
612         TexResult texres;
613         
614         if(ibuf==NULL) {
615                 return;
616         }
617         
618         boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1);
619         result[0]= texres.tr;
620         result[1]= texres.tg;
621         result[2]= texres.tb;
622         result[3]= texres.ta;
623 }
624
625
626
627 int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, float *dyt, TexResult *texres)
628 {
629         TexResult texr;
630         float fx, fy, minx, maxx, miny, maxy, dx, dy;
631         float maxd, pixsize, val1, val2, val3;
632         int curmap, retval, imaprepeat, imapextend;
633
634         texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
635         
636         /* we need to set retval OK, otherwise texture code generates normals itself... */
637         retval= texres->nor?3:1;
638         
639         /* quick tests */
640         if(ibuf==NULL && ima==NULL)
641                 return retval;
642         if(ima) {
643
644                 /* hack for icon render */
645                 if(ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD))
646                         return retval;
647                 
648                 ibuf= BKE_image_get_ibuf(ima, &tex->iuser); 
649         }
650         if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL))
651            return retval;
652         
653         /* mipmap test */
654         if(tex->imaflag & TEX_MIPMAP) {
655                 if(ibuf->flags & IB_fields);
656                 else if(ibuf->mipmap[0]==NULL) {
657                         BLI_lock_thread(LOCK_IMAGE);
658                         
659                         if(ibuf->mipmap[0]==NULL)
660                                 IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
661
662                         BLI_unlock_thread(LOCK_IMAGE);
663                 }
664         }
665
666         if(tex->imaflag & TEX_USEALPHA) {
667                 if(tex->imaflag & TEX_CALCALPHA);
668                 else texres->talpha= 1;
669         }
670         
671         texr.talpha= texres->talpha;
672         
673         if(tex->imaflag & TEX_IMAROT) {
674                 fy= texvec[0];
675                 fx= texvec[1];
676         }
677         else {
678                 fx= texvec[0];
679                 fy= texvec[1];
680         }
681         
682         if(ibuf->flags & IB_fields) {
683                 if(R.r.mode & R_FIELDS) {                       /* field render */
684                         if(R.flag & R_SEC_FIELD) {              /* correction for 2nd field */
685                                 /* fac1= 0.5/( (float)ibuf->y ); */
686                                 /* fy-= fac1; */
687                         }
688                         else {                          /* first field */
689                                 fy+= 0.5f/( (float)ibuf->y );
690                         }
691                 }
692         }
693         
694         /* pixel coordinates */
695
696         minx= MIN3(dxt[0],dyt[0],dxt[0]+dyt[0] );
697         maxx= MAX3(dxt[0],dyt[0],dxt[0]+dyt[0] );
698         miny= MIN3(dxt[1],dyt[1],dxt[1]+dyt[1] );
699         maxy= MAX3(dxt[1],dyt[1],dxt[1]+dyt[1] );
700
701         /* tex_sharper has been removed */
702         minx= tex->filtersize*(maxx-minx)/2.0f;
703         miny= tex->filtersize*(maxy-miny)/2.0f;
704         
705         if(tex->imaflag & TEX_FILTER_MIN) {
706                 /* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */
707                 float addval= (0.5f * tex->filtersize) / (float) MIN2(ibuf->x, ibuf->y);
708                 
709                 if(addval > minx)
710                         minx= addval;
711                 if(addval > miny)
712                         miny= addval;
713         }
714         if(tex->filtersize!=1.0f) {
715                 dxt[0]*= tex->filtersize;
716                 dxt[1]*= tex->filtersize;
717                 dyt[0]*= tex->filtersize;
718                 dyt[1]*= tex->filtersize;
719         }
720
721         if(tex->imaflag & TEX_IMAROT) SWAP(float, minx, miny);
722         
723         if(minx>0.25) minx= 0.25;
724         else if(minx<0.00001f) minx= 0.00001f;  /* side faces of unit-cube */
725         if(miny>0.25) miny= 0.25;
726         else if(miny<0.00001f) miny= 0.00001f;
727
728         
729         /* repeat and clip */
730         imaprepeat= (tex->extend==TEX_REPEAT);
731         imapextend= (tex->extend==TEX_EXTEND);
732
733         if(tex->extend == TEX_REPEAT) {
734                 if(tex->flag & (TEX_REPEAT_XMIR|TEX_REPEAT_YMIR)) {
735                         imaprepeat= 0;
736                         imapextend= 1;
737                 }
738         }
739
740         if(tex->extend == TEX_CHECKER) {
741                 int xs, ys, xs1, ys1, xs2, ys2, boundary;
742                 
743                 xs= (int)floor(fx);
744                 ys= (int)floor(fy);
745                 
746                 // both checkers available, no boundary exceptions, checkerdist will eat aliasing
747                 if( (tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN) ) {
748                         fx-= xs;
749                         fy-= ys;
750                 }
751                 else {
752                         
753                         xs1= (int)floor(fx-minx);
754                         ys1= (int)floor(fy-miny);
755                         xs2= (int)floor(fx+minx);
756                         ys2= (int)floor(fy+miny);
757                         boundary= (xs1!=xs2) || (ys1!=ys2);
758
759                         if(boundary==0) {
760                                 if( (tex->flag & TEX_CHECKER_ODD)==0) {
761                                         if((xs+ys) & 1); 
762                                         else return retval;
763                                 }
764                                 if( (tex->flag & TEX_CHECKER_EVEN)==0) {
765                                         if((xs+ys) & 1) return retval;
766                                 }
767                                 fx-= xs;
768                                 fy-= ys;
769                         }
770                         else {
771                                 if(tex->flag & TEX_CHECKER_ODD) {
772                                         if((xs1+ys) & 1) fx-= xs2;
773                                         else fx-= xs1;
774                                         
775                                         if((ys1+xs) & 1) fy-= ys2;
776                                         else fy-= ys1;
777                                 }
778                                 if(tex->flag & TEX_CHECKER_EVEN) {
779                                         if((xs1+ys) & 1) fx-= xs1;
780                                         else fx-= xs2;
781                                         
782                                         if((ys1+xs) & 1) fy-= ys1;
783                                         else fy-= ys2;
784                                 }
785                         }
786                 }
787
788                 /* scale around center, (0.5, 0.5) */
789                 if(tex->checkerdist<1.0) {
790                         fx= (fx-0.5)/(1.0-tex->checkerdist) +0.5;
791                         fy= (fy-0.5)/(1.0-tex->checkerdist) +0.5;
792                         minx/= (1.0-tex->checkerdist);
793                         miny/= (1.0-tex->checkerdist);
794                 }
795         }
796
797         if(tex->extend == TEX_CLIPCUBE) {
798                 if(fx+minx<0.0 || fy+miny<0.0 || fx-minx>1.0 || fy-miny>1.0 || texvec[2]<-1.0 || texvec[2]>1.0) {
799                         return retval;
800                 }
801         }
802         else if(tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
803                 if(fx+minx<0.0 || fy+miny<0.0 || fx-minx>1.0 || fy-miny>1.0) {
804                         return retval;
805                 }
806         }
807         else {
808                 if(imapextend) {
809                         if(fx>1.0) fx = 1.0;
810                         else if(fx<0.0) fx= 0.0;
811                 }
812                 else {
813                         if(fx>1.0) fx -= (int)(fx);
814                         else if(fx<0.0) fx+= 1-(int)(fx);
815                 }
816                 
817                 if(imapextend) {
818                         if(fy>1.0) fy = 1.0;
819                         else if(fy<0.0) fy= 0.0;
820                 }
821                 else {
822                         if(fy>1.0) fy -= (int)(fy);
823                         else if(fy<0.0) fy+= 1-(int)(fy);
824                 }
825         }
826
827         /* warning no return! */
828         if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
829                 ibuf->rect+= (ibuf->x*ibuf->y);
830         }
831
832         /* choice:  */
833         if(tex->imaflag & TEX_MIPMAP) {
834                 ImBuf *previbuf, *curibuf;
835                 float bumpscale;
836                 
837                 dx= minx;
838                 dy= miny;
839                 maxd= MAX2(dx, dy);
840                 if(maxd>0.5) maxd= 0.5;
841
842                 pixsize = 1.0f/ (float) MIN2(ibuf->x, ibuf->y);
843                 
844                 bumpscale= pixsize/maxd;
845                 if(bumpscale>1.0f) bumpscale= 1.0f;
846                 else bumpscale*=bumpscale;
847                 
848                 curmap= 0;
849                 previbuf= curibuf= ibuf;
850                 while(curmap<IB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) {
851                         if(maxd < pixsize) break;
852                         previbuf= curibuf;
853                         curibuf= ibuf->mipmap[curmap];
854                         pixsize= 1.0f / (float)MIN2(curibuf->x, curibuf->y);
855                         curmap++;
856                 }
857
858                 if(previbuf!=curibuf || (tex->imaflag & TEX_INTERPOL)) {
859                         /* sample at least 1 pixel */
860                         if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
861                         if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
862                 }
863                 
864                 if(texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
865                         /* a bit extra filter */
866                         //minx*= 1.35f;
867                         //miny*= 1.35f;
868                         
869                         boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
870                         val1= texres->tr+texres->tg+texres->tb;
871                         boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
872                         val2= texr.tr + texr.tg + texr.tb;
873                         boxsample(curibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
874                         val3= texr.tr + texr.tg + texr.tb;
875
876                         /* don't switch x or y! */
877                         texres->nor[0]= (val1-val2);
878                         texres->nor[1]= (val1-val3);
879                         
880                         if(previbuf!=curibuf) {  /* interpolate */
881                                 
882                                 boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend);
883                                 
884                                 /* calc rgb */
885                                 dx= 2.0f*(pixsize-maxd)/pixsize;
886                                 if(dx>=1.0f) {
887                                         texres->ta= texr.ta; texres->tb= texr.tb;
888                                         texres->tg= texr.tg; texres->tr= texr.tr;
889                                 }
890                                 else {
891                                         dy= 1.0f-dx;
892                                         texres->tb= dy*texres->tb+ dx*texr.tb;
893                                         texres->tg= dy*texres->tg+ dx*texr.tg;
894                                         texres->tr= dy*texres->tr+ dx*texr.tr;
895                                         texres->ta= dy*texres->ta+ dx*texr.ta;
896                                 }
897                                 
898                                 val1= dy*val1+ dx*(texr.tr + texr.tg + texr.tb);
899                                 boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
900                                 val2= dy*val2+ dx*(texr.tr + texr.tg + texr.tb);
901                                 boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
902                                 val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb);
903                                 
904                                 texres->nor[0]= (val1-val2);    /* vals have been interpolated above! */
905                                 texres->nor[1]= (val1-val3);
906                                 
907                                 if(dx<1.0f) {
908                                         dy= 1.0f-dx;
909                                         texres->tb= dy*texres->tb+ dx*texr.tb;
910                                         texres->tg= dy*texres->tg+ dx*texr.tg;
911                                         texres->tr= dy*texres->tr+ dx*texr.tr;
912                                         texres->ta= dy*texres->ta+ dx*texr.ta;
913                                 }
914                         }
915                         texres->nor[0]*= bumpscale;
916                         texres->nor[1]*= bumpscale;
917                 }
918                 else {
919                         maxx= fx+minx;
920                         minx= fx-minx;
921                         maxy= fy+miny;
922                         miny= fy-miny;
923
924                         boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
925
926                         if(previbuf!=curibuf) {  /* interpolate */
927                                 boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
928                                 
929                                 fx= 2.0f*(pixsize-maxd)/pixsize;
930                                 
931                                 if(fx>=1.0) {
932                                         texres->ta= texr.ta; texres->tb= texr.tb;
933                                         texres->tg= texr.tg; texres->tr= texr.tr;
934                                 } else {
935                                         fy= 1.0f-fx;
936                                         texres->tb= fy*texres->tb+ fx*texr.tb;
937                                         texres->tg= fy*texres->tg+ fx*texr.tg;
938                                         texres->tr= fy*texres->tr+ fx*texr.tr;
939                                         texres->ta= fy*texres->ta+ fx*texr.ta;
940                                 }
941                         }
942                 }
943         }
944         else {
945                 if((tex->imaflag & TEX_INTERPOL)) {
946                         /* sample 1 pixel minimum */
947                         if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
948                         if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
949                 }
950
951                 if(texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
952                         
953                         boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
954                         val1= texres->tr+texres->tg+texres->tb;
955                         boxsample(ibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
956                         val2= texr.tr + texr.tg + texr.tb;
957                         boxsample(ibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
958                         val3= texr.tr + texr.tg + texr.tb;
959                         /* don't switch x or y! */
960                         texres->nor[0]= (val1-val2);
961                         texres->nor[1]= (val1-val3);
962                 }
963                 else {
964                         boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
965                 }
966         }
967         
968         BRICONTRGB;
969         
970         if(tex->imaflag & TEX_CALCALPHA) {
971                 texres->ta= texres->tin= texres->ta*MAX3(texres->tr, texres->tg, texres->tb);
972         }
973         else texres->tin= texres->ta;
974
975         if(tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
976         
977         if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
978                 ibuf->rect-= (ibuf->x*ibuf->y);
979         }
980
981         if(texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
982                 // qdn: normal from color
983                 texres->nor[0] = 2.f*(texres->tr - 0.5f);
984                 texres->nor[1] = 2.f*(0.5f - texres->tg);
985                 texres->nor[2] = 2.f*(texres->tb - 0.5f);
986         }
987         
988         /* de-premul, this is being premulled in shade_input_do_shade() */
989         if(texres->ta!=1.0f && texres->ta!=0.0f) {
990                 fx= 1.0f/texres->ta;
991                 texres->tr*= fx;
992                 texres->tg*= fx;
993                 texres->tb*= fx;
994         }
995
996         return retval;
997 }