2.5: Texture Filtering
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 21 Jul 2009 13:20:35 +0000 (13:20 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 21 Jul 2009 13:20:35 +0000 (13:20 +0000)
Patch by Alfredo de Greef with high quality image texture filters.
This adds 3 new filters:

* SAT: Summed Area Tables. This is like mipmaps, but using somewhat
  more memory avoids some artifacts.
* EWA: Ellipitical Weighted Average, anisotropic filter.
* FELINE: Fast elliptical lines for anisotropic texture mapping.

The one change I made to this was to try to fix an alpha/premul
problem, hopefully I didn't break anything, it looks compatible
with the existing filter now for me.

release/ui/buttons_texture.py
source/blender/blenkernel/intern/texture.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/imbuf/IMB_imbuf.h
source/blender/imbuf/intern/filter.c
source/blender/makesdna/DNA_texture_types.h
source/blender/makesrna/intern/rna_texture.c
source/blender/render/intern/source/imagetexture.c
source/blender/render/intern/source/texture.c

index 7367805a39542a5e0fa0b748dae8f1364cfc7070..d86cec17d015dbdfeaefacd18651656f69d3ddbd 100644 (file)
@@ -426,19 +426,17 @@ class TEXTURE_PT_image_sampling(TextureButtonsPanel):
 
                sub = split.column() 
                sub.itemL(text="Filter:")
-               #sub.itemR(tex, "filter", text="")
+               sub.itemR(tex, "filter", text="")
                sub.itemR(tex, "mipmap")
                row = sub.row()
                row.itemR(tex, "mipmap_gauss", text="Gauss")
                row.active = tex.mipmap
                sub.itemR(tex, "interpolation")
-               """
                if tex.mipmap and tex.filter != 'DEFAULT':
                        if tex.filter == 'FELINE':
                                sub.itemR(tex, "filter_probes", text="Probes")
                        else:
                                sub.itemR(tex, "filter_eccentricity", text="Eccentricity")
-               """
 
 class TEXTURE_PT_image_mapping(TextureButtonsPanel):
        __idname__= "TEXTURE_PT_image_mapping"
index bcdea06936f0214867019220c57832be5bf754f2..db864dc9f1eb999048ede02430f9579ab915a691 100644 (file)
@@ -435,12 +435,15 @@ void default_tex(Tex *tex)
        VarStruct *varstr;
        int a;
 
+       tex->type= TEX_CLOUDS;
        tex->stype= 0;
        tex->flag= TEX_CHECKER_ODD;
-       tex->imaflag= TEX_INTERPOL+TEX_MIPMAP+TEX_USEALPHA;
+       tex->imaflag= TEX_INTERPOL|TEX_MIPMAP|TEX_USEALPHA;
        tex->extend= TEX_REPEAT;
        tex->cropxmin= tex->cropymin= 0.0;
        tex->cropxmax= tex->cropymax= 1.0;
+       tex->texfilter = TXF_DEFAULT;
+       tex->afmax = 8;
        tex->xrepeat= tex->yrepeat= 1;
        tex->fie_ima= 2;
        tex->sfra= 1;
index c43c720bad0a45fe988dbd865aaa2e81be031c98..6da444bc88eb791b42da158f926af51937dc60d4 100644 (file)
@@ -9273,6 +9273,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                World *wo;
                Object *ob;
                Material *ma;
+               Tex *tex;
                Scene *sce;
                ToolSettings *ts;
                int i;
@@ -9349,6 +9350,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                        }
                }
 
