static void maskmodifier_apply_threaded(int width, int height, unsigned char *rect, float *rect_float, unsigned char *mask_rect, float *mask_rect_float, void *UNUSED(data_v)) { int x, y; if (rect && !mask_rect) return; if (rect_float && !mask_rect_float) return; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { int pixel_index = (y * width + x) * 4; if (rect) { unsigned char *pixel = rect + pixel_index; unsigned char *mask_pixel = mask_rect + pixel_index; unsigned char mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]); /* byte buffer is straight, so only affect on alpha itself, * this is the only way to alpha-over byte strip after * applying mask modifier. */ pixel[3] = (float)(pixel[3] * mask) / 255.0f; } else if (rect_float) { int c; float *pixel = rect_float + pixel_index; const float *mask_pixel = mask_rect_float + pixel_index; float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]); /* float buffers are premultiplied, so need to premul color * as well to make it easy to alpha-over masted strip. */ for (c = 0; c < 4; c++) pixel[c] = pixel[c] * mask; } } } }
static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2], float *distance_r) { MovieTrackingTrack *track = NULL, *cur; float mindist = 0.0f; int framenr = ED_space_clip_get_clip_frame_number(sc); cur = tracksbase->first; while (cur) { MovieTrackingMarker *marker = BKE_tracking_marker_get(cur, framenr); if (((cur->flag & TRACK_HIDDEN) == 0) && MARKER_VISIBLE(sc, cur, marker)) { float dist, d1, d2 = FLT_MAX, d3 = FLT_MAX; /* distance to marker point */ d1 = sqrtf((co[0] - marker->pos[0] - cur->offset[0]) * (co[0] - marker->pos[0] - cur->offset[0]) + (co[1] - marker->pos[1] - cur->offset[1]) * (co[1] - marker->pos[1] - cur->offset[1])); /* distance to pattern boundbox */ if (sc->flag & SC_SHOW_MARKER_PATTERN) d2 = dist_to_crns(co, marker->pos, marker->pattern_corners); /* distance to search boundbox */ if (sc->flag & SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur)) d3 = dist_to_rect(co, marker->pos, marker->search_min, marker->search_max); /* choose minimal distance. useful for cases of overlapped markers. */ dist = min_fff(d1, d2, d3); if (track == NULL || dist < mindist) { track = cur; mindist = dist; } } cur = cur->next; } *distance_r = mindist; return track; }
static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *arg) { Scene *scene = CTX_data_scene(C); UnitSettings *unit = &scene->unit; RulerItem *ruler_item; RulerInfo *ruler_info = arg; RegionView3D *rv3d = ruler_info->ar->regiondata; // ARegion *ar = ruler_info->ar; const float cap_size = 4.0f; const float bg_margin = 4.0f * U.pixelsize; const float bg_radius = 4.0f * U.pixelsize; const float arc_size = 64.0f * U.pixelsize; #define ARC_STEPS 24 const int arc_steps = ARC_STEPS; int i; //unsigned int color_act = 0x666600; unsigned int color_act = 0xffffff; unsigned int color_base = 0x0; unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80}; unsigned char color_text[3]; unsigned char color_wire[3]; /* anti-aliased lines for more consistent appearance */ glEnable(GL_LINE_SMOOTH); BLF_enable(blf_mono_font, BLF_ROTATION); BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); BLF_rotation(blf_mono_font, 0.0f); UI_GetThemeColor3ubv(TH_TEXT, color_text); UI_GetThemeColor3ubv(TH_WIRE, color_wire); for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) { const bool is_act = (i == ruler_info->item_active); float dir_ruler[2]; float co_ss[3][2]; int j; /* should these be checked? - ok for now not to */ for (j = 0; j < 3; j++) { ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); } glEnable(GL_BLEND); cpack(is_act ? color_act : color_base); if (ruler_item->flag & RULERITEM_USE_ANGLE) { glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j++) { glVertex2fv(co_ss[j]); } glEnd(); cpack(0xaaaaaa); setlinestyle(3); glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j++) { glVertex2fv(co_ss[j]); } glEnd(); setlinestyle(0); /* arc */ { float dir_tmp[3]; float co_tmp[3]; float arc_ss_coords[ARC_STEPS + 1][2]; float dir_a[3]; float dir_b[3]; float quat[4]; float axis[3]; float angle; const float px_scale = (ED_view3d_pixel_size(rv3d, ruler_item->co[1]) * min_fff(arc_size, len_v2v2(co_ss[0], co_ss[1]) / 2.0f, len_v2v2(co_ss[2], co_ss[1]) / 2.0f)); sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]); sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]); normalize_v3(dir_a); normalize_v3(dir_b); cross_v3_v3v3(axis, dir_a, dir_b); angle = angle_normalized_v3v3(dir_a, dir_b); axis_angle_to_quat(quat, axis, angle / arc_steps); copy_v3_v3(dir_tmp, dir_a); glColor3ubv(color_wire); for (j = 0; j <= arc_steps; j++) { madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP); mul_qt_v3(quat, dir_tmp); } glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords); glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1); glDisableClientState(GL_VERTEX_ARRAY); } /* text */ { char numstr[256]; float numstr_size[2]; float pos[2]; const int prec = 2; /* XXX, todo, make optional */ ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); pos[0] = co_ss[1][0] + (cap_size * 2.0f); pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); /* draw text (bg) */ glColor4ubv(color_back); uiSetRoundBox(UI_CNR_ALL); uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin, pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], bg_radius); /* draw text */ glColor3ubv(color_text); BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); BLF_rotation(blf_mono_font, 0.0f); BLF_draw(blf_mono_font, numstr, sizeof(numstr)); } /* capping */ { float rot_90_vec_a[2]; float rot_90_vec_b[2]; float cap[2]; sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); rot_90_vec_a[0] = -dir_ruler[1]; rot_90_vec_a[1] = dir_ruler[0]; normalize_v2(rot_90_vec_a); sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]); rot_90_vec_b[0] = -dir_ruler[1]; rot_90_vec_b[1] = dir_ruler[0]; normalize_v2(rot_90_vec_b); glEnable(GL_BLEND); glColor3ubv(color_wire); glBegin(GL_LINES); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); glVertex2fv(cap); /* angle vertex */ glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); glEnd(); glDisable(GL_BLEND); } } else { glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j += 2) { glVertex2fv(co_ss[j]); } glEnd(); cpack(0xaaaaaa); setlinestyle(3); glBegin(GL_LINE_STRIP); for (j = 0; j < 3; j += 2) { glVertex2fv(co_ss[j]); } glEnd(); setlinestyle(0); sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); /* text */ { char numstr[256]; float numstr_size[2]; const int prec = 6; /* XXX, todo, make optional */ float pos[2]; ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); mid_v2_v2v2(pos, co_ss[0], co_ss[2]); /* center text */ pos[0] -= numstr_size[0] / 2.0f; pos[1] -= numstr_size[1] / 2.0f; /* draw text (bg) */ glColor4ubv(color_back); uiSetRoundBox(UI_CNR_ALL); uiRoundBox(pos[0] - bg_margin, pos[1] - bg_margin, pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], bg_radius); /* draw text */ glColor3ubv(color_text); BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); BLF_draw(blf_mono_font, numstr, sizeof(numstr)); } /* capping */ { float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; float cap[2]; normalize_v2(rot_90_vec); glEnable(GL_BLEND); glColor3ubv(color_wire); glBegin(GL_LINES); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); glVertex2fv(cap); madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); glVertex2fv(cap); glEnd(); glDisable(GL_BLEND); } } } glDisable(GL_LINE_SMOOTH); BLF_disable(blf_mono_font, BLF_ROTATION); #undef ARC_STEPS /* draw snap */ if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG)) { ruler_item = ruler_item_active_get(ruler_info); if (ruler_item) { /* size from drawSnapping */ const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); float co_ss[3]; ED_view3d_project_float_global(ar, ruler_item->co[ruler_item->co_index], co_ss, V3D_PROJ_TEST_NOP); cpack(color_act); circ(co_ss[0], co_ss[1], size * U.pixelsize); } } }
static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2], RulerItem **r_ruler_item, int *r_co_index) { ARegion *ar = ruler_info->ar; RulerItem *ruler_item; float dist_best = RULER_PICK_DIST_SQ; RulerItem *ruler_item_best = NULL; int co_index_best = -1; for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) { float co_ss[3][2]; float dist; int j; /* should these be checked? - ok for now not to */ for (j = 0; j < 3; j++) { ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); } if (ruler_item->flag & RULERITEM_USE_ANGLE) { dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]), dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2])); if (dist < dist_best) { dist_best = dist; ruler_item_best = ruler_item; { const float dist_points[3] = { len_squared_v2v2(co_ss[0], mval), len_squared_v2v2(co_ss[1], mval), len_squared_v2v2(co_ss[2], mval), }; if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = min_axis_v3(dist_points); } else { co_index_best = -1; } } } } else { dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]); if (dist < dist_best) { dist_best = dist; ruler_item_best = ruler_item; { const float dist_points[2] = { len_squared_v2v2(co_ss[0], mval), len_squared_v2v2(co_ss[2], mval), }; if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2; } else { co_index_best = -1; } } } } } if (ruler_item_best) { *r_ruler_item = ruler_item_best; *r_co_index = co_index_best; return true; } else { *r_ruler_item = NULL; *r_co_index = -1; return false; } }
static enum ISectType intersect_line_tri( const float p0[3], const float p1[3], const float *t_cos[3], const float t_nor[3], float r_ix[3], const struct ISectEpsilon *e) { float p_dir[3]; unsigned int i_t0; float fac; sub_v3_v3v3(p_dir, p0, p1); normalize_v3(p_dir); for (i_t0 = 0; i_t0 < 3; i_t0++) { const unsigned int i_t1 = (i_t0 + 1) % 3; float te_dir[3]; sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]); normalize_v3(te_dir); if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) { /* co-linear */ } else { float ix_pair[2][3]; int ix_pair_type; ix_pair_type = isect_line_line_epsilon_v3(p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f); if (ix_pair_type != 0) { if (ix_pair_type == 1) { copy_v3_v3(ix_pair[1], ix_pair[0]); } if ((ix_pair_type == 1) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq)) { fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]); if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { fac = line_point_factor_v3(ix_pair[0], p0, p1); if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { copy_v3_v3(r_ix, ix_pair[0]); return (IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0); } } } } } } /* check ray isn't planar with tri */ if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) { if (isect_line_segment_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) { if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) { interp_v3_v3v3(r_ix, p0, p1, fac); if (min_fff(len_squared_v3v3(t_cos[0], r_ix), len_squared_v3v3(t_cos[1], r_ix), len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq) { return IX_EDGE_TRI; } } } } /* r_ix may be unset */ return IX_NONE; }
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; }
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; }