Changeset View
Changeset View
Standalone View
Standalone View
source/blender/sequencer/intern/render.c
| Show First 20 Lines • Show All 453 Lines • ▼ Show 20 Lines | static bool seq_input_have_to_preprocess(const SeqRenderData *context, | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| typedef struct ImageTransformThreadInitData { | typedef struct ImageTransformThreadInitData { | ||||
| ImBuf *ibuf_source; | ImBuf *ibuf_source; | ||||
| ImBuf *ibuf_out; | ImBuf *ibuf_out; | ||||
| StripTransform *transform; | Sequence *seq; | ||||
| float scale_to_fit; | |||||
| float image_scale_factor; | |||||
| float preview_scale_factor; | float preview_scale_factor; | ||||
| bool is_proxy_image; | |||||
| bool for_render; | bool for_render; | ||||
| } ImageTransformThreadInitData; | } ImageTransformThreadInitData; | ||||
| typedef struct ImageTransformThreadData { | typedef struct ImageTransformThreadData { | ||||
| ImBuf *ibuf_source; | ImBuf *ibuf_source; | ||||
| ImBuf *ibuf_out; | ImBuf *ibuf_out; | ||||
| StripTransform *transform; | Sequence *seq; | ||||
| float scale_to_fit; | |||||
| /* image_scale_factor is used to scale proxies to correct preview size. */ | /* image_scale_factor is used to scale proxies to correct preview size. */ | ||||
| float image_scale_factor; | float image_scale_factor; | ||||
| /* Preview scale factor is needed to correct translation to match preview size. */ | /* Preview scale factor is needed to correct translation to match preview size. */ | ||||
| float preview_scale_factor; | float preview_scale_factor; | ||||
| float crop_scale_factor; | |||||
| bool for_render; | bool for_render; | ||||
| int start_line; | int start_line; | ||||
| int tot_line; | int tot_line; | ||||
| } ImageTransformThreadData; | } ImageTransformThreadData; | ||||
| static void sequencer_image_transform_init(void *handle_v, | /** | ||||
| * Effect, mask and scene in strip input strips are rendered in preview resolution. | |||||
| * They are already down-scaled. #input_preprocess() does not expect this to happen. | |||||
| * Other strip types are rendered with original media resolution, unless proxies are | |||||
| * enabled for them. With proxies `is_proxy_image` will be set correctly to true. | |||||
| */ | |||||
| static bool seq_need_scale_to_render_size(const Sequence *seq, bool is_proxy_image) | |||||
| { | |||||
| if (is_proxy_image) { | |||||
| return true; | |||||
| } | |||||
| if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->type == SEQ_TYPE_MASK || | |||||
| seq->type == SEQ_TYPE_META || | |||||
| (seq->type == SEQ_TYPE_SCENE && ((seq->flag & SEQ_SCENE_STRIPS) != 0))) { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static void sequencer_image_crop_transform_init(void *handle_v, | |||||
| int start_line, | int start_line, | ||||
| int tot_line, | int tot_line, | ||||
| void *init_data_v) | void *init_data_v) | ||||
| { | { | ||||
| ImageTransformThreadData *handle = (ImageTransformThreadData *)handle_v; | ImageTransformThreadData *handle = (ImageTransformThreadData *)handle_v; | ||||
| const ImageTransformThreadInitData *init_data = (ImageTransformThreadInitData *)init_data_v; | const ImageTransformThreadInitData *init_data = (ImageTransformThreadInitData *)init_data_v; | ||||
| handle->ibuf_source = init_data->ibuf_source; | handle->ibuf_source = init_data->ibuf_source; | ||||
| handle->ibuf_out = init_data->ibuf_out; | handle->ibuf_out = init_data->ibuf_out; | ||||
| handle->transform = init_data->transform; | handle->seq = init_data->seq; | ||||
| handle->image_scale_factor = init_data->image_scale_factor; | |||||
| handle->preview_scale_factor = init_data->preview_scale_factor; | handle->preview_scale_factor = init_data->preview_scale_factor; | ||||
| handle->for_render = init_data->for_render; | if (seq_need_scale_to_render_size(init_data->seq, init_data->is_proxy_image)) { | ||||
| handle->image_scale_factor = 1.0f; | |||||
| } | |||||
| else { | |||||
| handle->image_scale_factor = handle->preview_scale_factor; | |||||
| } | |||||
| /* Proxy image is smaller, so crop values must be corrected by proxy scale factor. | |||||
| * Proxy scale factor always matches preview_scale_factor. */ | |||||
| handle->crop_scale_factor = seq_need_scale_to_render_size(init_data->seq, | |||||
| init_data->is_proxy_image) ? | |||||
| init_data->preview_scale_factor : | |||||
| 1.0f; | |||||
| handle->for_render = init_data->for_render; | |||||
| handle->start_line = start_line; | handle->start_line = start_line; | ||||
| handle->tot_line = tot_line; | handle->tot_line = tot_line; | ||||
| } | } | ||||
| static void *sequencer_image_transform_do_thread(void *data_v) | static void *sequencer_image_crop_transform_do_thread(void *data_v) | ||||
| { | { | ||||
| const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v; | const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v; | ||||
| const StripTransform *transform = data->transform; | const StripTransform *transform = data->seq->strip->transform; | ||||
| const float scale_x = transform->scale_x * data->image_scale_factor; | const float scale_x = transform->scale_x * data->image_scale_factor; | ||||
| const float scale_y = transform->scale_y * data->image_scale_factor; | const float scale_y = transform->scale_y * data->image_scale_factor; | ||||
| const float image_center_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2; | const float image_center_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2; | ||||
| const float image_center_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2; | const float image_center_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2; | ||||
| const float translate_x = transform->xofs * data->preview_scale_factor + image_center_offs_x; | const float translate_x = transform->xofs * data->preview_scale_factor + image_center_offs_x; | ||||
| const float translate_y = transform->yofs * data->preview_scale_factor + image_center_offs_y; | const float translate_y = transform->yofs * data->preview_scale_factor + image_center_offs_y; | ||||
| const float pivot[2] = {data->ibuf_source->x / 2, data->ibuf_source->y / 2}; | const float pivot[2] = {data->ibuf_source->x / 2, data->ibuf_source->y / 2}; | ||||
| float transform_matrix[3][3]; | float transform_matrix[3][3]; | ||||
| loc_rot_size_to_mat3(transform_matrix, | loc_rot_size_to_mat3(transform_matrix, | ||||
| (const float[]){translate_x, translate_y}, | (const float[]){translate_x, translate_y}, | ||||
| transform->rotation, | transform->rotation, | ||||
| (const float[]){scale_x, scale_y}); | (const float[]){scale_x, scale_y}); | ||||
| invert_m3(transform_matrix); | |||||
| transform_pivot_set_m3(transform_matrix, pivot); | transform_pivot_set_m3(transform_matrix, pivot); | ||||
| invert_m3(transform_matrix); | |||||
| /* Image crop is done by offsetting image boundary limits. */ | |||||
| const StripCrop *c = data->seq->strip->crop; | |||||
| const int left = c->left * data->crop_scale_factor; | |||||
| const int right = c->right * data->crop_scale_factor; | |||||
| const int top = c->top * data->crop_scale_factor; | |||||
| const int bottom = c->bottom * data->crop_scale_factor; | |||||
| const float source_pixel_range_max[2] = {data->ibuf_source->x - right, | |||||
| data->ibuf_source->y - top}; | |||||
| const float source_pixel_range_min[2] = {left, bottom}; | |||||
| const int width = data->ibuf_out->x; | const int width = data->ibuf_out->x; | ||||
| for (int yi = data->start_line; yi < data->start_line + data->tot_line; yi++) { | for (int yi = data->start_line; yi < data->start_line + data->tot_line; yi++) { | ||||
| for (int xi = 0; xi < width; xi++) { | for (int xi = 0; xi < width; xi++) { | ||||
| float uv[2] = {xi, yi}; | float uv[2] = {xi, yi}; | ||||
| mul_v2_m3v2(uv, transform_matrix, uv); | mul_v2_m3v2(uv, transform_matrix, uv); | ||||
| if (source_pixel_range_min[0] >= uv[0] || uv[0] >= source_pixel_range_max[0] || | |||||
| source_pixel_range_min[1] >= uv[1] || uv[1] >= source_pixel_range_max[1]) { | |||||
| continue; | |||||
| } | |||||
| if (data->for_render) { | if (data->for_render) { | ||||
| bilinear_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi); | bilinear_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi); | ||||
| } | } | ||||
| else { | else { | ||||
| nearest_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi); | nearest_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 31 Lines | while (a--) { | ||||
| rt_float[2] *= fmul; | rt_float[2] *= fmul; | ||||
| rt_float[3] *= fmul; | rt_float[3] *= fmul; | ||||
| rt_float += 4; | rt_float += 4; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Effect, mask and scene in strip input strips are rendered in preview resolution. | |||||
| * They are already down-scaled. #input_preprocess() does not expect this to happen. | |||||
| * Other strip types are rendered with original media resolution, unless proxies are | |||||
| * enabled for them. With proxies `is_proxy_image` will be set correctly to true. | |||||
| */ | |||||
| static bool seq_need_scale_to_render_size(const Sequence *seq, bool is_proxy_image) | |||||
| { | |||||
| if (is_proxy_image) { | |||||
| return true; | |||||
| } | |||||
| if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->type == SEQ_TYPE_MASK || | |||||
| seq->type == SEQ_TYPE_META || | |||||
| (seq->type == SEQ_TYPE_SCENE && ((seq->flag & SEQ_SCENE_STRIPS) != 0))) { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| static ImBuf *input_preprocess(const SeqRenderData *context, | static ImBuf *input_preprocess(const SeqRenderData *context, | ||||
| Sequence *seq, | Sequence *seq, | ||||
| float timeline_frame, | float timeline_frame, | ||||
| ImBuf *ibuf, | ImBuf *ibuf, | ||||
| const bool is_proxy_image) | const bool is_proxy_image) | ||||
| { | { | ||||
| Scene *scene = context->scene; | Scene *scene = context->scene; | ||||
| ImBuf *preprocessed_ibuf = NULL; | ImBuf *preprocessed_ibuf = NULL; | ||||
| /* Deinterlace. */ | /* Deinterlace. */ | ||||
| if ((seq->flag & SEQ_FILTERY) && !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) { | if ((seq->flag & SEQ_FILTERY) && !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) { | ||||
| /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */ | /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */ | ||||
| preprocessed_ibuf = IMB_makeSingleUser(ibuf); | preprocessed_ibuf = IMB_makeSingleUser(ibuf); | ||||
| ibuf = preprocessed_ibuf; | ibuf = preprocessed_ibuf; | ||||
| IMB_filtery(preprocessed_ibuf); | IMB_filtery(preprocessed_ibuf); | ||||
| } | } | ||||
| /* Get scale factor if preview resolution doesn't match project resolution. */ | if (sequencer_use_crop(seq) || sequencer_use_transform(seq) || context->rectx != ibuf->x || | ||||
| float preview_scale_factor; | context->recty != ibuf->y) { | ||||
| if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) { | |||||
| preview_scale_factor = (float)scene->r.size / 100; | |||||
| } | |||||
| else { | |||||
| preview_scale_factor = SEQ_rendersize_to_scale_factor(context->preview_render_size); | |||||
| } | |||||
| if (sequencer_use_crop(seq)) { | |||||
| /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */ | |||||
| preprocessed_ibuf = IMB_makeSingleUser(ibuf); | |||||
| ibuf = preprocessed_ibuf; | |||||
| const int width = ibuf->x; | |||||
| const int height = ibuf->y; | |||||
| const StripCrop *c = seq->strip->crop; | |||||
| /* Proxy image is smaller, so crop values must be corrected by proxy scale factor. | |||||
| * Proxy scale factor always matches preview_scale_factor. */ | |||||
| const float crop_scale_factor = seq_need_scale_to_render_size(seq, is_proxy_image) ? | |||||
| preview_scale_factor : | |||||
| 1.0f; | |||||
| const int left = c->left * crop_scale_factor; | |||||
| const int right = c->right * crop_scale_factor; | |||||
| const int top = c->top * crop_scale_factor; | |||||
| const int bottom = c->bottom * crop_scale_factor; | |||||
| const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; | |||||
| /* Left. */ | |||||
| IMB_rectfill_area_replace(preprocessed_ibuf, col, 0, 0, left, height); | |||||
| /* Bottom. */ | |||||
| IMB_rectfill_area_replace(preprocessed_ibuf, col, left, 0, width, bottom); | |||||
| /* Right. */ | |||||
| IMB_rectfill_area_replace(preprocessed_ibuf, col, width - right, bottom, width, height); | |||||
| /* Top. */ | |||||
| IMB_rectfill_area_replace(preprocessed_ibuf, col, left, height - top, width - right, height); | |||||
| } | |||||
| if (sequencer_use_transform(seq) || context->rectx != ibuf->x || context->recty != ibuf->y) { | |||||
| const int x = context->rectx; | const int x = context->rectx; | ||||
| const int y = context->recty; | const int y = context->recty; | ||||
| preprocessed_ibuf = IMB_allocImBuf(x, y, 32, ibuf->rect_float ? IB_rectfloat : IB_rect); | preprocessed_ibuf = IMB_allocImBuf(x, y, 32, ibuf->rect_float ? IB_rectfloat : IB_rect); | ||||
| ImageTransformThreadInitData init_data = {NULL}; | ImageTransformThreadInitData init_data = {NULL}; | ||||
| init_data.ibuf_source = ibuf; | init_data.ibuf_source = ibuf; | ||||
| init_data.ibuf_out = preprocessed_ibuf; | init_data.ibuf_out = preprocessed_ibuf; | ||||
| init_data.transform = seq->strip->transform; | init_data.seq = seq; | ||||
| if (seq_need_scale_to_render_size(seq, is_proxy_image)) { | init_data.is_proxy_image = is_proxy_image; | ||||
| init_data.image_scale_factor = 1.0f; | |||||
| /* Get scale factor if preview resolution doesn't match project resolution. */ | |||||
| if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) { | |||||
| init_data.preview_scale_factor = (float)scene->r.size / 100; | |||||
| } | } | ||||
| else { | else { | ||||
| init_data.image_scale_factor = preview_scale_factor; | init_data.preview_scale_factor = SEQ_rendersize_to_scale_factor( | ||||
| context->preview_render_size); | |||||
| } | } | ||||
| init_data.preview_scale_factor = preview_scale_factor; | |||||
| init_data.for_render = context->for_render; | init_data.for_render = context->for_render; | ||||
| IMB_processor_apply_threaded(context->recty, | IMB_processor_apply_threaded(context->recty, | ||||
| sizeof(ImageTransformThreadData), | sizeof(ImageTransformThreadData), | ||||
| &init_data, | &init_data, | ||||
| sequencer_image_transform_init, | sequencer_image_crop_transform_init, | ||||
| sequencer_image_transform_do_thread); | sequencer_image_crop_transform_do_thread); | ||||
| seq_imbuf_assign_spaces(scene, preprocessed_ibuf); | seq_imbuf_assign_spaces(scene, preprocessed_ibuf); | ||||
| IMB_metadata_copy(preprocessed_ibuf, ibuf); | IMB_metadata_copy(preprocessed_ibuf, ibuf); | ||||
| IMB_freeImBuf(ibuf); | IMB_freeImBuf(ibuf); | ||||
| } | } | ||||
| /* Duplicate ibuf if we still have original. */ | /* Duplicate ibuf if we still have original. */ | ||||
| if (preprocessed_ibuf == NULL) { | if (preprocessed_ibuf == NULL) { | ||||
| preprocessed_ibuf = IMB_makeSingleUser(ibuf); | preprocessed_ibuf = IMB_makeSingleUser(ibuf); | ||||
| ▲ Show 20 Lines • Show All 1,367 Lines • Show Last 20 Lines | |||||