+               /* texture filter */
+               for(tex = main->tex.first; tex; tex = tex->id.next)
+                       if(tex->afmax == 0)
+                               tex->afmax= 8;
+
                for(ma = main->mat.first; ma; ma = ma->id.next) {
                        if(ma->mode & MA_HALO) {
                                ma->material_type= MA_TYPE_HALO;
index f8d1e1d7ab98cb5c57144147b7c9e5eb19b2ba0e..8b01c341565382b2baf91ad9f73237ab4ced6d00 100644 (file)
@@ -1215,10 +1215,10 @@ void uiTemplatePreview(uiLayout *layout, ID *id, ID *parent)
        uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
        
        /* add buttons */
-       if(id) {
-               if(GS(id->name) == ID_MA || (parent && GS(parent->name) == ID_MA)) {
-                       if(GS(id->name) == ID_MA) ma= (Material*)id;
-                       else ma= (Material*)parent;
+       if(pid) {
+               if(GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
+                       if(GS(pid->name) == ID_MA) ma= (Material*)pid;
+                       else ma= (Material*)pparent;
 
                        uiLayoutColumn(row, 1);
 
index dd4e67e612c6e08abf97f478afd289a1cae6337a..d80a26e50f8e971e470d7c2d4535025a47248cc6 100644 (file)
@@ -1345,7 +1345,7 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d)
                int mip= 0;
                
                if(ibuf->mipmap[0]==NULL)
-                       IMB_makemipmap(ibuf, 0);
+                       IMB_makemipmap(ibuf, 0, 0);
                
                while(tzoom < 1.0f && mip<8 && ibuf->mipmap[mip]) {
                        tzoom*= 2.0f;
index 1d8035a2358cf633a3db7289be25739851b761da..d2f561438b9711cfe21c0fecfc87d8037b3f8392 100644 (file)
@@ -319,7 +319,7 @@ void IMB_antialias(struct ImBuf * ibuf);
 void IMB_filter(struct ImBuf *ibuf);
 void IMB_filterN(struct ImBuf *out, struct ImBuf *in);
 void IMB_filter_extend(struct ImBuf *ibuf, char *mask);
-void IMB_makemipmap(struct ImBuf *ibuf, int use_filter);
+void IMB_makemipmap(struct ImBuf *ibuf, int use_filter, int SAT);
 
 /**
  *
index 9802405fd8d38cd44c54f1e3083f0019c9b52532..cc3315c76964440b52cd31f107051c5ae0b035bd 100644 (file)
@@ -371,6 +371,7 @@ void IMB_filter_extend(struct ImBuf *ibuf, char *mask)
        }
 }
 
+#if 0
 void IMB_makemipmap(ImBuf *ibuf, int use_filter)
 {
        ImBuf *hbuf= ibuf;
@@ -394,5 +395,90 @@ void IMB_makemipmap(ImBuf *ibuf, int use_filter)
                minsize= hbuf->x<hbuf->y?hbuf->x:hbuf->y;
        }
 }
+#endif
 
-
+void IMB_makemipmap(ImBuf *ibuf, int use_filter, int SAT)
+{
+       if (SAT) {
+               // to maximize precision subtract image average, use intermediate double SAT,
+               // only convert to float at the end
+               const double dv = 1.0/255.0;
+               double avg[4] = {0, 0, 0, 0};
+               const int x4 = ibuf->x << 2;
+               int x, y, i;
+               ImBuf* sbuf = IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rectfloat, 0);
+               double *satp, *satbuf = MEM_callocN(sizeof(double)*ibuf->x*ibuf->y*4, "tmp SAT buf");
+               const double mf = ibuf->x*ibuf->y;
+               float* fp;
+               ibuf->mipmap[0] = sbuf;
+               if (ibuf->rect_float) {
+                       fp = ibuf->rect_float;
+                       for (y=0; y<ibuf->y; ++y)
+                               for (x=0; x<ibuf->x; ++x) {
+                                       avg[0] += *fp++;
+                                       avg[1] += *fp++;
+                                       avg[2] += *fp++;
+                                       avg[3] += *fp++;
+                               }
+               }
+               else {
+                       char* cp = (char*)ibuf->rect;
+                       for (y=0; y<ibuf->y; ++y)
+                               for (x=0; x<ibuf->x; ++x) {
+                                       avg[0] += *cp++ * dv;
+                                       avg[1] += *cp++ * dv;
+                                       avg[2] += *cp++ * dv;
+                                       avg[3] += *cp++ * dv;
+                               }
+               }
+               avg[0] /= mf;
+               avg[1] /= mf;
+               avg[2] /= mf;
+               avg[3] /= mf;
+               for (y=0; y<ibuf->y; ++y)
+                       for (x=0; x<ibuf->x; ++x) {
+                               const unsigned int p = (x + y*ibuf->x) << 2;
+                               char* cp = (char*)ibuf->rect + p;
+                               fp = ibuf->rect_float + p;
+                               satp = satbuf + p;
+                               for (i=0; i<4; ++i, ++cp, ++fp, ++satp) {
+                                       double sv = (ibuf->rect_float ? (double)*fp : (double)(*cp)*dv) - avg[i];
+                                       if (x > 0) sv += satp[-4];
+                                       if (y > 0) sv += satp[-x4];
+                                       if (x > 0 && y > 0) sv -= satp[-x4 - 4];
+                                       *satp = sv;
+                               }
+                       }
+               fp = sbuf->rect_float;
+               satp = satbuf;
+               for (y=0; y<ibuf->y; ++y)
+                       for (x=0; x<ibuf->x; ++x) {
+                               *fp++ = (float)*satp++;
+                               *fp++ = (float)*satp++;
+                               *fp++ = (float)*satp++;
+                               *fp++ = (float)*satp++;
+                       }
+               MEM_freeN(satbuf);
+               fp = &sbuf->rect_float[(sbuf->x - 1 + (sbuf->y - 1)*sbuf->x) << 2];
+               fp[0] = avg[0];
+               fp[1] = avg[1];
+               fp[2] = avg[2];
+               fp[3] = avg[3];
+       }
+       else {
+               ImBuf *hbuf = ibuf;
+               int curmap = 0;
+               while (curmap < IB_MIPMAP_LEVELS) {
+                       if (use_filter) {
+                               ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect, 0);
+                               IMB_filterN(nbuf, hbuf);
+                               ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
+                               IMB_freeImBuf(nbuf);
+                       }
+                       else ibuf->mipmap[curmap] = IMB_onehalf(hbuf);
+                       hbuf = ibuf->mipmap[curmap];
+                       if (hbuf->x == 1 && hbuf->y == 1) break;
+                       curmap++;
+               }
+       }
+}
index 6b7bfbdcd83df5c51c856b7e3fd191da67cb5099..e1dd21a8ccb14b3e3ed1f74ec58d14f5bdf57ab4 100644 (file)
@@ -150,11 +150,13 @@ typedef struct Tex {
 
        /* newnoise: noisebasis type for clouds/marble/etc, noisebasis2 only used for distorted noise */
        short noisebasis, noisebasis2;
-       
+
        short imaflag, flag;
        short type, stype;
        
        float cropxmin, cropymin, cropxmax, cropymax;
+       int texfilter;
+       int afmax;      // anisotropic filter maximum value, ewa -> max eccentricity, feline -> max probes
        short xrepeat, yrepeat;
        short extend;
 
@@ -253,6 +255,15 @@ typedef struct TexMapping {
 #define TEX_GAUSS_MIP  4096
 #define TEX_FILTER_MIN 8192
 
+/* texfilter */
+// TXF_DEFAULT -> blender's old texture filtering method
+#define TXF_DEFAULT            0
+#define TXF_EWA                        1
+#define TXF_FELINE             2
+#define TXF_AREA               3
+// TXF_SAT only available when mipmaps disabled
+#define TXF_SAT                        4
+
 /* imaflag unused, only for version check */
 #define TEX_FIELDS_            8
 #define TEX_ANIMCYCLIC_        64
index 2573ad8394aed73fb2bee573c9e6d74ac5c25d3a..330d38502cedffbfa6656c48b7f14f83acdf5b97 100644 (file)
 
 #include "WM_types.h"
 
+static EnumPropertyItem texture_filter_items[] = {
+       {TXF_DEFAULT, "DEFAULT", 0, "Default", ""},
+       {TXF_EWA, "EWA", 0, "EWA", ""},
+       {TXF_FELINE, "FELINE", 0, "FELINE", ""},
+       {TXF_AREA, "AREA", 0, "Area", ""},
+       {TXF_SAT, "SAT", 0, "SAT (4x mem)", ""},
+       {0, NULL, 0, NULL, NULL}};
+
 #ifdef RNA_RUNTIME
 
 #include "BKE_texture.h"
@@ -110,6 +118,35 @@ static void rna_Texture_use_color_ramp_set(PointerRNA *ptr, int value)
                tex->coba= add_colorband(0);
 }
 
+static void rna_ImageTexture_mipmap_set(PointerRNA *ptr, int value)
+{
+       Tex *tex= (Tex*)ptr->data;
+
+       if(value) tex->imaflag |= TEX_MIPMAP;
+       else tex->imaflag &= ~TEX_MIPMAP;
+
+       if((tex->imaflag & TEX_MIPMAP) && tex->texfilter == TXF_SAT)
+               tex->texfilter = TXF_DEFAULT;
+}
+
+static EnumPropertyItem *rna_ImageTexture_filter_itemf(bContext *C, PointerRNA *ptr, int *free)
+{
+       Tex *tex= (Tex*)ptr->data;
+       EnumPropertyItem *item= NULL;
+       int totitem= 0;
+
+       RNA_enum_items_add_value(&item, &totitem, texture_filter_items, TXF_DEFAULT);
+       RNA_enum_items_add_value(&item, &totitem, texture_filter_items, TXF_EWA);
+       RNA_enum_items_add_value(&item, &totitem, texture_filter_items, TXF_FELINE);
+       RNA_enum_items_add_value(&item, &totitem, texture_filter_items, TXF_AREA);
+       if(tex->imaflag & TEX_MIPMAP)
+               RNA_enum_items_add_value(&item, &totitem, texture_filter_items, TXF_SAT);
+       
+       *free= 1;
+
+       return item;
+}
+
 #else
 
 static void rna_def_color_ramp_element(BlenderRNA *brna)
@@ -751,7 +788,7 @@ static void rna_def_texture_image(BlenderRNA *brna)
 
        prop= RNA_def_property(srna, "mipmap", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "imaflag", TEX_MIPMAP);
-       //RNA_def_property_boolean_funcs(prop, NULL, "rna_ImageTexture_mipmap_set");
+       RNA_def_property_boolean_funcs(prop, NULL, "rna_ImageTexture_mipmap_set");
        RNA_def_property_ui_text(prop, "MIP Map", "Uses auto-generated MIP maps for the image");
        RNA_def_property_update(prop, NC_TEXTURE, NULL);
 
@@ -889,6 +926,26 @@ static void rna_def_texture_image(BlenderRNA *brna)
        RNA_def_property_flag(prop, PROP_EDITABLE);
        RNA_def_property_ui_text(prop, "Image", "");
        RNA_def_property_update(prop, NC_TEXTURE, NULL);
+
+       /* filtering */
+       prop= RNA_def_property(srna, "filter", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "texfilter");
+       RNA_def_property_enum_items(prop, texture_filter_items);
+       RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageTexture_filter_itemf");
+       RNA_def_property_ui_text(prop, "Filter", "Texture filter to use for sampling image.");
+       RNA_def_property_update(prop, NC_TEXTURE, NULL);
+
+       prop= RNA_def_property(srna, "filter_probes", PROP_INT, PROP_NONE);
+       RNA_def_property_int_sdna(prop, NULL, "afmax");
+       RNA_def_property_range(prop, 1, 256);
+       RNA_def_property_ui_text(prop, "Filter Probes", "Maximum number of samples. Higher gives less blur at distant/oblique angles, but is also slower.");
+       RNA_def_property_update(prop, NC_TEXTURE, NULL);
+
+       prop= RNA_def_property(srna, "filter_eccentricity", PROP_INT, PROP_NONE);
+       RNA_def_property_int_sdna(prop, NULL, "afmax");
+       RNA_def_property_range(prop, 1, 256);
+       RNA_def_property_ui_text(prop, "Filter Eccentricity", "Maximum eccentricity. Higher gives less blur at distant/oblique angles, but is also slower.");
+       RNA_def_property_update(prop, NC_TEXTURE, NULL);
 }
 
 static void rna_def_texture_plugin(BlenderRNA *brna)
index b9a2acb8b1c33d647b49613a8b64ff0a2d7cedbd..743dbb72e7c95bc1ff86f524c2516176b7eb2bf6 100644 (file)
@@ -416,6 +416,107 @@ static float clipy_rctf(rctf *rf, float y1, float y2)
 
 }
 
+// used in SAT_get_color_bilerp() below
+static void SAT_getcol(float* col, ImBuf* ibuf, int x, int y)
+{
+       if ((x == (ibuf->x - 1)) && (y == (ibuf->y - 1))) {     // avg val pos
+               col[0] = col[1] = col[2] = col[3] = 0.f;
+               return;
+       }
+       ibuf_get_color(col, ibuf, x, y);
+}
+
+// used in boxsampleclip_SAT() below
+static void SAT_get_color_bilerp(float *col, ImBuf *ibuf, float u, float v)
+{
+       float c00[4], c01[4], c10[4], c11[4];
+       const float ufl = floorf(u -= 0.5f), vfl = floorf(v -= 0.5f);
+       const float uf = u - ufl, vf = v - vfl;
+       const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+       int x1 = (int)ufl, y1 = (int)vfl, x2 = x1 + 1, y2 = y1 + 1;
+       x1 = (x1 < 0) ? 0 : (x1 >= ibuf->x ? ibuf->x - 1 : x1);
+       x2 = (x2 < 0) ? 0 : (x2 >= ibuf->x ? ibuf->x - 1 : x2);
+       y1 = (y1 < 0) ? 0 : (y1 >= ibuf->y ? ibuf->y - 1 : y1);
+       y2 = (y2 < 0) ? 0 : (y2 >= ibuf->y ? ibuf->y - 1 : y2);
+       SAT_getcol(c00, ibuf, x1, y1);
+       SAT_getcol(c10, ibuf, x2, y1);
+       SAT_getcol(c01, ibuf, x1, y2);
+       SAT_getcol(c11, ibuf, x2, y2);
+       col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+       col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
+       col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
+       col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
+}
+
+static void boxsampleclip_SAT(ImBuf *ibuf, rctf *rf, TexResult *texres, int intpol)
+{
+       float div, col[4];
+       if (intpol) {
+               div = 1.f/((rf->xmax - rf->xmin + 1.f)*(rf->ymax - rf->ymin + 1.f));
+               SAT_get_color_bilerp(&texres->tr, ibuf, rf->xmax, rf->ymax);
+               if (rf->ymin >= 1.f) {
+                       SAT_get_color_bilerp(col, ibuf, rf->xmax, rf->ymin - 1.f);
+                       texres->tr -= col[0];
+                       texres->tg -= col[1];
+                       texres->tb -= col[2];
+                       texres->ta -= col[3];
+               }
+               if (rf->xmin >= 1.f) {
+                       SAT_get_color_bilerp(col, ibuf, rf->xmin - 1.f, rf->ymax);
+                       texres->tr -= col[0];
+                       texres->tg -= col[1];
+                       texres->tb -= col[2];
+                       texres->ta -= col[3];
+               }
+               if (rf->xmin >= 1.f && rf->ymin >= 1.f) {
+                       SAT_get_color_bilerp(col, ibuf, rf->xmin - 1.f, rf->ymin - 1.f);
+                       texres->tr += col[0];
+                       texres->tg += col[1];
+                       texres->tb += col[2];
+                       texres->ta += col[3];
+               }
+       }
+       else {
+               int startx = (int)floorf(rf->xmin);
+               int endx = (int)floorf(rf->xmax);
+               int starty = (int)floorf(rf->ymin);
+               int endy = (int)floorf(rf->ymax);
+               if (startx < 0) startx = 0;
+               if (starty < 0) starty = 0;
+               if (endx >= ibuf->x) endx = ibuf->x - 1;
+               if (endy >= ibuf->y) endy = ibuf->y - 1;
+               div = 1.f/((endx - startx + 1)*(endy - starty + 1));
+               SAT_getcol(&texres->tr, ibuf, endx, endy);
+               if (starty >= 1) {
+                       SAT_getcol(col, ibuf, endx, starty - 1);
+                       texres->tr -= col[0];
+                       texres->tg -= col[1];
+                       texres->tb -= col[2];
+                       texres->ta -= col[3];
+               }
+               if (startx >= 1) {
+                       SAT_getcol(col, ibuf, startx - 1, endy);
+                       texres->tr -= col[0];
+                       texres->tg -= col[1];
+                       texres->tb -= col[2];
+                       texres->ta -= col[3];
+               }
+               if (startx >=1 && starty >= 1) {
+                       SAT_getcol(col, ibuf, startx - 1, starty - 1);
+                       texres->tr += col[0];
+                       texres->tg += col[1];
+                       texres->tb += col[2];
+                       texres->ta += col[3];
+               }
+       }
+       // avg
+       ibuf_get_color(col, ibuf, ibuf->x - 1, ibuf->y - 1);
+       texres->tr = texres->tr*div + col[0];
+       texres->tg = texres->tg*div + col[1];
+       texres->tb = texres->tb*div + col[2];
+       texres->ta = texres->ta*div + col[3];
+}
+
 static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
 {
        /* sample box, is clipped already, and minx etc. have been set at ibuf size.
@@ -485,6 +586,7 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
                                }
                        }
                }
+
                if(div!=0.0) {
                        div= 1.0f/div;
                        texres->tb*= div;
@@ -498,13 +600,13 @@ static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
        }
 }
 
-static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, TexResult *texres, int imaprepeat, int imapextend)
+static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, TexResult *texres, int imaprepeat, int imapextend, int SAT, int intpol)
 {
        /* Sample box, performs clip. minx etc are in range 0.0 - 1.0 .
-     * Enlarge with antialiased edges of pixels.
-     * If variable 'imaprepeat' has been set, the
-     *  clipped-away parts are sampled as well.
-     */
+   * Enlarge with antialiased edges of pixels.
+   * If variable 'imaprepeat' has been set, the
+   * clipped-away parts are sampled as well.
+   */
        /* note: actually minx etc isnt in the proper range... this due to filter size and offset vectors for bump */
        TexResult texr;
        rctf *rf, stack[8];
@@ -552,7 +654,10 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
        if(count>1) {
                tot= texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
                while(count--) {
-                       boxsampleclip(ibuf, rf, &texr);
+                       if (SAT)
+                               boxsampleclip_SAT(ibuf, rf, &texr, intpol);
+                       else
+                               boxsampleclip(ibuf, rf, &texr);
                        
                        opp= square_rctf(rf);
                        tot+= opp;
@@ -571,7 +676,10 @@ static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float max
                }
        }
        else {
-               boxsampleclip(ibuf, rf, texres);
+               if (SAT)
+                       boxsampleclip_SAT(ibuf, rf, texres, intpol);
+               else
+                       boxsampleclip(ibuf, rf, texres);
        }
 
        if(texres->talpha==0) texres->ta= 1.0;
@@ -598,7 +706,7 @@ void image_sample(Image *ima, float fx, float fy, float dx, float dy, float *res
        if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
                ibuf->rect+= (ibuf->x*ibuf->y);
        
-       boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1);
+       boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1, 0, 0);
        result[0]= texres.tr;
        result[1]= texres.tg;
        result[2]= texres.tb;
@@ -617,7 +725,7 @@ void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float *res
        }
        
        memset(&texres, 0, sizeof(texres));
-       boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1);
+       boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1, 0, 0);
        result[0]= texres.tr;
        result[1]= texres.tg;
        result[2]= texres.tb;
@@ -625,13 +733,777 @@ void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float *res
 }
 
 
