Example #1
0
/* Make sure all images used by texture are loaded into pool. */
void BKE_texture_fetch_images_for_pool(Tex *texture, struct ImagePool *pool)
{
	if (texture->nodetree != NULL) {
		texture_nodes_fetch_images_for_pool(texture, texture->nodetree, pool);
	}
	else {
		if (texture->type == TEX_IMAGE) {
			if (texture->ima != NULL) {
				BKE_image_pool_acquire_ibuf(texture->ima, &texture->iuser, pool);
			}
		}
	}
}
Example #2
0
static void texture_nodes_fetch_images_for_pool(Tex *texture, bNodeTree *ntree, struct ImagePool *pool)
{
	for (bNode *node = ntree->nodes.first; node; node = node->next) {
		if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
			Image *image = (Image *)node->id;
			BKE_image_pool_acquire_ibuf(image, &texture->iuser, pool);
		}
		else if (node->type == NODE_GROUP && node->id != NULL) {
			/* TODO(sergey): Do we need to control recursion here? */
			bNodeTree *nested_tree = (bNodeTree *)node->id;
			texture_nodes_fetch_images_for_pool(texture, nested_tree, pool);
		}
	}
}
Example #3
0
void image_sample(Image *ima, float fx, float fy, float dx, float dy, float result[4], struct ImagePool *pool)
{
	TexResult texres;
	ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, NULL, pool);
	
	if (UNLIKELY(ibuf == NULL)) {
		zero_v4(result);
		return;
	}
	
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
		ibuf->rect+= (ibuf->x*ibuf->y);

	texres.talpha = true; /* boxsample expects to be initialized */
	boxsample(ibuf, fx, fy, fx + dx, fy + dy, &texres, 0, 1);
	copy_v4_v4(result, &texres.tr);
	
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
		ibuf->rect-= (ibuf->x*ibuf->y);

	ima->flag|= IMA_USED_FOR_RENDER;

	BKE_image_pool_release_ibuf(ima, ibuf, pool);
}
Example #4
0
/* Generic texture sampler for 3D painting systems. point has to be either in
 * region space mouse coordinates, or 3d world coordinates for 3D mapping.
 *
 * rgba outputs straight alpha. */
float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
                              const float point[3],
                              float rgba[4], const int thread,
                              struct ImagePool *pool)
{
	UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
	MTex *mtex = &br->mtex;
	float intensity = 1.0;
	bool hasrgb = false;

	if (!mtex->tex) {
		intensity = 1;
	}
	else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
		/* Get strength by feeding the vertex
		 * location directly into a texture */
		hasrgb = externtex(mtex, point, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
	}
	else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x, y;
		float co[3];

		x = point_2d[0] - br->stencil_pos[0];
		y = point_2d[1] - br->stencil_pos[1];

		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		if (fabsf(x) > br->stencil_dimension[0] || fabsf(y) > br->stencil_dimension[1]) {
			zero_v4(rgba);
			return 0.0f;
		}
		x /= (br->stencil_dimension[0]);
		y /= (br->stencil_dimension[1]);

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		hasrgb = externtex(mtex, co, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
	}
	else {
		float rotation = -mtex->rot;
		float point_2d[2] = {point[0], point[1]};
		float x = 0.0f, y = 0.0f; /* Quite warnings */
		float invradius = 1.0f; /* Quite warnings */
		float co[3];

		if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) {
			/* keep coordinates relative to mouse */

			rotation += ups->brush_rotation;

			x = point_2d[0] - ups->tex_mouse[0];
			y = point_2d[1] - ups->tex_mouse[1];

			/* use pressure adjusted size for fixed mode */
			invradius = 1.0f / ups->pixel_radius;
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
			/* leave the coordinates relative to the screen */

			/* use unadjusted size for tiled mode */
			invradius = 1.0f / BKE_brush_size_get(scene, br);

			x = point_2d[0];
			y = point_2d[1];
		}
		else if (mtex->brush_map_mode == MTEX_MAP_MODE_RANDOM) {
			rotation += ups->brush_rotation;
			/* these contain a random coordinate */
			x = point_2d[0] - ups->tex_mouse[0];
			y = point_2d[1] - ups->tex_mouse[1];

			invradius = 1.0f / ups->pixel_radius;
		}

