Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2009-07-21 17:20:35 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2009-07-21 17:20:35 +0400
commite3c6ae9b89d1d0c7bb6957f81b9fd9a89477b2d0 (patch)
tree9a50b247676dd1f3b0abe3cea40cc0773161dae3 /source
parentea0b015b0a1c73fb1899a4d9040704a7d85fda9c (diff)
2.5: Texture Filtering
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.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/intern/texture.c5
-rw-r--r--source/blender/blenloader/intern/readfile.c6
-rw-r--r--source/blender/editors/interface/interface_templates.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c2
-rw-r--r--source/blender/imbuf/IMB_imbuf.h2
-rw-r--r--source/blender/imbuf/intern/filter.c88
-rw-r--r--source/blender/makesdna/DNA_texture_types.h13
-rw-r--r--source/blender/makesrna/intern/rna_texture.c59
-rw-r--r--source/blender/render/intern/source/imagetexture.c947
-rw-r--r--source/blender/render/intern/source/texture.c50
10 files changed, 1118 insertions, 62 deletions
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index bcdea06936f..db864dc9f1e 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -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;
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index c43c720bad0..6da444bc88e 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -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;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index f8d1e1d7ab9..8b01c341565 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -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);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index dd4e67e612c..d80a26e50f8 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -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;
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 1d8035a2358..d2f561438b9 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -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);
/**
*
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 9802405fd8d..cc3315c7696 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -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++;
+ }
+ }
+}
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 6b7bfbdcd83..e1dd21a8ccb 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -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
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 2573ad8394a..330d38502ce 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -39,6 +39,14 @@
#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)
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index b9a2acb8b1c..743dbb72e7c 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -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);
}
}
diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c
index e11bb0004b2..9466bd45420 100644
--- a/source/blender/render/intern/source/texture.c
+++ b/source/blender/render/intern/source/texture.c
@@ -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;