+//-----------------------------------------------------------------------------------------------------------------
+// from here, some functions only used for the new filtering
+
+// this only used here to make it easier to pass extend flags as single int
+enum {TXC_XMIR=1, TXC_YMIR, TXC_REPT, TXC_EXTD};
+
+// similar to ibuf_get_color() but clips/wraps coords according to repeat/extend flags
+// returns true if out of range in clipmode
+static int ibuf_get_color_clip(float *col, ImBuf *ibuf, int x, int y, int extflag)
+{
+       int clip = 0;
+       switch (extflag) {
+               case TXC_XMIR:  // y rep
+                       x %= 2*ibuf->x;
+                       x += x < 0 ? 2*ibuf->x : 0;
+                       x = x >= ibuf->x ? 2*ibuf->x - x - 1 : x;
+                       y %= ibuf->y;
+                       y += y < 0 ? ibuf->y : 0;
+                       break;
+               case TXC_YMIR:  // x rep
+                       x %= ibuf->x;
+                       x += x < 0 ? ibuf->x : 0;
+                       y %= 2*ibuf->y;
+                       y += y < 0 ? 2*ibuf->y : 0;
+                       y = y >= ibuf->y ? 2*ibuf->y - y - 1 : y;
+                       break;
+               case TXC_EXTD:
+                       x = (x < 0) ? 0 : ((x >= ibuf->x) ? (ibuf->x - 1) : x);
+                       y = (y < 0) ? 0 : ((y >= ibuf->y) ? (ibuf->y - 1) : y);
+                       break;
+               case TXC_REPT:
+                       x %= ibuf->x;
+                       x += (x < 0) ? ibuf->x : 0;
+                       y %= ibuf->y;
+                       y += (y < 0) ? ibuf->y : 0;
+                       break;
+               default:        {       // as extend, if clipped, set alpha to 0.0
+                       if (x < 0) { x = 0;  } // TXF alpha: clip = 1; }
+                       if (x >= ibuf->x) { x = ibuf->x - 1; } // TXF alpha:  clip = 1; }
+                       if (y < 0) { y = 0; } // TXF alpha:  clip = 1; }
+                       if (y >= ibuf->y) { y = ibuf->y - 1; } // TXF alpha:  clip = 1; }
+               }
+       }
+
+       if (ibuf->rect_float) {
+               const float* fp = ibuf->rect_float + (x + y*ibuf->x)*ibuf->channels;
+               if (ibuf->channels == 1)
+                       col[0] = col[1] = col[2] = col[3] = *fp;
+               else {
+                       col[0] = fp[0];
+                       col[1] = fp[1];
+                       col[2] = fp[2];
+                       col[3] = clip ? 0.f : (ibuf->channels == 4 ? fp[3] : 1.f);
+               }
+       }
+       else {
+               char* rect = (char*)(ibuf->rect + x + y*ibuf->x);
+               col[0] = rect[0]*(1.f/255.f);
+               col[1] = rect[1]*(1.f/255.f);
+               col[2] = rect[2]*(1.f/255.f);
+               col[3] = clip ? 0.f : rect[3]*(1.f/255.f);
+       }
+       return clip;
+}
+
+// as above + bilerp
+static int ibuf_get_color_clip_bilerp(float *col, ImBuf *ibuf, float u, float v, int intpol, int extflag)
+{
+       if (intpol) {
+               float c00[4], c01[4], c10[4], c11[4];
+               const float ufl = floorf(u -= 0.5f), vfl = floorf(v -= 0.5f);
+               const float uf = u - ufl, vf = v - vfl;
+               const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+               const int x1 = (int)ufl, y1 = (int)vfl, x2 = x1 + 1, y2 = y1 + 1;
+               int clip = ibuf_get_color_clip(c00, ibuf, x1, y1, extflag);
+               clip |= ibuf_get_color_clip(c10, ibuf, x2, y1, extflag);
+               clip |= ibuf_get_color_clip(c01, ibuf, x1, y2, extflag);
+               clip |= ibuf_get_color_clip(c11, ibuf, x2, y2, extflag);
+               col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+               col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
+               col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
+               col[3] = clip ? 0.f : w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
+               return clip;
+       }
+       return ibuf_get_color_clip(col, ibuf, (int)u, (int)v, extflag);
+}
+
+// anisotropic filters, data struct used instead of long line of (possibly unused) func args
+typedef struct afdata_t {
+       float *dxt, *dyt;
+       int intpol, extflag;
+       // feline only
+       float majrad, minrad, theta;
+       int iProbes;
+       float dusc, dvsc;
+} afdata_t;
+
+static void area_sample(TexResult* texr, ImBuf* ibuf, float fx, float fy, afdata_t* AFD)
+{
+       int xs, ys, clip = 0;
+       float tc[4], xsd, ysd, cw = 0.f;
+       const float ux = ibuf->x*AFD->dxt[0], uy = ibuf->y*AFD->dxt[1];
+       const float vx = ibuf->x*AFD->dyt[0], vy = ibuf->y*AFD->dyt[1];
+       int xsam = (int)(0.5f*sqrtf(ux*ux + uy*uy) + 0.5f);
+       int ysam = (int)(0.5f*sqrtf(vx*vx + vy*vy) + 0.5f);
+       const int minsam = AFD->intpol ? 2 : 4;
+       xsam = xsam < minsam ? minsam : xsam;
+       ysam = ysam < minsam ? minsam : ysam;
+       xsd = 1.f / xsam;
+       ysd = 1.f / ysam;
+       texr->tr = texr->tg = texr->tb = texr->ta = 0.f;
+       for (ys=0; ys<ysam; ++ys) {
+               for (xs=0; xs<xsam; ++xs) {
+                       const float su = (xs + ((ys & 1) + 0.5f)*0.5f)*xsd - 0.5f;
+                       const float sv = (ys + ((xs & 1) + 0.5f)*0.5f)*ysd - 0.5f;
+                       const float pu = fx + su*AFD->dxt[0] + sv*AFD->dyt[0];
+                       const float pv = fy + su*AFD->dxt[1] + sv*AFD->dyt[1];
+                       const int out = ibuf_get_color_clip_bilerp(tc, ibuf, pu*ibuf->x, pv*ibuf->y, AFD->intpol, AFD->extflag);
+                       clip |= out;
+                       cw += out ? 0.f : 1.f;
+                       texr->tr += tc[0];
+                       texr->tg += tc[1];
+                       texr->tb += tc[2];
+                       texr->ta += texr->talpha ? tc[3] : 0.f;
+               }
+       }
+       xsd *= ysd;
+       texr->tr *= xsd;
+       texr->tg *= xsd;
+       texr->tb *= xsd;
+       // clipping can be ignored if alpha used, texr->ta already includes filtered edge
+       texr->ta = texr->talpha ? texr->ta*xsd : (clip ? cw*xsd : 1.f);
+}
+
+// table of (exp(ar) - exp(a)) / (1 - exp(a)) for r in range [0, 1] and a = -2
+// used instead of actual gaussian, otherwise at high texture magnifications circular artifacts are visible
+#define EWA_MAXIDX 255
+static float EWA_WTS[EWA_MAXIDX + 1] =
+{ 1.f, 0.990965f, 0.982f, 0.973105f, 0.96428f, 0.955524f, 0.946836f, 0.938216f, 0.929664f,
+ 0.921178f, 0.912759f, 0.904405f, 0.896117f, 0.887893f, 0.879734f, 0.871638f, 0.863605f,
+ 0.855636f, 0.847728f, 0.839883f, 0.832098f, 0.824375f, 0.816712f, 0.809108f, 0.801564f,
+ 0.794079f, 0.786653f, 0.779284f, 0.771974f, 0.76472f, 0.757523f, 0.750382f, 0.743297f,
+ 0.736267f, 0.729292f, 0.722372f, 0.715505f, 0.708693f, 0.701933f, 0.695227f, 0.688572f,
+ 0.68197f, 0.67542f, 0.66892f, 0.662471f, 0.656073f, 0.649725f, 0.643426f, 0.637176f,
+ 0.630976f, 0.624824f, 0.618719f, 0.612663f, 0.606654f, 0.600691f, 0.594776f, 0.588906f,
+ 0.583083f, 0.577305f, 0.571572f, 0.565883f, 0.56024f, 0.55464f, 0.549084f, 0.543572f,
+ 0.538102f, 0.532676f, 0.527291f, 0.521949f, 0.516649f, 0.511389f, 0.506171f, 0.500994f,
+ 0.495857f, 0.490761f, 0.485704f, 0.480687f, 0.475709f, 0.470769f, 0.465869f, 0.461006f,
+ 0.456182f, 0.451395f, 0.446646f, 0.441934f, 0.437258f, 0.432619f, 0.428017f, 0.42345f,
+ 0.418919f, 0.414424f, 0.409963f, 0.405538f, 0.401147f, 0.39679f, 0.392467f, 0.388178f,
+ 0.383923f, 0.379701f, 0.375511f, 0.371355f, 0.367231f, 0.363139f, 0.359079f, 0.355051f,
+ 0.351055f, 0.347089f, 0.343155f, 0.339251f, 0.335378f, 0.331535f, 0.327722f, 0.323939f,
+ 0.320186f, 0.316461f, 0.312766f, 0.3091f, 0.305462f, 0.301853f, 0.298272f, 0.294719f,
+ 0.291194f, 0.287696f, 0.284226f, 0.280782f, 0.277366f, 0.273976f, 0.270613f, 0.267276f,
+ 0.263965f, 0.26068f, 0.257421f, 0.254187f, 0.250979f, 0.247795f, 0.244636f, 0.241502f,
+ 0.238393f, 0.235308f, 0.232246f, 0.229209f, 0.226196f, 0.223206f, 0.220239f, 0.217296f,
+ 0.214375f, 0.211478f, 0.208603f, 0.20575f, 0.20292f, 0.200112f, 0.197326f, 0.194562f,
+ 0.191819f, 0.189097f, 0.186397f, 0.183718f, 0.18106f, 0.178423f, 0.175806f, 0.17321f,
+ 0.170634f, 0.168078f, 0.165542f, 0.163026f, 0.16053f, 0.158053f, 0.155595f, 0.153157f,
+ 0.150738f, 0.148337f, 0.145955f, 0.143592f, 0.141248f, 0.138921f, 0.136613f, 0.134323f,
+ 0.132051f, 0.129797f, 0.12756f, 0.125341f, 0.123139f, 0.120954f, 0.118786f, 0.116635f,
+ 0.114501f, 0.112384f, 0.110283f, 0.108199f, 0.106131f, 0.104079f, 0.102043f, 0.100023f,
+ 0.0980186f, 0.09603f, 0.094057f, 0.0920994f, 0.0901571f, 0.08823f, 0.0863179f, 0.0844208f,
+ 0.0825384f, 0.0806708f, 0.0788178f, 0.0769792f, 0.0751551f, 0.0733451f, 0.0715493f, 0.0697676f,
+ 0.0679997f, 0.0662457f, 0.0645054f, 0.0627786f, 0.0610654f, 0.0593655f, 0.0576789f, 0.0560055f,
+ 0.0543452f, 0.0526979f, 0.0510634f, 0.0494416f, 0.0478326f, 0.0462361f, 0.0446521f, 0.0430805f,
+ 0.0415211f, 0.039974f, 0.0384389f, 0.0369158f, 0.0354046f, 0.0339052f, 0.0324175f, 0.0309415f,
+ 0.029477f, 0.0280239f, 0.0265822f, 0.0251517f, 0.0237324f, 0.0223242f, 0.020927f, 0.0195408f,
+ 0.0181653f, 0.0168006f, 0.0154466f, 0.0141031f, 0.0127701f, 0.0114476f, 0.0101354f, 0.00883339f,
+ 0.00754159f, 0.00625989f, 0.00498819f, 0.00372644f, 0.00247454f, 0.00123242f, 0.f
+};
+
+// test if a float value is 'nan'
+// there is a C99 function for this: isnan(), but blender seems to use C90 (according to gcc warns),
+// and may not be supported by other compilers either
+#ifndef ISNAN
+#define ISNAN(x) ((x) != (x))
+#endif
+//static int ISNAN(float x) { return (x != x); }
+
+static void radangle2imp(float a2, float b2, float th, float* A, float* B, float* C, float* F)
+{
+       float ct2 = cosf(th);
+       const float st2 = 1.f - ct2*ct2;        // <- sin(th)^2
+       ct2 *= ct2;
+       *A = a2*st2 + b2*ct2;
+       *B = (b2 - a2)*sinf(2.f*th);
+       *C = a2*ct2 + b2*st2;
+       *F = a2*b2;
+}
+
+// all tests here are done to make sure possible overflows are hopefully minimized
+static void imp2radangle(float A, float B, float C, float F, float* a, float* b, float* th, float* ecc)
+{
+       if (F <= 1e-5f) {       // use arbitrary major radius, zero minor, infinite eccentricity
+               *a = sqrtf(A > C ? A : C);
+               *b = 0.f;
+               *ecc = 1e10f;
+               *th = 0.5f*(atan2f(B, A - C) + (float)M_PI);
+       }
+       else {
+               const float AmC = A - C, ApC = A + C, F2 = F*2.f;
+               const float r = sqrtf(AmC*AmC + B*B);
+               float d = ApC - r;
+               *a = (d <= 0.f) ? sqrtf(A > C ? A : C) : sqrtf(F2 / d);
+               d = ApC + r;
+               if (d <= 0.f) {
+                       *b = 0.f;
+                       *ecc = 1e10f;
+               }
+               else {
+                       *b = sqrtf(F2 / d);
+                       *ecc = *a / *b;
+               }
+               // incr theta by 0.5*pi (angle of major axis)
+               *th = 0.5f*(atan2f(B, AmC) + (float)M_PI);
+       }
+}
+
+static void ewa_eval(TexResult* texr, ImBuf* ibuf, float fx, float fy, afdata_t* AFD)
+{
+       // scaling dxt/dyt by full resolution can cause overflow because of huge A/B/C and esp. F values,
+       // scaling by aspect ratio alone does the opposite, so try something inbetween instead...
+       const float ff2 = ibuf->x, ff = sqrtf(ff2), q = ibuf->y / ff;
+       const float Ux = AFD->dxt[0]*ff, Vx = AFD->dxt[1]*q, Uy = AFD->dyt[0]*ff, Vy = AFD->dyt[1]*q;
+       float A = Vx*Vx + Vy*Vy;
+       float B = -2.f*(Ux*Vx + Uy*Vy);
+       float C = Ux*Ux + Uy*Uy;
+       float F = A*C - B*B*0.25f;
+       float a, b, th, ecc, a2, b2, ue, ve, U0, V0, DDQ, U, ac1, ac2, BU, d; // TXF alpha: cw = 0.f;
+       int u, v, u1, u2, v1, v2; // TXF alpha: clip = 0;
+
+       // The so-called 'high' quality ewa method simply adds a constant of 1 to both A & C,
+       // so the ellipse always covers at least some texels. But since the filter is now always larger,
+       // it also means that everywhere else it's also more blurry then ideally should be the case.
+       // So instead here the ellipse radii are modified instead whenever either is too low.
+       // Use a different radius based on interpolation switch, just enough to anti-alias when interpolation is off,
+       // and slightly larger to make result a bit smoother than bilinear interpolation when interpolation is on
+       // (minimum values: const float rmin = intpol ? 1.f : 0.5f;)
+       const float rmin = (AFD->intpol ? 1.5625f : 0.765625f)/ff2;
+       imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
+       if ((b2 = b*b) < rmin) {
+               if ((a2 = a*a) < rmin) {
+                       B = 0.f;
+                       A = C = rmin;
+                       F = A*C;
+               }
+               else {
+                       b2 = rmin;
+                       radangle2imp(a2, b2, th, &A, &B, &C, &F);
+               }
+       }
+
+       ue = ff*sqrtf(C);
+       ve = ff*sqrtf(A);
+       d = (float)(EWA_MAXIDX + 1) / (F*ff2);
+       A *= d;
+       B *= d;
+       C *= d;
+
+       U0 = fx*ibuf->x;
+       V0 = fy*ibuf->y;
+       u1 = (int)(floorf(U0 - ue));
+       u2 = (int)(ceilf(U0 + ue));
+       v1 = (int)(floorf(V0 - ve));
+       v2 = (int)(ceilf(V0 + ve));
+       U0 -= 0.5f;
+       V0 -= 0.5f;
+       DDQ = 2.f*A;
+       U = u1 - U0;
+       ac1 = A*(2.f*U + 1.f);
+       ac2 = A*U*U;
+       BU = B*U;
+
+       d = texr->tr = texr->tb = texr->tg = texr->ta = 0.f;
+       for (v=v1; v<=v2; ++v) {
+               const float V = v - V0;
+               float DQ = ac1 + B*V;
+               float Q = (C*V + BU)*V + ac2;
+               for (u=u1; u<=u2; ++u) {
+                       if (Q < (float)(EWA_MAXIDX + 1)) {
+                               float tc[4];
+                               const float wt = EWA_WTS[(Q < 0.f) ? 0 : (unsigned int)Q];
+                               /*const int out =*/ ibuf_get_color_clip(tc, ibuf, u, v, AFD->extflag);
+                               // TXF alpha: clip |= out;
+                               // TXF alpha: cw += out ? 0.f : wt;
+                               texr->tr += tc[0]*wt;
+                               texr->tg += tc[1]*wt;
+                               texr->tb += tc[2]*wt;
+                               texr->ta += texr->talpha ? tc[3]*wt : 0.f;
+                               d += wt;
+                       }
+                       Q += DQ;
+                       DQ += DDQ;
+               }
+       }
+
+       // d should hopefully never be zero anymore
+       d = 1.f/d;
+       texr->tr *= d;
+       texr->tg *= d;
+       texr->tb *= d;
+       // clipping can be ignored if alpha used, texr->ta already includes filtered edge
+       texr->ta = texr->talpha ? texr->ta*d : 1.f; // TXF alpha (clip ? cw*d : 1.f);
+}
+
+static void feline_eval(TexResult* texr, ImBuf* ibuf, float fx, float fy, afdata_t* AFD)
+{
+       const int maxn = AFD->iProbes - 1;
+       const float ll = ((AFD->majrad == AFD->minrad) ? 2.f*AFD->majrad : 2.f*(AFD->majrad - AFD->minrad)) / (maxn ? (float)maxn : 1.f);
+       float du = maxn ? cosf(AFD->theta)*ll : 0.f;
+       float dv = maxn ? sinf(AFD->theta)*ll : 0.f;
+       //const float D = -0.5f*(du*du + dv*dv) / (AFD->majrad*AFD->majrad);
+       const float D = (EWA_MAXIDX + 1)*0.25f*(du*du + dv*dv) / (AFD->majrad*AFD->majrad);
+       float d; // TXF alpha: cw = 0.f;
+       int n; // TXF alpha: clip = 0;
+       // have to use same scaling for du/dv here as for Ux/Vx/Uy/Vy (*after* D calc.)
+       du *= AFD->dusc;
+       dv *= AFD->dvsc;
+       d = texr->tr = texr->tb = texr->tg = texr->ta = 0.f;
+       for (n=-maxn; n<=maxn; n+=2) {
+               float tc[4];
+               const float hn = n*0.5f;
+               const float u = fx + hn*du, v = fy + hn*dv;
+               //const float wt = expf(n*n*D);
+               // can use ewa table here too
+               const float wt = EWA_WTS[(int)(n*n*D)];
+               /*const int out =*/ ibuf_get_color_clip_bilerp(tc, ibuf, ibuf->x*u, ibuf->y*v, AFD->intpol, AFD->extflag);
+               // TXF alpha: clip |= out;
+               // TXF alpha: cw += out ? 0.f : wt;
+               texr->tr += tc[0]*wt;
+               texr->tg += tc[1]*wt;
+               texr->tb += tc[2]*wt;
+               texr->ta += texr->talpha ? tc[3]*wt : 0.f;
+               d += wt;
+       }
+
+       d = 1.f/d;
+       texr->tr *= d;
+       texr->tg *= d;
+       texr->tb *= d;
+       // clipping can be ignored if alpha used, texr->ta already includes filtered edge
+       texr->ta = texr->talpha ? texr->ta*d : 1.f; // TXF alpha: (clip ? cw*d : 1.f);
+}
+#undef EWA_MAXIDX
+
+static void alpha_clip_aniso(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, int extflag, TexResult *texres)
+{
+       float alphaclip;
+       rctf rf;
+
+       // TXF apha: we're doing the same alphaclip here as boxsample, but i'm doubting
+       // if this is actually correct for the all the filtering algorithms ..
+
+       if(!(extflag == TXC_REPT || extflag == TXC_EXTD)) {
+               rf.xmin= minx*(ibuf->x);
+               rf.xmax= maxx*(ibuf->x);
+               rf.ymin= miny*(ibuf->y);
+               rf.ymax= maxy*(ibuf->y);
+   
+               alphaclip = clipx_rctf(&rf, 0.0, (float)(ibuf->x));
+               alphaclip*= clipy_rctf(&rf, 0.0, (float)(ibuf->y));
+               alphaclip= MAX2(alphaclip, 0.0f);
+
+               if(alphaclip!=1.0) {
+                       /* premul it all */
+                       texres->tr*= alphaclip;
+                       texres->tg*= alphaclip;
+                       texres->tb*= alphaclip;
+                       texres->ta*= alphaclip;
+               }
+       }
+}
+
+static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, float *dyt, TexResult *texres)
+{
+       TexResult texr;
+       float fx, fy, minx, maxx, miny, maxy;
+       float maxd, val1, val2, val3;
+       int curmap, retval, intpol, extflag = 0;
+       afdata_t AFD;
+
+       void (*filterfunc)(TexResult*, ImBuf*, float, float, afdata_t*);
+       switch (tex->texfilter) {
+               case TXF_EWA:
+                       filterfunc = ewa_eval;
+                       break;
+               case TXF_FELINE:
+                       filterfunc = feline_eval;
+                       break;
+               case TXF_AREA:
+               default:
+                       filterfunc = area_sample;
+       }
+
+       texres->tin = texres->ta = texres->tr = texres->tg = texres->tb = 0.f;
+
+       // we need to set retval OK, otherwise texture code generates normals itself...
+       retval = texres->nor ? 3 : 1;
+
+       // quick tests
+       if (ibuf==NULL && ima==NULL) return retval;
+
+       if (ima) {      // hack for icon render
+               if ((ima->ibufs.first == NULL) && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval;
+               ibuf = BKE_image_get_ibuf(ima, &tex->iuser); 
+       }
+
+       if ((ibuf == NULL) || ((ibuf->rect == NULL) && (ibuf->rect_float == NULL))) return retval;
+
+       // mipmap test
+       if (tex->imaflag & TEX_MIPMAP) {
+               if (((ibuf->flags & IB_fields) == 0) && (ibuf->mipmap[0] == NULL)) {
+                       BLI_lock_thread(LOCK_IMAGE);
+                       if (ibuf->mipmap[0] == NULL) IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP, 0);
+                       BLI_unlock_thread(LOCK_IMAGE);
+               }
+       }
+
+       if ((tex->imaflag & TEX_USEALPHA) && ((tex->imaflag & TEX_CALCALPHA) == 0)) texres->talpha = 1;
+       texr.talpha = texres->talpha;
+
+       if (tex->imaflag & TEX_IMAROT) {
+               fy = texvec[0];
+               fx = texvec[1];
+       }
+       else {
+               fx = texvec[0];
+               fy = texvec[1];
+       }
+
+       if (ibuf->flags & IB_fields) {
+               if (R.r.mode & R_FIELDS) {                      /* field render */
+                       if (R.flag & R_SEC_FIELD) {             /* correction for 2nd field */
+                               /* fac1= 0.5/( (float)ibuf->y ); */
+                               /* fy-= fac1; */
+                       }
+                       else    /* first field */
+                               fy += 0.5f/( (float)ibuf->y );
+               }
+       }
+
+       // pixel coordinates
+       minx = MIN3(dxt[0], dyt[0], dxt[0] + dyt[0]);
+       maxx = MAX3(dxt[0], dyt[0], dxt[0] + dyt[0]);
+       miny = MIN3(dxt[1], dyt[1], dxt[1] + dyt[1]);
+       maxy = MAX3(dxt[1], dyt[1], dxt[1] + dyt[1]);
+
+       // tex_sharper has been removed
+       minx = (maxx - minx)*0.5f;
+       miny = (maxy - miny)*0.5f;
+
+       if (tex->imaflag & TEX_FILTER_MIN) {
+               // make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy)
+               const float addval = (0.5f * tex->filtersize) / (float)MIN2(ibuf->x, ibuf->y);
+               if (addval > minx) minx = addval;
+               if (addval > miny) miny = addval;
+       }
+       else if (tex->filtersize != 1.f) {
+               minx *= tex->filtersize;
+               miny *= tex->filtersize;
+               dxt[0] *= tex->filtersize;
+               dxt[1] *= tex->filtersize;
+               dyt[0] *= tex->filtersize;
+               dyt[1] *= tex->filtersize;
+       }
+
+       if (tex->imaflag & TEX_IMAROT) {
+               float t;
+               SWAP(float, minx, miny);
+               // must rotate dxt/dyt 90 deg
+               // yet another blender problem is that swapping X/Y axes (or any tex proj switches) should do something similar,
+               // but it doesn't, it only swaps coords, so filter area will be incorrect in those cases.
+               t = dxt[0];
+               dxt[0] = dxt[1];
+               dxt[1] = -t;
+               t = dyt[0];
+               dyt[0] = dyt[1];
+               dyt[1] = -t;
+       }
+
+       // side faces of unit-cube
+       minx = (minx > 0.25f) ? 0.25f : ((minx < 1e-5f) ? 1e-5 : minx);
+       miny = (miny > 0.25f) ? 0.25f : ((miny < 1e-5f) ? 1e-5 : miny);
+
+       // repeat and clip
+
+       if (tex->extend == TEX_REPEAT) {
+               if ((tex->flag & (TEX_REPEAT_XMIR | TEX_REPEAT_YMIR)) == (TEX_REPEAT_XMIR | TEX_REPEAT_YMIR))
+                       extflag = TXC_EXTD;
+               else if (tex->flag & TEX_REPEAT_XMIR)
+                       extflag = TXC_XMIR;
+               else if (tex->flag & TEX_REPEAT_YMIR)
+                       extflag = TXC_YMIR;
+               else
+                       extflag = TXC_REPT;
+       }
+       else if (tex->extend == TEX_EXTEND)
+               extflag = TXC_EXTD;
+
+       if (tex->extend == TEX_CHECKER) {
+               int xs = (int)floorf(fx), ys = (int)floorf(fy);
+               // both checkers available, no boundary exceptions, checkerdist will eat aliasing
+               if ((tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN)) {
+                       fx -= xs;
+                       fy -= ys;
+               }
+               else {
+                       int xs1 = (int)floorf(fx - minx);
+                       int ys1 = (int)floorf(fy - miny);
+                       int xs2 = (int)floorf(fx + minx);
+                       int ys2 = (int)floorf(fy + miny);
+                       if ((xs1 != xs2) || (ys1 != ys2)) {
+                               if (tex->flag & TEX_CHECKER_ODD) {
+                                       fx -= ((xs1 + ys) & 1) ? xs2 : xs1;
+                                       fy -= ((ys1 + xs) & 1) ? ys2 : ys1;
+                               }
+                               if (tex->flag & TEX_CHECKER_EVEN) {
+                                       fx -= ((xs1 + ys) & 1) ? xs1 : xs2;
+                                       fy -= ((ys1 + xs) & 1) ? ys1 : ys2;
+                               }
+                       }
+                       else {
+                               if ((tex->flag & TEX_CHECKER_ODD) == 0 && ((xs + ys) & 1) == 0) return retval;
+                               if ((tex->flag & TEX_CHECKER_EVEN) == 0 && (xs + ys) & 1) return retval;
+                               fx -= xs;
+                               fy -= ys;
+                       }
+               }
+               // scale around center, (0.5, 0.5)
+               if (tex->checkerdist < 1.f) {
+                       const float omcd = 1.f / (1.f - tex->checkerdist);
+                       fx = (fx - 0.5f)*omcd + 0.5f;
+                       fy = (fy - 0.5f)*omcd + 0.5f;
+                       minx *= omcd;
+                       miny *= omcd;
+               }
+       }
+
+       if (tex->extend == TEX_CLIPCUBE) {
+               if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f || texvec[2] < -1.f || texvec[2] > 1.f) return retval;
+       }
+       else if (tex->extend == TEX_CLIP || tex->extend == TEX_CHECKER) {
+               if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f) return retval;
+       }
+       else {
+               if (tex->extend == TEX_EXTEND) {
+                       fx = (fx > 1.f) ? 1.f : ((fx < 0.f) ? 0.f : fx);
+                       fy = (fy > 1.f) ? 1.f : ((fy < 0.f) ? 0.f : fy);
+               }
+               else {
+                       fx -= floorf(fx);
+                       fy -= floorf(fy);
+               }
+       }
+
+       intpol = tex->imaflag & TEX_INTERPOL;
+
+       // warning no return!
+       if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
+               ibuf->rect += ibuf->x*ibuf->y;
+
+       // struct common data
+       AFD.dxt = dxt;
+       AFD.dyt = dyt;
+       AFD.intpol = intpol;
+       AFD.extflag = extflag;
+
+       // choice:
+       if (tex->imaflag & TEX_MIPMAP) {
+               ImBuf *previbuf, *curibuf;
+               float levf;
+               int maxlev;
+               ImBuf* mipmaps[IB_MIPMAP_LEVELS + 1];
+
+               // modify ellipse minor axis if too eccentric, use for area sampling as well
+               // scaling dxt/dyt as done in pbrt is not the same
+               // (as in ewa_eval(), scale by sqrt(ibuf->x) to maximize precision)
+               const float ff = sqrtf(ibuf->x), q = ibuf->y/ff;
+               const float Ux = dxt[0]*ff, Vx = dxt[1]*q, Uy = dyt[0]*ff, Vy = dyt[1]*q;
+               const float A = Vx*Vx + Vy*Vy;
+               const float B = -2.f*(Ux*Vx + Uy*Vy);
+               const float C = Ux*Ux + Uy*Uy;
+               const float F = A*C - B*B*0.25f;
+               float a, b, th, ecc;
+               imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
+               if (tex->texfilter == TXF_FELINE) {
+                       float fProbes;
+                       a *= ff;
+                       b *= ff;
+                       a = MAX2(a, 1.f);
+                       b = MAX2(b, 1.f);
+                       fProbes = 2.f*(a / b) - 1.f;
+                       AFD.iProbes = (int)floorf(fProbes + 0.5f);
+                       AFD.iProbes = MIN2(AFD.iProbes, tex->afmax);
+                       if (AFD.iProbes < fProbes)
+                               b = 2.f*a / (float)(AFD.iProbes + 1);
+                       AFD.majrad = a/ff;
+                       AFD.minrad = b/ff;
+                       AFD.theta = th;
+                       AFD.dusc = 1.f/ff;
+                       AFD.dvsc = ff / (float)ibuf->y;
+               }
+               else {  // EWA & area
+                       if (ecc > (float)tex->afmax) b = a / (float)tex->afmax;
+                       b *= ff;
+               }
+               maxd = MAX2(b, 1e-8f);
+               levf = logf(maxd)*(float)M_LOG2E;
+
+               curmap = 0;
+               maxlev = 1;
+               mipmaps[0] = ibuf;
+               while (curmap < IB_MIPMAP_LEVELS) {
+                       mipmaps[curmap + 1] = ibuf->mipmap[curmap];
+                       if (ibuf->mipmap[curmap]) maxlev++;
+                       curmap++;
+               }
+
+               // mipmap level
+               if (levf < 0.f) {       // original image only
+                       previbuf = curibuf = mipmaps[0];
+                       levf = 0.f;
+               }
+               else if (levf >= maxlev - 1) {
+                       previbuf = curibuf = mipmaps[maxlev - 1];
+                       levf = 0.f;
+                       if (tex->texfilter == TXF_FELINE) AFD.iProbes = 1;
+               }
+               else {
+                       const int lev = ISNAN(levf) ? 0 : (int)levf;
+                       curibuf = mipmaps[lev];
+                       previbuf = mipmaps[lev + 1];
+                       levf -= floorf(levf);
+               }
+
+               // filter functions take care of interpolation themselves, no need to modify dxt/dyt here
+
+               if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
+                       // color & normal
+                       filterfunc(texres, curibuf, fx, fy, &AFD);
+                       val1 = texres->tr + texres->tg + texres->tb;
+                       filterfunc(&texr, curibuf, fx + dxt[0], fy + dxt[1], &AFD);
+                       val2 = texr.tr + texr.tg + texr.tb;
+                       filterfunc(&texr, curibuf, fx + dyt[0], fy + dyt[1], &AFD);
+                       val3 = texr.tr + texr.tg + texr.tb;
+                       // don't switch x or y!
+                       texres->nor[0] = val1 - val2;
+                       texres->nor[1] = val1 - val3;
+                       if (previbuf != curibuf) {  // interpolate
+                               filterfunc(&texr, previbuf, fx, fy, &AFD);
+                               // rgb
+                               texres->tr += levf*(texr.tr - texres->tr);
+                               texres->tg += levf*(texr.tg - texres->tg);
+                               texres->tb += levf*(texr.tb - texres->tb);
+                               texres->ta += levf*(texr.ta - texres->ta);
+                               // normal
+                               val1 += levf*((texr.tr + texr.tg + texr.tb) - val1);
+                               filterfunc(&texr, previbuf, fx + dxt[0], fy + dxt[1], &AFD);
+                               val2 += levf*((texr.tr + texr.tg + texr.tb) - val2);
+                               filterfunc(&texr, previbuf, fx + dyt[0], fy + dyt[1], &AFD);
+                               val3 += levf*((texr.tr + texr.tg + texr.tb) - val3);
+                               texres->nor[0] = val1 - val2;   // vals have been interpolated above!
+                               texres->nor[1] = val1 - val3;
+                       }
+               }
+               else {  // color
+                       filterfunc(texres, curibuf, fx, fy, &AFD);
+                       if (previbuf != curibuf) {  // interpolate
+                               filterfunc(&texr, previbuf, fx, fy, &AFD);
+                               texres->tr += levf*(texr.tr - texres->tr);
+                               texres->tg += levf*(texr.tg - texres->tg);
+                               texres->tb += levf*(texr.tb - texres->tb);
+                               texres->ta += levf*(texr.ta - texres->ta);
+                       }
+
+                       alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
+               }
+       }
+       else {  // no mipmap
+               // filter functions take care of interpolation themselves, no need to modify dxt/dyt here
+               if (tex->texfilter == TXF_FELINE) {
+                       const float ff = sqrtf(ibuf->x), q = ibuf->y/ff;
+                       const float Ux = dxt[0]*ff, Vx = dxt[1]*q, Uy = dyt[0]*ff, Vy = dyt[1]*q;
+                       const float A = Vx*Vx + Vy*Vy;
+                       const float B = -2.f*(Ux*Vx + Uy*Vy);
+                       const float C = Ux*Ux + Uy*Uy;
+                       const float F = A*C - B*B*0.25f;
+                       float a, b, th, ecc, fProbes;
+                       imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
+                       a *= ff;
+                       b *= ff;
+                       a = MAX2(a, 1.f);
+                       b = MAX2(b, 1.f);
+                       fProbes = 2.f*(a / b) - 1.f;
+                       // no limit to number of Probes here
+                       AFD.iProbes = (int)floorf(fProbes + 0.5f);
+                       if (AFD.iProbes < fProbes) b = 2.f*a / (float)(AFD.iProbes + 1);
+                       AFD.majrad = a/ff;
+                       AFD.minrad = b/ff;
+                       AFD.theta = th;
+                       AFD.dusc = 1.f/ff;
+                       AFD.dvsc = ff / (float)ibuf->y;
+               }
+               if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
+                       // color & normal
+                       filterfunc(texres, ibuf, fx, fy, &AFD);
+                       val1 = texres->tr + texres->tg + texres->tb;
+                       filterfunc(&texr, ibuf, fx + dxt[0], fy + dxt[1], &AFD);
+                       val2 = texr.tr + texr.tg + texr.tb;
+                       filterfunc(&texr, ibuf, fx + dyt[0], fy + dyt[1], &AFD);
+                       val3 = texr.tr + texr.tg + texr.tb;
+                       // don't switch x or y!
+                       texres->nor[0] = val1 - val2;
+                       texres->nor[1] = val1 - val3;
+               }
+               else {
+                       filterfunc(texres, ibuf, fx, fy, &AFD);
+                       alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
+               }
+       }
+
+       BRICONTRGB;
+
+       if (tex->imaflag & TEX_CALCALPHA)
+               texres->ta = texres->tin = texres->ta * MAX3(texres->tr, texres->tg, texres->tb);
+       else
+               texres->tin = texres->ta;
+       if (tex->flag & TEX_NEGALPHA) texres->ta = 1.f - texres->ta;
+       
+       if ((R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields))
+               ibuf->rect -= ibuf->x*ibuf->y;
+
+       if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {    // normal from color
+               texres->nor[0] = 2.f*(texres->tr - 0.5f);
+               texres->nor[1] = 2.f*(0.5f - texres->tg);
+               texres->nor[2] = 2.f*(texres->tb - 0.5f);
+       }
+       
+       // de-premul, this is being premulled in shade_input_do_shade()
+       // TXF: this currently does not (yet?) work properly, destroys edge AA in clip/checker mode, so for now commented out
+       // also disabled in imagewraposa() to be able to compare results with blender's default texture filtering
+
+       // brecht: tried to fix this, see "TXF alpha" comments
+
+       if (texres->ta != 1.f && (texres->ta > FLT_EPSILON)) {
+               fx = 1.f/texres->ta;
+               texres->tr *= fx;
+               texres->tg *= fx;
+               texres->tb *= fx;
+       }
+
+       return retval;
+}
 
