Exemple #1
0
static int previewrange_define_exec(bContext *C, wmOperator *op)
{
  Scene *scene = CTX_data_scene(C);
  ARegion *ar = CTX_wm_region(C);
  float sfra, efra;
  rcti rect;

  /* get min/max values from box select rect (already in region coordinates, not screen) */
  WM_operator_properties_border_to_rcti(op, &rect);

  /* convert min/max values to frames (i.e. region to 'tot' rect) */
  sfra = UI_view2d_region_to_view_x(&ar->v2d, rect.xmin);
  efra = UI_view2d_region_to_view_x(&ar->v2d, rect.xmax);

  /* set start/end frames for preview-range
   * - must clamp within allowable limits
   * - end must not be before start (though this won't occur most of the time)
   */
  FRAMENUMBER_MIN_CLAMP(sfra);
  FRAMENUMBER_MIN_CLAMP(efra);
  if (efra < sfra) {
    efra = sfra;
  }

  scene->r.flag |= SCER_PRV_RANGE;
  scene->r.psfra = round_fl_to_int(sfra);
  scene->r.pefra = round_fl_to_int(efra);

  /* send notifiers */
  WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);

  return OPERATOR_FINISHED;
}
Exemple #2
0
/* Set the new frame number */
static void change_frame_apply(bContext *C, wmOperator *op)
{
  Main *bmain = CTX_data_main(C);
  Scene *scene = CTX_data_scene(C);
  float frame = RNA_float_get(op->ptr, "frame");
  bool do_snap = RNA_boolean_get(op->ptr, "snap");

  if (do_snap) {
    if (CTX_wm_space_seq(C)) {
      frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false);
    }
    else {
      frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame);
    }
  }

  /* set the new frame number */
  if (scene->r.flag & SCER_SHOW_SUBFRAME) {
    CFRA = (int)frame;
    SUBFRA = frame - (int)frame;
  }
  else {
    CFRA = round_fl_to_int(frame);
    SUBFRA = 0.0f;
  }
  FRAMENUMBER_MIN_CLAMP(CFRA);

  /* do updates */
  BKE_sound_seek_scene(bmain, scene);
  WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
Exemple #3
0
/* tweak and line gestures */
int wm_gesture_evaluate(wmGesture *gesture, const wmEvent *event)
{
  if (gesture->type == WM_GESTURE_TWEAK) {
    rcti *rect = gesture->customdata;
    const int delta[2] = {
        BLI_rcti_size_x(rect),
        BLI_rcti_size_y(rect),
    };

    if (WM_event_drag_test_with_delta(event, delta)) {
      int theta = round_fl_to_int(4.0f * atan2f((float)delta[1], (float)delta[0]) / (float)M_PI);
      int val = EVT_GESTURE_W;

      if (theta == 0) {
        val = EVT_GESTURE_E;
      }
      else if (theta == 1) {
        val = EVT_GESTURE_NE;
      }
      else if (theta == 2) {
        val = EVT_GESTURE_N;
      }
      else if (theta == 3) {
        val = EVT_GESTURE_NW;
      }
      else if (theta == -1) {
        val = EVT_GESTURE_SE;
      }
      else if (theta == -2) {
        val = EVT_GESTURE_S;
      }
      else if (theta == -3) {
        val = EVT_GESTURE_SW;
      }

#if 0
      /* debug */
      if (val == 1)
        printf("tweak north\n");
      if (val == 2)
        printf("tweak north-east\n");
      if (val == 3)
        printf("tweak east\n");
      if (val == 4)
        printf("tweak south-east\n");
      if (val == 5)
        printf("tweak south\n");
      if (val == 6)
        printf("tweak south-west\n");
      if (val == 7)
        printf("tweak west\n");
      if (val == 8)
        printf("tweak north-west\n");
#endif
      return val;
    }
  }
  return 0;
}
Exemple #4
0
/**
 * Generate time string and store in \a str
 *
 * \param str: destination string
 * \param maxncpy: maximum number of characters to copy ``sizeof(str)``
 * \param power: special setting for #View2D grid drawing,
 *        used to specify how detailed we need to be
 * \param time_seconds: time total time in seconds
 * \return length of \a str
 *
 * \note in some cases this is used to print non-seconds values.
 */
