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; }
/* 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); }
/* 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; }
/** * 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; }
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; }
/* 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); }
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; }
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; }
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; }