-int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, float *dyt, TexResult *texres)
+
+int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *DXT, float *DYT, TexResult *texres)
 {
        TexResult texr;
-       float fx, fy, minx, maxx, miny, maxy, dx, dy;
+       float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[3], dyt[3];
        float maxd, pixsize, val1, val2, val3;
-       int curmap, retval, imaprepeat, imapextend;
+       int curmap, retval, imaprepeat, imapextend, SAT = (tex->texfilter == TXF_SAT);
+
+       // TXF: since dxt/dyt might be modified here and since they might be needed after imagewraposa() call,
+       // make a local copy here so that original vecs remain untouched
+       VECCOPY(dxt, DXT);
+       VECCOPY(dyt, DYT);
+
+       // anisotropic filtering
+       if (!SAT && (tex->texfilter != TXF_DEFAULT))
+               return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres);
 
        texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
        
@@ -653,13 +1525,13 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
           return retval;
        
        /* mipmap test */
-       if(tex->imaflag & TEX_MIPMAP) {
+       if (SAT || tex->imaflag & TEX_MIPMAP) {
                if(ibuf->flags & IB_fields);
                else if(ibuf->mipmap[0]==NULL) {
                        BLI_lock_thread(LOCK_IMAGE);
                        
                        if(ibuf->mipmap[0]==NULL)
-                               IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
+                               IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP, SAT);
 
                        BLI_unlock_thread(LOCK_IMAGE);
                }
@@ -871,11 +1743,11 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
                        //minx*= 1.35f;
                        //miny*= 1.35f;
                        
-                       boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
+                       boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, 0, 0);
                        val1= texres->tr+texres->tg+texres->tb;
