diff options
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r-- | source/blender/imbuf/IMB_imbuf.h | 12 | ||||
-rw-r--r-- | source/blender/imbuf/intern/imageprocess.c | 131 |
2 files changed, 143 insertions, 0 deletions
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 9c84127105a..651c69726ff 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -70,6 +70,7 @@ extern "C" { */ struct ImBuf; struct rcti; +struct rctf; /** * @@ -323,6 +324,11 @@ typedef enum IMB_Proxy_Size { IMB_PROXY_MAX_SLOT = 4, } IMB_Proxy_Size; +typedef enum eIMBInterpolationFilterMode { + IMB_FILTER_NEAREST, + IMB_FILTER_BILINEAR, +} eIMBInterpolationFilterMode; + /* Defaults to BL_proxy within the directory of the animation. */ void IMB_anim_set_index_dir(struct anim *anim, const char *dir); void IMB_anim_get_fname(struct anim *anim, char *file, int size); @@ -732,6 +738,12 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data); +void IMB_transform(struct ImBuf *src, + struct ImBuf *dst, + float transform_matrix[3][3], + struct rctf *src_crop, + const eIMBInterpolationFilterMode filter); + /* ffmpeg */ void IMB_ffmpeg_init(void); const char *IMB_ffmpeg_last_error(void); diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index 1fe3a7717fb..c88a9b81ff2 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -350,6 +350,137 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in } /* -------------------------------------------------------------------- */ +/** \name Image transform + * \{ */ +typedef struct TransformUserData { + ImBuf *src; + ImBuf *dst; + float start_uv[2]; + float add_x[2]; + float add_y[2]; + rctf src_crop; +} TransformUserData; + +static void imb_transform_calc_start_uv(const float transform_matrix[3][3], float r_start_uv[2]) +{ + float orig[2]; + orig[0] = 0.0f; + orig[1] = 0.0f; + mul_v2_m3v2(r_start_uv, transform_matrix, orig); +} + +static void imb_transform_calc_add_x(const float transform_matrix[3][3], + const float start_uv[2], + const int width, + float r_add_x[2]) +{ + float uv_max_x[2]; + uv_max_x[0] = width; + uv_max_x[1] = 0.0f; + mul_v2_m3v2(r_add_x, transform_matrix, uv_max_x); + sub_v2_v2(r_add_x, start_uv); + mul_v2_fl(r_add_x, 1.0f / width); +} + +static void imb_transform_calc_add_y(const float transform_matrix[3][3], + const float start_uv[2], + const int height, + float r_add_y[2]) +{ + float uv_max_y[2]; + uv_max_y[0] = 0.0f; + uv_max_y[1] = height; + mul_v2_m3v2(r_add_y, transform_matrix, uv_max_y); + sub_v2_v2(r_add_y, start_uv); + mul_v2_fl(r_add_y, 1.0f / height); +} + +typedef void (*InterpolationColorFunction)( + struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v); +BLI_INLINE void imb_transform_scanlines(const TransformUserData *user_data, + int start_scanline, + int num_scanlines, + InterpolationColorFunction interpolation) +{ + const int width = user_data->dst->x; + + float next_line_start_uv[2]; + madd_v2_v2v2fl(next_line_start_uv, user_data->start_uv, user_data->add_y, start_scanline); + + unsigned char *outI = NULL; + float *outF = NULL; + pixel_from_buffer(user_data->dst, &outI, &outF, 0, start_scanline); + + for (int yi = start_scanline; yi < start_scanline + num_scanlines; yi++) { + float uv[2]; + copy_v2_v2(uv, next_line_start_uv); + add_v2_v2(next_line_start_uv, user_data->add_y); + for (int xi = 0; xi < width; xi++) { + if (uv[0] >= user_data->src_crop.xmin && uv[0] < user_data->src_crop.xmax && + uv[1] >= user_data->src_crop.ymin && uv[1] < user_data->src_crop.ymax) { + interpolation(user_data->src, outI, outF, uv[0], uv[1]); + } + add_v2_v2(uv, user_data->add_x); + if (outI) { + outI += 4; + } + if (outF) { + outF += 4; + } + } + } +} + +static void imb_transform_nearest_scanlines(void *custom_data, + int start_scanline, + int num_scanlines) +{ + const TransformUserData *user_data = custom_data; + imb_transform_scanlines(user_data, start_scanline, num_scanlines, nearest_interpolation_color); +} + +static void imb_transform_bilinear_scanlines(void *custom_data, + int start_scanline, + int num_scanlines) +{ + const TransformUserData *user_data = custom_data; + imb_transform_scanlines(user_data, start_scanline, num_scanlines, bilinear_interpolation_color); +} + +static ScanlineThreadFunc imb_transform_scanline_func(const eIMBInterpolationFilterMode filter) +{ + ScanlineThreadFunc scanline_func = NULL; + switch (filter) { + case IMB_FILTER_NEAREST: + scanline_func = imb_transform_nearest_scanlines; + break; + case IMB_FILTER_BILINEAR: + scanline_func = imb_transform_bilinear_scanlines; + break; + } + return scanline_func; +} + +void IMB_transform(struct ImBuf *src, + struct ImBuf *dst, + float transform_matrix[3][3], + struct rctf *src_crop, + const eIMBInterpolationFilterMode filter) +{ + TransformUserData user_data; + user_data.src = src; + user_data.dst = dst; + user_data.src_crop = *src_crop; + imb_transform_calc_start_uv(transform_matrix, user_data.start_uv); + imb_transform_calc_add_x(transform_matrix, user_data.start_uv, src->x, user_data.add_x); + imb_transform_calc_add_y(transform_matrix, user_data.start_uv, src->y, user_data.add_y); + ScanlineThreadFunc scanline_func = imb_transform_scanline_func(filter); + IMB_processor_apply_threaded_scanlines(dst->y, scanline_func, &user_data); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Threaded Image Processing * \{ */ |