		x *= invradius;
		y *= invradius;

		/* it is probably worth optimizing for those cases where
		 * the texture is not rotated by skipping the calls to
		 * atan2, sqrtf, sin, and cos. */
		if (rotation > 0.001f || rotation < -0.001f) {
			const float angle    = atan2f(y, x) + rotation;
			const float flen     = sqrtf(x * x + y * y);

			x = flen * cosf(angle);
			y = flen * sinf(angle);
		}

		co[0] = x;
		co[1] = y;
		co[2] = 0.0f;

		hasrgb = externtex(mtex, co, &intensity,
		                   rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
	}

	intensity += br->texture_sample_bias;

	if (!hasrgb) {
		rgba[0] = intensity;
		rgba[1] = intensity;
		rgba[2] = intensity;
		rgba[3] = 1.0f;
	}
	else {
		if (br->mtex.tex->type == TEX_IMAGE && br->mtex.tex->ima) {
			ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(br->mtex.tex->ima, &br->mtex.tex->iuser, pool);
			/* For consistency, sampling always returns color in linear space */
			if (tex_ibuf && tex_ibuf->rect_float == NULL) {
				IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, tex_ibuf->rect_colorspace);
			}
			BKE_image_pool_release_ibuf(br->mtex.tex->ima, tex_ibuf, pool);
		}
	}

	return intensity;
}
Example #5
0
static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), const int j, const int thread_id)
{
	LoadTexData *data = userdata;
	Brush *br = data->br;
	ViewContext *vc = data->vc;

	MTex *mtex = data->mtex;
	GLubyte *buffer = data->buffer;
	const bool col = data->col;

	struct ImagePool *pool = data->pool;
	const int size = data->size;
	const float rotation = data->rotation;
	const float radius = data->radius;

	bool convert_to_linear = false;
	struct ColorSpace *colorspace = NULL;

	if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
		ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
		/* For consistency, sampling always returns color in linear space */
		if (tex_ibuf && tex_ibuf->rect_float == NULL) {
			convert_to_linear = true;
			colorspace = tex_ibuf->rect_colorspace;
		}
		BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
	}

	for (int i = 0; i < size; i++) {
		// largely duplicated from tex_strength

		int index = j * size + i;

		float x = (float)i / size;
		float y = (float)j / size;
		float len;

		if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
			x *= vc->ar->winx / radius;
			y *= vc->ar->winy / radius;
		}
		else {
			x = (x - 0.5f) * 2.0f;
			y = (y - 0.5f) * 2.0f;
		}

		len = sqrtf(x * x + y * y);

		if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1.0f) {
			/* it is probably worth optimizing for those cases where the texture is not rotated by skipping the calls to
			 * atan2, sqrtf, sin, and cos. */
			if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
				const float angle = atan2f(y, x) + rotation;

				x = len * cosf(angle);
				y = len * sinf(angle);
			}

			if (col) {
				float rgba[4];

				paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);

				buffer[index * 4]     = rgba[0] * 255;
				buffer[index * 4 + 1] = rgba[1] * 255;
				buffer[index * 4 + 2] = rgba[2] * 255;
				buffer[index * 4 + 3] = rgba[3] * 255;
			}
			else {
				float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);

				avg += br->texture_sample_bias;

				/* clamp to avoid precision overflow */
				CLAMP(avg, 0.0f, 1.0f);
				buffer[index] = 255 - (GLubyte)(255 * avg);
			}
		}
		else {
			if (col) {
				buffer[index * 4]     = 0;
				buffer[index * 4 + 1] = 0;
				buffer[index * 4 + 2] = 0;
				buffer[index * 4 + 3] = 0;
			}
			else {
				buffer[index] = 0;
			}
		}
	}
}
Example #6
0
static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
	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 (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
			return retval;
		}
		ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
	}

	if ((ibuf == NULL) || ((ibuf->rect == NULL) && (ibuf->rect_float == NULL))) {
		if (ima)
			BKE_image_pool_release_ibuf(ima, ibuf, pool);
		return retval;
	}

	if (ima) {
		ima->flag |= IMA_USED_FOR_RENDER;
	}

	/* mipmap test */
	image_mipmap_test(tex, ibuf);
	
	if (ima) {
		if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
			if ((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 = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	miny = min_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
	maxy = max_fff(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-5f : minx);
	miny = (miny > 0.25f) ? 0.25f : ((miny < 1e-5f) ? 1e-5f : 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 if ((tex->flag & TEX_CHECKER_ODD) == 0 &&
		         (tex->flag & TEX_CHECKER_EVEN) == 0)
		{
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
		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) {
					if (ima)
						BKE_image_pool_release_ibuf(ima, ibuf, pool);
					return retval;
				}
				if ((tex->flag & TEX_CHECKER_EVEN) == 0 && (xs + ys) & 1) {
					if (ima)
						BKE_image_pool_release_ibuf(ima, ibuf, pool);
					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) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			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) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			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 */
	copy_v2_v2(AFD.dxt, dxt);
	copy_v2_v2(AFD.dyt, dyt);
	AFD.intpol = intpol;
	AFD.extflag = extflag;

	/* brecht: added stupid clamping here, large dx/dy can give very large
	 * filter sizes which take ages to render, it may be better to do this
	 * more intelligently later in the code .. probably it's not noticeable */
	if (AFD.dxt[0]*AFD.dxt[0] + AFD.dxt[1]*AFD.dxt[1] > 2.0f*2.0f)
		mul_v2_fl(AFD.dxt, 2.0f/len_v2(AFD.dxt));
	if (AFD.dyt[0]*AFD.dyt[0] + AFD.dyt[1]*AFD.dyt[1] > 2.0f*2.0f)
		mul_v2_fl(AFD.dyt, 2.0f/len_v2(AFD.dyt));

	/* choice: */
	if (tex->imaflag & TEX_MIPMAP) {
		ImBuf *previbuf, *curibuf;
		float levf;
		int maxlev;
		ImBuf *mipmaps[IMB_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;
		BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
		if (tex->texfilter == TXF_FELINE) {
			float fProbes;
			a *= ff;
			b *= ff;
			a = max_ff(a, 1.0f);
			b = max_ff(b, 1.0f);
			fProbes = 2.f*(a / b) - 1.f;
			AFD.iProbes = round_fl_to_int(fProbes);
			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 = max_ff(b, 1e-8f);
		levf = ((float)M_LOG2E) * logf(maxd);

		curmap = 0;
		maxlev = 1;
		mipmaps[0] = ibuf;
		while (curmap < IMB_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);
			}

			if (tex->texfilter != TXF_EWA) {
				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;
			BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
			a *= ff;
			b *= ff;
			a = max_ff(a, 1.0f);
			b = max_ff(b, 1.0f);
			fProbes = 2.f*(a / b) - 1.f;
			/* no limit to number of Probes here */
			AFD.iProbes = round_fl_to_int(fProbes);
			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);
			if (tex->texfilter != TXF_EWA) {
				alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
			}
		}
	}

	if (tex->imaflag & TEX_CALCALPHA)
		texres->ta = texres->tin = texres->ta * max_fff(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 */
		/* The invert of the red channel is to make
		 * the normal map compliant with the outside world.
		 * It needs to be done because in Blender
		 * the normal used in the renderer points inward. It is generated
		 * this way in calc_vertexnormals(). Should this ever change
		 * this negate must be removed. */
		texres->nor[0] = -2.f*(texres->tr - 0.5f);
		texres->nor[1] = 2.f*(texres->tg - 0.5f);
		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 */

	/* do not de-premul for generated alpha, it is already in straight */
	if (texres->ta!=1.0f && texres->ta>1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
		fx = 1.f/texres->ta;
		texres->tr *= fx;
		texres->tg *= fx;
		texres->tb *= fx;
	}

	if (ima)
		BKE_image_pool_release_ibuf(ima, ibuf, pool);

	BRICONTRGB;
	
	return retval;
}
Example #7
0
int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
	TexResult texr;
	float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2];
	float maxd, pixsize, val1, val2, val3;
	int curmap, retval, imaprepeat, imapextend;

	/* 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 */
	copy_v2_v2(dxt, DXT);
	copy_v2_v2(dyt, DYT);

	/* anisotropic filtering */
	if (tex->texfilter != TXF_BOX)
		return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool, skip_load_image);

	texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
	
	/* 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 (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
			return retval;
		
		ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);

		ima->flag|= IMA_USED_FOR_RENDER;
	}
	if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
		if (ima)
			BKE_image_pool_release_ibuf(ima, ibuf, pool);
		return retval;
	}
	
	/* mipmap test */
	image_mipmap_test(tex, ibuf);

	if (ima) {
		if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
			if ((tex->imaflag & TEX_CALCALPHA) == 0) {
				texres->talpha = true;
			}
		}
	}
	
	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 = min_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	maxx = max_fff(dxt[0], dyt[0], dxt[0] + dyt[0]);
	miny = min_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);
	maxy = max_fff(dxt[1], dyt[1], dxt[1] + dyt[1]);

	/* tex_sharper has been removed */
	minx= (maxx-minx)/2.0f;
	miny= (maxy-miny)/2.0f;
	
	if (tex->imaflag & TEX_FILTER_MIN) {
		/* make sure the filtersize is minimal in pixels (normal, ref map can have miniature pixel dx/dy) */
		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.0f) {
		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) SWAP(float, minx, miny);
	
	if (minx>0.25f) minx= 0.25f;
	else if (minx<0.00001f) minx= 0.00001f;	/* side faces of unit-cube */
	if (miny>0.25f) miny= 0.25f;
	else if (miny<0.00001f) miny= 0.00001f;

	
	/* repeat and clip */
	imaprepeat= (tex->extend==TEX_REPEAT);
	imapextend= (tex->extend==TEX_EXTEND);

	if (tex->extend == TEX_REPEAT) {
		if (tex->flag & (TEX_REPEAT_XMIR|TEX_REPEAT_YMIR)) {
			imaprepeat= 0;
			imapextend= 1;
		}
	}

	if (tex->extend == TEX_CHECKER) {
		int xs, ys, xs1, ys1, xs2, ys2, boundary;
		
		xs= (int)floor(fx);
		ys= (int)floor(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 if ((tex->flag & TEX_CHECKER_ODD) == 0 &&
		         (tex->flag & TEX_CHECKER_EVEN) == 0)
		{
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
		else {
			
			xs1= (int)floor(fx-minx);
			ys1= (int)floor(fy-miny);
			xs2= (int)floor(fx+minx);
			ys2= (int)floor(fy+miny);
			boundary= (xs1!=xs2) || (ys1!=ys2);

			if (boundary==0) {
				if ( (tex->flag & TEX_CHECKER_ODD)==0) {
					if ((xs + ys) & 1) {
						/* pass */
					}
					else {
						if (ima)
							BKE_image_pool_release_ibuf(ima, ibuf, pool);
						return retval;
					}
				}
				if ( (tex->flag & TEX_CHECKER_EVEN)==0) {
					if ((xs + ys) & 1) {
						if (ima)
							BKE_image_pool_release_ibuf(ima, ibuf, pool);
						return retval;
					}
				}
				fx-= xs;
				fy-= ys;
			}
			else {
				if (tex->flag & TEX_CHECKER_ODD) {
					if ((xs1+ys) & 1) fx-= xs2;
					else fx-= xs1;
					
					if ((ys1+xs) & 1) fy-= ys2;
					else fy-= ys1;
				}
				if (tex->flag & TEX_CHECKER_EVEN) {
					if ((xs1+ys) & 1) fx-= xs1;
					else fx-= xs2;
					
					if ((ys1+xs) & 1) fy-= ys1;
					else fy-= ys2;
				}
			}
		}

		/* scale around center, (0.5, 0.5) */
		if (tex->checkerdist<1.0f) {
			fx= (fx-0.5f)/(1.0f-tex->checkerdist) +0.5f;
			fy= (fy-0.5f)/(1.0f-tex->checkerdist) +0.5f;
			minx/= (1.0f-tex->checkerdist);
			miny/= (1.0f-tex->checkerdist);
		}
	}

	if (tex->extend == TEX_CLIPCUBE) {
		if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f || texvec[2]<-1.0f || texvec[2]>1.0f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else if (tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
		if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else {
		if (imapextend) {
			if (fx>1.0f) fx = 1.0f;
			else if (fx<0.0f) fx= 0.0f;
		}
		else {
			if (fx>1.0f) fx -= (int)(fx);
			else if (fx<0.0f) fx+= 1-(int)(fx);
		}
		
		if (imapextend) {
			if (fy>1.0f) fy = 1.0f;
			else if (fy<0.0f) fy= 0.0f;
		}
		else {
			if (fy>1.0f) fy -= (int)(fy);
			else if (fy<0.0f) fy+= 1-(int)(fy);
		}
	}

	/* warning no return! */
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
		ibuf->rect+= (ibuf->x*ibuf->y);
	}

	/* choice:  */
	if (tex->imaflag & TEX_MIPMAP) {
		ImBuf *previbuf, *curibuf;
		float bumpscale;
		
		dx = minx;
		dy = miny;
		maxd = max_ff(dx, dy);
		if (maxd > 0.5f) maxd = 0.5f;

		pixsize = 1.0f / (float) MIN2(ibuf->x, ibuf->y);
		
		bumpscale= pixsize/maxd;
		if (bumpscale>1.0f) bumpscale= 1.0f;
		else bumpscale*=bumpscale;
		
		curmap= 0;
		previbuf= curibuf= ibuf;
		while (curmap < IMB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) {
			if (maxd < pixsize) break;
			previbuf= curibuf;
			curibuf= ibuf->mipmap[curmap];
			pixsize= 1.0f / (float)MIN2(curibuf->x, curibuf->y);
			curmap++;
		}

		if (previbuf!=curibuf || (tex->imaflag & TEX_INTERPOL)) {
			/* sample at least 1 pixel */
			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) {
			/* a bit extra filter */
			//minx*= 1.35f;
			//miny*= 1.35f;
			
			boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
			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);
			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);
			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 */
				
				boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend);
				
				/* calc rgb */
				dx= 2.0f*(pixsize-maxd)/pixsize;
				if (dx>=1.0f) {
					texres->ta= texr.ta; texres->tb= texr.tb;
					texres->tg= texr.tg; texres->tr= texr.tr;
				}
				else {
					dy= 1.0f-dx;
					texres->tb= dy*texres->tb+ dx*texr.tb;
					texres->tg= dy*texres->tg+ dx*texr.tg;
					texres->tr= dy*texres->tr+ dx*texr.tr;
					texres->ta= dy*texres->ta+ dx*texr.ta;
				}
				
				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);
				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);
				val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb);
				
				texres->nor[0]= (val1-val2);	/* vals have been interpolated above! */
				texres->nor[1]= (val1-val3);
				
				if (dx<1.0f) {
					dy= 1.0f-dx;
					texres->tb= dy*texres->tb+ dx*texr.tb;
					texres->tg= dy*texres->tg+ dx*texr.tg;
					texres->tr= dy*texres->tr+ dx*texr.tr;
					texres->ta= dy*texres->ta+ dx*texr.ta;
				}
			}
			texres->nor[0]*= bumpscale;
			texres->nor[1]*= bumpscale;
		}
		else {
			maxx= fx+minx;
			minx= fx-minx;
			maxy= fy+miny;
			miny= fy-miny;

			boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);

			if (previbuf!=curibuf) {  /* interpolate */
				boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
				
				fx= 2.0f*(pixsize-maxd)/pixsize;
				
				if (fx>=1.0f) {
					texres->ta= texr.ta; texres->tb= texr.tb;
					texres->tg= texr.tg; texres->tr= texr.tr;
				}
				else {
					fy= 1.0f-fx;
					texres->tb= fy*texres->tb+ fx*texr.tb;
					texres->tg= fy*texres->tg+ fx*texr.tg;
					texres->tr= fy*texres->tr+ fx*texr.tr;
					texres->ta= fy*texres->ta+ fx*texr.ta;
				}
			}
		}
	}
	else {
		const int intpol = tex->imaflag & TEX_INTERPOL;
		if (intpol) {
			/* 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;

			/* 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 (tex->imaflag & TEX_CALCALPHA) {
		texres->ta = texres->tin = texres->ta * max_fff(texres->tr, texres->tg, texres->tb);
	}
	else {
		texres->tin = texres->ta;
	}

	if (tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-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)) {
		/* qdn: normal from color
		 * The invert of the red channel is to make
		 * the normal map compliant with the outside world.
		 * It needs to be done because in Blender
		 * the normal used in the renderer points inward. It is generated
		 * this way in calc_vertexnormals(). Should this ever change
		 * this negate must be removed. */
		texres->nor[0] = -2.f*(texres->tr - 0.5f);
		texres->nor[1] = 2.f*(texres->tg - 0.5f);
		texres->nor[2] = 2.f*(texres->tb - 0.5f);
	}

	/* de-premul, this is being premulled in shade_input_do_shade() */
	/* do not de-premul for generated alpha, it is already in straight */
	if (texres->ta!=1.0f && texres->ta>1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
		mul_v3_fl(&texres->tr, 1.0f / texres->ta);
	}

	if (ima)
		BKE_image_pool_release_ibuf(ima, ibuf, pool);

	BRICONTRGB;
	
	return retval;
}
Example #8
0
int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
	float fx, fy, val1, val2, val3;
	int x, y, retval;
	int xi, yi; /* original values */

	texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
	
	/* 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 (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
			return retval;

		ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);

		ima->flag|= IMA_USED_FOR_RENDER;
	}
	if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
		if (ima)
			BKE_image_pool_release_ibuf(ima, ibuf, pool);
		return retval;
	}
	
	/* setup mapping */
	if (tex->imaflag & TEX_IMAROT) {
		fy= texvec[0];
		fx= texvec[1];
	}
	else {
		fx= texvec[0];
		fy= texvec[1];
	}
	
	if (tex->extend == TEX_CHECKER) {
		int xs, ys;
		
		xs= (int)floor(fx);
		ys= (int)floor(fy);
		fx-= xs;
		fy-= ys;

		if ( (tex->flag & TEX_CHECKER_ODD) == 0) {
			if ((xs + ys) & 1) {
				/* pass */
			}
			else {
				if (ima)
					BKE_image_pool_release_ibuf(ima, ibuf, pool);
				return retval;
			}
		}
		if ( (tex->flag & TEX_CHECKER_EVEN)==0) {
			if ((xs+ys) & 1) {
				if (ima)
					BKE_image_pool_release_ibuf(ima, ibuf, pool);
				return retval;
			}
		}
		/* scale around center, (0.5, 0.5) */
		if (tex->checkerdist<1.0f) {
			fx= (fx-0.5f)/(1.0f-tex->checkerdist) +0.5f;
			fy= (fy-0.5f)/(1.0f-tex->checkerdist) +0.5f;
		}
	}

	x= xi= (int)floorf(fx*ibuf->x);
	y= yi= (int)floorf(fy*ibuf->y);

	if (tex->extend == TEX_CLIPCUBE) {
		if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y || texvec[2]<-1.0f || texvec[2]>1.0f) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else if ( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
		if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
			if (ima)
				BKE_image_pool_release_ibuf(ima, ibuf, pool);
			return retval;
		}
	}
	else {
		if (tex->extend==TEX_EXTEND) {
			if (x>=ibuf->x) x = ibuf->x-1;
			else if (x<0) x= 0;
		}
		else {
			x= x % ibuf->x;
			if (x<0) x+= ibuf->x;
		}
		if (tex->extend==TEX_EXTEND) {
			if (y>=ibuf->y) y = ibuf->y-1;
			else if (y<0) y= 0;
		}
		else {
			y= y % ibuf->y;
			if (y<0) y+= ibuf->y;
		}
	}
	
	/* warning, no return before setting back! */
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
		ibuf->rect+= (ibuf->x*ibuf->y);
	}

	/* keep this before interpolation [#29761] */
	if (ima) {
		if ((tex->imaflag & TEX_USEALPHA) && (ima->flag & IMA_IGNORE_ALPHA) == 0) {
			if ((tex->imaflag & TEX_CALCALPHA) == 0) {
				texres->talpha = true;
			}
		}
	}

	/* interpolate */
	if (tex->imaflag & TEX_INTERPOL) {
		float filterx, filtery;
		filterx = (0.5f * tex->filtersize) / ibuf->x;
		filtery = (0.5f * tex->filtersize) / ibuf->y;

		/* important that this value is wrapped [#27782]
		 * this applies the modifications made by the checks above,
		 * back to the floating point values */
		fx -= (float)(xi - x) / (float)ibuf->x;
		fy -= (float)(yi - y) / (float)ibuf->y;

		boxsample(ibuf, fx-filterx, fy-filtery, fx+filterx, fy+filtery, texres, (tex->extend==TEX_REPEAT), (tex->extend==TEX_EXTEND));
	}
	else { /* no filtering */
		ibuf_get_color(&texres->tr, ibuf, x, y);
	}
	
	if ( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
		ibuf->rect-= (ibuf->x*ibuf->y);
	}

	if (texres->nor) {
		if (tex->imaflag & TEX_NORMALMAP) {
			/* qdn: normal from color
			 * The invert of the red channel is to make
			 * the normal map compliant with the outside world.
			 * It needs to be done because in Blender
			 * the normal used in the renderer points inward. It is generated
			 * this way in calc_vertexnormals(). Should this ever change
			 * this negate must be removed. */
			texres->nor[0] = -2.f*(texres->tr - 0.5f);
			texres->nor[1] = 2.f*(texres->tg - 0.5f);
			texres->nor[2] = 2.f*(texres->tb - 0.5f);
		}
		else {
			/* bump: take three samples */
			val1= texres->tr+texres->tg+texres->tb;

			if (x<ibuf->x-1) {
				float col[4];
				ibuf_get_color(col, ibuf, x+1, y);
				val2= (col[0]+col[1]+col[2]);
			}
			else {
				val2= val1;
			}

			if (y<ibuf->y-1) {
				float col[4];
				ibuf_get_color(col, ibuf, x, y+1);
				val3 = (col[0]+col[1]+col[2]);
			}
			else {
				val3 = val1;
			}

			/* do not mix up x and y here! */
			texres->nor[0]= (val1-val2);
			texres->nor[1]= (val1-val3);
		}
	}

	if (texres->talpha) {
		texres->tin = texres->ta;
	}
	else if (tex->imaflag & TEX_CALCALPHA) {
		texres->ta = texres->tin = max_fff(texres->tr, texres->tg, texres->tb);
	}
	else {
		texres->ta = texres->tin = 1.0;
	}
	
	if (tex->flag & TEX_NEGALPHA) {
		texres->ta = 1.0f - texres->ta;
	}

	/* de-premul, this is being premulled in shade_input_do_shade()
	 * do not de-premul for generated alpha, it is already in straight */
	if (texres->ta!=1.0f && texres->ta>1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
		fx= 1.0f/texres->ta;
		texres->tr*= fx;
		texres->tg*= fx;
		texres->tb*= fx;
	}

	if (ima)
		BKE_image_pool_release_ibuf(ima, ibuf, pool);

	BRICONTRGB;
	
	return retval;
}