-                       boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
+                       boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend, 0, 0);
                        val2= texr.tr + texr.tg + texr.tb;
-                       boxsample(curibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
+                       boxsample(curibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend, 0, 0);
                        val3= texr.tr + texr.tg + texr.tb;
 
                        /* don't switch x or y! */
@@ -884,7 +1756,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
                        
                        if(previbuf!=curibuf) {  /* interpolate */
                                
-                               boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend);
+                               boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend, 0, 0);
                                
                                /* calc rgb */
                                dx= 2.0f*(pixsize-maxd)/pixsize;
@@ -901,9 +1773,9 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
                                }
                                
                                val1= dy*val1+ dx*(texr.tr + texr.tg + texr.tb);
-                               boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
+                               boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend, 0, 0);
                                val2= dy*val2+ dx*(texr.tr + texr.tg + texr.tb);
-                               boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
+                               boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend, 0, 0);
                                val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb);
                                
                                texres->nor[0]= (val1-val2);    /* vals have been interpolated above! */
@@ -926,10 +1798,10 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
                        maxy= fy+miny;
                        miny= fy-miny;
 
-                       boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
+                       boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend, 0, 0);
 
                        if(previbuf!=curibuf) {  /* interpolate */
-                               boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
+                               boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend, 0, 0);
                                
                                fx= 2.0f*(pixsize-maxd)/pixsize;
                                