size_t BLI_timecode_string_from_time_seconds(
        char *str, const size_t maxncpy, const int power, const float time_seconds)
{
	size_t rlen;

	/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
	if (power <= 0) {
		rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
	}
	else {
		rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
	}

	return rlen;
}
Exemple #5
0
bool ED_region_panel_category_gutter_calc_rect(const ARegion *ar, rcti *r_ar_gutter)
{
  *r_ar_gutter = ar->winrct;
  if (UI_panel_category_is_visible(ar)) {
    const int category_tabs_width = round_fl_to_int(UI_view2d_scale_get_x(&ar->v2d) *
                                                    UI_PANEL_CATEGORY_MARGIN_WIDTH);
    if (ar->alignment == RGN_ALIGN_LEFT) {
      r_ar_gutter->xmax = r_ar_gutter->xmin + category_tabs_width;
    }
    else if (ar->alignment == RGN_ALIGN_RIGHT) {
      r_ar_gutter->xmin = r_ar_gutter->xmax - category_tabs_width;
    }
    else {
      BLI_assert(!"Unsupported alignment");
    }
    return true;
  }
  return false;
}
Exemple #6
0
/* Set the new frame number */
static void graphview_cursor_apply(bContext *C, wmOperator *op)
{
	Main *bmain = CTX_data_main(C);
	Scene *scene = CTX_data_scene(C);
	SpaceIpo *sipo = CTX_wm_space_graph(C);
	float frame = RNA_float_get(op->ptr, "frame"); /* this isn't technically "frame", but it'll do... */
	
	/* adjust the frame or the cursor x-value */
	if (sipo->mode == SIPO_MODE_DRIVERS) {
		/* adjust cursor x-value */
		sipo->cursorTime = frame;
	}
	else {
		/* adjust the frame 
		 * NOTE: sync this part of the code with ANIM_OT_change_frame
		 */
		/* 1) frame is rounded to the nearest int, since frames are ints */
		CFRA = round_fl_to_int(frame);
		
		if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
			/* Clip to preview range
			 * NOTE: Preview range won't go into negative values,
			 *       so only clamping once should be fine.
			 */
			CLAMP(CFRA, PSFRA, PEFRA);
		}
		else {
			/* Prevent negative frames */
			FRAMENUMBER_MIN_CLAMP(CFRA);
		}
		
		SUBFRA = 0.0f;
		BKE_sound_seek_scene(bmain, scene);
	}
	
	/* set the cursor value */
	sipo->cursorVal = RNA_float_get(op->ptr, "value");
	
	/* send notifiers - notifiers for frame should force an update for both vars ok... */
	WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
Exemple #7
0
static int frame_from_event(bContext *C, const wmEvent *event)
{
	ARegion *ar = CTX_wm_region(C);
	Scene *scene = CTX_data_scene(C);
	int framenr = 0;

	if (ar->regiontype == RGN_TYPE_WINDOW) {
		float sfra = SFRA, efra = EFRA, framelen = ar->winx / (efra - sfra + 1);

		framenr = sfra + event->mval[0] / framelen;
	}
	else {
		float viewx, viewy;

		UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);

		framenr = round_fl_to_int(viewx);
	}

	return framenr;
}
Exemple #8
0
size_t BLI_timecode_string_from_time(
        char *str, const size_t maxncpy, const int power, const float time_seconds,
        const double fps, const short timecode_style)
{
	int hours = 0, minutes = 0, seconds = 0, frames = 0;
	float time = time_seconds;
	char neg[2] = {'\0'};
	size_t rlen;

	/* get cframes */
	if (time < 0) {
		/* correction for negative cfraues */
		neg[0] = '-';
		time = -time;
	}

	if (time >= 3600.0f) {
		/* hours */
		/* XXX should we only display a single digit for hours since clips are
		 *     VERY UNLIKELY to be more than 1-2 hours max? However, that would
		 *     go against conventions...
		 */
		hours = (int)time / 3600;
		time = fmodf(time, 3600);
	}

	if (time >= 60.0f) {
		/* minutes */
		minutes = (int)time / 60;
		time = fmodf(time, 60);
	}

	if (power <= 0) {
		/* seconds + frames
		 * Frames are derived from 'fraction' of second. We need to perform some additional rounding
		 * to cope with 'half' frames, etc., which should be fine in most cases
		 */
		seconds = (int)time;
		frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps));
	}
	else {
		/* seconds (with pixel offset rounding) */
		seconds = round_fl_to_int(time);
	}

	switch (timecode_style) {
		case USER_TIMECODE_MINIMAL:
		{
			/* - In general, minutes and seconds should be shown, as most clips will be
			 *   within this length. Hours will only be included if relevant.
			 * - Only show frames when zoomed in enough for them to be relevant
			 *   (using separator of '+' for frames).
			 *   When showing frames, use slightly different display to avoid confusion with mm:ss format
			 */
			if (power <= 0) {
				/* include "frames" in display */
				if (hours) {
					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
				}
				else if (minutes) {
					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
				}
				else {
					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%d+%02d", neg, seconds, frames);
				}
			}
			else {
				/* don't include 'frames' in display */
				if (hours) {
					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
				}
				else {
					rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
				}
			}
			break;
		}
		case USER_TIMECODE_SMPTE_MSF:
		{
			/* reduced SMPTE format that always shows minutes, seconds, frames. Hours only shown as needed. */
			if (hours) {
				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
			}
			else {
				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
			}
			break;
		}
		case USER_TIMECODE_MILLISECONDS:
		{
			/* reduced SMPTE. Instead of frames, milliseconds are shown */

			/* precision of decimal part */
			const int ms_dp = (power <= 0) ? (1 - power) : 1;

			/* to get 2 digit whole-number part for seconds display
			 * (i.e. 3 is for 2 digits + radix, on top of full length) */
			const int s_pad = ms_dp + 3;

			if (hours) {
				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
			}
			else {
				rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad,  ms_dp, time);
			}
			break;
		}
		case USER_TIMECODE_SUBRIP:
		{
			/* SubRip, like SMPTE milliseconds but seconds and milliseconds are separated by a comma, not a dot... */

			/* precision of decimal part */
			const int ms_dp = (power <= 0) ? (1 - power) : 1;
			const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f);

			rlen = BLI_snprintf_rlen(
			           str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms);
			break;
		}
		case USER_TIMECODE_SECONDS_ONLY:
		{
			/* only show the original seconds display */
			/* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
			if (power <= 0) {
				rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
			}
			else {
				rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
			}
			break;
		}
		case USER_TIMECODE_SMPTE_FULL:
		default:
		{
			/* full SMPTE format */
			rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
			break;
		}
	}

	return rlen;
}
Exemple #9
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;
}