@@ -947,26 +1819,39 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, f
                }
        }
        else {
-               if((tex->imaflag & TEX_INTERPOL)) {
+               const int intpol = tex->imaflag & TEX_INTERPOL;
+               if (intpol && !SAT) {
                        /* sample 1 pixel minimum */
                        if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
                        if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
                }
 
                if(texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
-                       
-                       boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
-                       val1= texres->tr+texres->tg+texres->tb;
-                       boxsample(ibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
-                       val2= texr.tr + texr.tg + texr.tb;
-                       boxsample(ibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
-                       val3= texr.tr + texr.tg + texr.tb;
+                       if (SAT) {
+                               boxsample(ibuf->mipmap[0], fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, 1, intpol);
+                               val1 = texres->tr + texres->tg + texres->tb;
+                               boxsample(ibuf->mipmap[0], fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend, 1, intpol);
+                               val2 = texr.tr + texr.tg + texr.tb;
+                               boxsample(ibuf->mipmap[0], fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend, 1, intpol);
+                               val3 = texr.tr + texr.tg + texr.tb;
+                       }
+                       else {
+                               boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, 0, 0);
+                               val1= texres->tr+texres->tg+texres->tb;
+                               boxsample(ibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend, 0, 0);
+                               val2= texr.tr + texr.tg + texr.tb;
+                               boxsample(ibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend, 0, 0);
+                               val3= texr.tr + texr.tg + texr.tb;
+                       }
                        /* don't switch x or y! */
                        texres->nor[0]= (val1-val2);
                        texres->nor[1]= (val1-val3);
                }
                else {
-                       boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
+                       if (SAT)
+                               boxsample(ibuf->mipmap[0], fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, 1, intpol);
+                       else
+                               boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend, 0, 0);
                }
        }
        
index e11bb0004b25cbace6fe9c1c51b3ad143b76490e..9466bd454208b33e4555d82101bfcff0e8ef8466 100644 (file)
@@ -984,7 +984,7 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                                
                                if(tex->flag & TEX_REPEAT_XMIR) {
                                        int orig= (int)floor(origf);
-                                       if(orig & 1) 
+                                       if(orig & 1)
                                                fx= 1.0-fx;
                                }
                        }
@@ -1077,13 +1077,15 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                                dxt[2]= f1;
                                dyt[2]= f2;
                        }
-                       dxt[0]/= 2.0; 
-                       dxt[1]/= 2.0;
-                       dxt[2]/= 2.0;
-                       
-                       dyt[0]/= 2.0; 
-                       dyt[1]/= 2.0;
-                       dyt[2]/= 2.0;
+
+                       dxt[0] *= 0.5f;
+                       dxt[1] *= 0.5f;
+                       dxt[2] *= 0.5f;
+
+                       dyt[0] *= 0.5f;
+                       dyt[1] *= 0.5f;
+                       dyt[2] *= 0.5f;
+
                }
                
                /* if area, then reacalculate dxt[] and dyt[] */
@@ -1102,13 +1104,16 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                        if(tex->xrepeat>1) {
                                float origf= fx *= tex->xrepeat;
                                
-                               if(fx>1.0f) fx -= (int)(fx);
-                               else if(fx<0.0f) fx+= 1-(int)(fx);
+                               // TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call
+                               if (tex->texfilter == TXF_DEFAULT) {
+                                       if(fx>1.0f) fx -= (int)(fx);
+                                       else if(fx<0.0f) fx+= 1-(int)(fx);
                                
-                               if(tex->flag & TEX_REPEAT_XMIR) {
-                                       int orig= (int)floor(origf);
-                                       if(orig & 1) 
-                                               fx= 1.0f-fx;
+                                       if(tex->flag & TEX_REPEAT_XMIR) {
+                                               int orig= (int)floor(origf);
+                                               if(orig & 1) 
+                                                       fx= 1.0f-fx;
+                                       }
                                }
                                
                                max= tex->xrepeat;
@@ -1119,13 +1124,16 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *n, float *d
                        if(tex->yrepeat>1) {
                                float origf= fy *= tex->yrepeat;
                                
-                               if(fy>1.0f) fy -= (int)(fy);
-                               else if(fy<0.0f) fy+= 1-(int)(fy);
+                               // TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call
+                               if (tex->texfilter == TXF_DEFAULT) {
+                                       if(fy>1.0f) fy -= (int)(fy);
+                                       else if(fy<0.0f) fy+= 1-(int)(fy);
                                
-                               if(tex->flag & TEX_REPEAT_YMIR) {
-                                       int orig= (int)floor(origf);
-                                       if(orig & 1) 
-                                               fy= 1.0f-fy;
+                                       if(tex->flag & TEX_REPEAT_YMIR) {
+                                               int orig= (int)floor(origf);
+                                               if(orig & 1) 
+                                                       fy= 1.0f-fy;
+                                       }
                                }
                                
                                if(max<tex->yrepeat)
@@ -1200,7 +1208,7 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex,
                retval= texnoise(tex, texres); 
                break;
        case TEX_IMAGE:
-               if(osatex) retval= imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres); 
+               if(osatex) retval= imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres);
                else retval= imagewrap(tex, tex->ima, NULL, texvec, texres); 
                tag_image_time(tex->ima); /* tag image as having being used */
                break;