Refactor: VSE: Use C++ matrix BLI API

This PR explicitly declares integer type for `image_center_offs`, which
formalizes accidentally implemented correct behavior. Previously type
was float, all rhs types in expression were integers, so result was int
cast to float.

Comment is also added clarifying why integer must be used - float may
cause images to be interpolated, even when translation is set to 0.

There should be no functional changes.

Pull Request: https://projects.blender.org/blender/blender/pulls/133573
This commit is contained in:
Richard Antalik
2025-01-28 02:01:07 +01:00
committed by Richard Antalik
parent 17c98a2c8c
commit bf19960937
7 changed files with 117 additions and 135 deletions

View File

@@ -1062,8 +1062,8 @@ static void strip_draw_image_origin_and_outline(const bContext *C,
immUnbindProgram();
/* Outline. */
float strip_image_quad[4][2];
SEQ_image_transform_final_quad_get(CTX_data_scene(C), strip, strip_image_quad);
const blender::Array<blender::float2> strip_image_quad = SEQ_image_transform_final_quad_get(
CTX_data_scene(C), strip);
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
@@ -1080,10 +1080,10 @@ static void strip_draw_image_origin_and_outline(const bContext *C,
immUniformColor3fv(col);
immUniform1f("lineWidth", U.pixelsize);
immBegin(GPU_PRIM_LINE_LOOP, 4);
immVertex2f(pos, strip_image_quad[0][0], strip_image_quad[0][1]);
immVertex2f(pos, strip_image_quad[1][0], strip_image_quad[1][1]);
immVertex2f(pos, strip_image_quad[2][0], strip_image_quad[2][1]);
immVertex2f(pos, strip_image_quad[3][0], strip_image_quad[3][1]);
immVertex2f(pos, strip_image_quad[0].x, strip_image_quad[0].y);
immVertex2f(pos, strip_image_quad[1].x, strip_image_quad[1].y);
immVertex2f(pos, strip_image_quad[2].x, strip_image_quad[2].y);
immVertex2f(pos, strip_image_quad[3].x, strip_image_quad[3].y);
immEnd();
immUnbindProgram();
GPU_line_width(1);
@@ -1124,8 +1124,7 @@ static void text_selection_draw(const bContext *C, const Strip *strip, uint pos)
const blender::float3 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f, 0.0f};
const float view_aspect = scene->r.xasp / scene->r.yasp;
blender::float4x4 transform_mat;
SEQ_image_transform_matrix_get(scene, strip, transform_mat.ptr());
blender::float4x4 transform_mat = SEQ_image_transform_matrix_get(scene, strip);
blender::float4x3 selection_quad{
{character_start.position.x, line_y, 0.0f},
{character_start.position.x, line_y + text->line_height, 0.0f},
@@ -1169,8 +1168,7 @@ static void text_edit_draw_cursor(const bContext *C, const Strip *strip, uint po
const blender::float3 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f, 0.0f};
const float view_aspect = scene->r.xasp / scene->r.yasp;
blender::float4x4 transform_mat;
SEQ_image_transform_matrix_get(scene, strip, transform_mat.ptr());
blender::float4x4 transform_mat = SEQ_image_transform_matrix_get(scene, strip);
const blender::int2 cursor_position = strip_text_cursor_offset_to_position(text,
data->cursor_offset);
const float cursor_width = 10;
@@ -1217,8 +1215,7 @@ static void text_edit_draw_box(const bContext *C, const Strip *strip, uint pos)
const blender::float3 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f, 0.0f};
const float view_aspect = scene->r.xasp / scene->r.yasp;
blender::float4x4 transform_mat;
SEQ_image_transform_matrix_get(CTX_data_scene(C), strip, transform_mat.ptr());
blender::float4x4 transform_mat = SEQ_image_transform_matrix_get(CTX_data_scene(C), strip);
blender::float4x3 box_quad{
{float(text->text_boundbox.xmin), float(text->text_boundbox.ymin), 0.0f},
{float(text->text_boundbox.xmin), float(text->text_boundbox.ymax), 0.0f},

View File

@@ -442,8 +442,8 @@ void recurs_sel_seq(Strip *strip_meta)
bool strip_point_image_isect(const Scene *scene, const Strip *strip, float point_view[2])
{
float strip_image_quad[4][2];
SEQ_image_transform_final_quad_get(scene, strip, strip_image_quad);
const blender::Array<blender::float2> strip_image_quad = SEQ_image_transform_final_quad_get(
scene, strip);
return isect_point_quad_v2(point_view,
strip_image_quad[0],
strip_image_quad[1],
@@ -2025,8 +2025,8 @@ static bool strip_box_select_rect_image_isect(const Scene *scene,
const Strip *strip,
const rctf *rect)
{
float strip_image_quad[4][2];
SEQ_image_transform_final_quad_get(scene, strip, strip_image_quad);
const blender::Array<blender::float2> strip_image_quad = SEQ_image_transform_final_quad_get(
scene, strip);
float rect_quad[4][2] = {{rect->xmax, rect->ymax},
{rect->xmax, rect->ymin},
{rect->xmin, rect->ymin},

View File

@@ -674,8 +674,7 @@ static void cursor_set_by_mouse_position(const bContext *C, const wmEvent *event
/* Convert cursor coordinates to domain of CharInfo::position. */
const blender::float3 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f, 0.0f};
const float view_aspect = scene->r.xasp / scene->r.yasp;
blender::float4x4 transform_mat;
SEQ_image_transform_matrix_get(CTX_data_scene(C), strip, transform_mat.ptr());
blender::float4x4 transform_mat = SEQ_image_transform_matrix_get(CTX_data_scene(C), strip);
transform_mat = blender::math::invert(transform_mat);
mouse_loc.x /= view_aspect;

View File

@@ -170,8 +170,8 @@ static bool seq_snap_source_points_build_preview(const Scene *scene,
snap_data->source_snap_points.reinitialize(point_count_source);
int i = 0;
for (Strip *strip : snap_sources) {
float seq_image_quad[4][2];
SEQ_image_transform_final_quad_get(scene, strip, seq_image_quad);
const blender::Array<blender::float2> seq_image_quad = SEQ_image_transform_final_quad_get(
scene, strip);
for (int j = 0; j < 4; j++) {
snap_data->source_snap_points[i][0] = seq_image_quad[j][0];
@@ -449,8 +449,8 @@ static bool seq_snap_target_points_build_preview(const Scene *scene,
if (snap_mode & SEQ_SNAP_TO_STRIPS_PREVIEW) {
for (Strip *strip : snap_targets) {
float strip_image_quad[4][2];
SEQ_image_transform_final_quad_get(scene, strip, strip_image_quad);
const blender::Array<blender::float2> strip_image_quad = SEQ_image_transform_final_quad_get(
scene, strip);
for (int j = 0; j < 4; j++) {
snap_data->target_snap_points[i][0] = strip_image_quad[j][0];

View File

@@ -8,6 +8,8 @@
* \ingroup sequencer
*/
#include "BLI_array.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_span.hh"
struct ListBase;
@@ -92,22 +94,20 @@ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
* \param scene: Scene in which strips are located
* \param seq: Sequence to calculate transformed image quad
* \param apply_rotation: Apply sequence rotation transform to the quad
* \param r_quad: array of 4 2D vectors
* \return array of 4 2D vectors
*/
void SEQ_image_transform_quad_get(const Scene *scene,
const Strip *strip,
bool apply_rotation,
float r_quad[4][2]);
blender::Array<blender::float2> SEQ_image_transform_quad_get(const Scene *scene,
const Strip *strip,
bool apply_rotation);
/**
* Get 4 corner points of strip image. Corner vectors are in viewport space.
*
* \param scene: Scene in which strips are located
* \param seq: Sequence to calculate transformed image quad
* \param r_quad: array of 4 2D vectors
* \return array of 4 2D vectors
*/
void SEQ_image_transform_final_quad_get(const Scene *scene,
const Strip *strip,
float r_quad[4][2]);
blender::Array<blender::float2> SEQ_image_transform_final_quad_get(const Scene *scene,
const Strip *strip);
void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2]);
void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], float co_dst[2]);
@@ -134,8 +134,5 @@ void SEQ_image_transform_bounding_box_from_collection(Scene *scene,
*
* \param scene: Scene in which strips are located
* \param seq: Strip that is used to construct the matrix
* \param r_transform_matrix: Return value
*/
void SEQ_image_transform_matrix_get(const Scene *scene,
const Strip *strip,
float r_transform_matrix[4][4]);
blender::float4x4 SEQ_image_transform_matrix_get(const Scene *scene, const Strip *strip);

View File

@@ -21,7 +21,7 @@
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
#include "BLI_math_rotation.h"
#include "BLI_math_matrix.hh"
#include "BLI_path_utils.hh"
#include "BLI_rect.h"
#include "BLI_task.hh"
@@ -297,13 +297,12 @@ StripScreenQuad get_strip_screen_quad(const SeqRenderData *context, const Strip
const int y = context->recty;
float2 offset{x * 0.5f, y * 0.5f};
float quad[4][2];
SEQ_image_transform_final_quad_get(scene, strip, quad);
Array<float2> quad = SEQ_image_transform_final_quad_get(scene, strip);
const float scale = SEQ_rendersize_to_scale_factor(context->preview_render_size);
return StripScreenQuad{float2(quad[0]) * scale + offset,
float2(quad[1]) * scale + offset,
float2(quad[2]) * scale + offset,
float2(quad[3]) * scale + offset};
return StripScreenQuad{quad[0] * scale + offset,
quad[1] * scale + offset,
quad[2] * scale + offset,
quad[3] * scale + offset};
}
/* Is quad `a` fully contained (i.e. covered by) quad `b`? For that to happen,
@@ -459,30 +458,30 @@ static bool seq_need_scale_to_render_size(const Strip *strip, bool is_proxy_imag
return false;
}
static void sequencer_image_crop_transform_matrix(const Strip *strip,
const ImBuf *in,
const ImBuf *out,
const float image_scale_factor,
const float preview_scale_factor,
float r_transform_matrix[4][4])
static float4x4 sequencer_image_crop_transform_matrix(const Strip *strip,
const ImBuf *in,
const ImBuf *out,
const float image_scale_factor,
const float preview_scale_factor)
{
const StripTransform *transform = strip->data->transform;
const float scale_x = transform->scale_x * image_scale_factor;
const float scale_y = transform->scale_y * image_scale_factor;
const float image_center_offs_x = (out->x - in->x) / 2;
const float image_center_offs_y = (out->y - in->y) / 2;
const float translate_x = transform->xofs * preview_scale_factor + image_center_offs_x;
const float translate_y = transform->yofs * preview_scale_factor + image_center_offs_y;
const float pivot[3] = {in->x * transform->origin[0], in->y * transform->origin[1], 0.0f};
float rotation_matrix[3][3];
axis_angle_to_mat3_single(rotation_matrix, 'Z', transform->rotation);
loc_rot_size_to_mat4(r_transform_matrix,
float3{translate_x, translate_y, 0.0f},
rotation_matrix,
float3{scale_x, scale_y, 1.0f});
transform_pivot_set_m4(r_transform_matrix, pivot);
invert_m4(r_transform_matrix);
/* This value is intentionally kept as integer. Otherwise images with odd dimensions would
* be translated to center of canvas by non-integer value, which would cause it to be
* interpolated. Interpolation with 0 user defined translation is unwanted behavior. */
const int3 image_center_offs((out->x - in->x) / 2, (out->y - in->y) / 2, 0);
const float3 translation(
transform->xofs * preview_scale_factor, transform->yofs * preview_scale_factor, 0.0f);
const float3 rotation(0.0f, 0.0f, transform->rotation);
const float2 scale(transform->scale_x * image_scale_factor,
transform->scale_y * image_scale_factor);
const float3 pivot(in->x * transform->origin[0], in->y * transform->origin[1], 0.0f);
const float4x4 matrix = math::from_loc_rot_scale<float4x4>(
translation + float3(image_center_offs), rotation, scale);
const float4x4 mat_pivot = math::from_origin_transform(matrix, pivot);
return math::invert(mat_pivot);
}
static void sequencer_image_crop_init(const Strip *strip,
@@ -558,9 +557,8 @@ static void sequencer_preprocess_transform_crop(
const bool do_scale_to_render_size = seq_need_scale_to_render_size(strip, is_proxy_image);
const float image_scale_factor = do_scale_to_render_size ? 1.0f : preview_scale_factor;
float transform_matrix[4][4];
sequencer_image_crop_transform_matrix(
strip, in, out, image_scale_factor, preview_scale_factor, transform_matrix);
float4x4 matrix = sequencer_image_crop_transform_matrix(
strip, in, out, image_scale_factor, 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. */
@@ -591,7 +589,12 @@ static void sequencer_preprocess_transform_crop(
break;
}
IMB_transform(in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, transform_matrix, &source_crop);
IMB_transform(in,
out,
IMB_TRANSFORM_MODE_CROP_SRC,
filter,
(float(*)[4])(matrix.base_ptr()),
&source_crop);
if (is_strip_covering_screen(context, strip)) {
out->planes = in->planes;

View File

@@ -12,8 +12,7 @@
#include "DNA_sequence_types.h"
#include "BLI_listbase.h"
#include "BLI_math_matrix.h"
#include "BLI_math_rotation.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
@@ -30,6 +29,8 @@
#include "sequencer.hh"
#include "strip_time.hh"
using namespace blender;
bool SEQ_transform_single_image_check(const Strip *strip)
{
return (strip->flag & SEQ_SINGLE_FRAME_CONTENT) != 0;
@@ -603,93 +604,79 @@ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
mul_v2_v2(r_origin, viewport_pixel_aspect);
}
void SEQ_image_transform_matrix_get(const Scene *scene,
const Strip *strip,
float r_transform_matrix[4][4])
static float4x4 seq_image_transform_matrix_get_ex(const Scene *scene,
const Strip *strip,
bool apply_rotation = true)
{
float image_size[2] = {float(scene->r.xsch), float(scene->r.ysch)};
float3 image_size(float(scene->r.xsch), float(scene->r.ysch), 0.0f);
if (ELEM(strip->type, STRIP_TYPE_MOVIE, STRIP_TYPE_IMAGE)) {
image_size[0] = strip->data->stripdata->orig_width;
image_size[1] = strip->data->stripdata->orig_height;
image_size.x = strip->data->stripdata->orig_width;
image_size.y = strip->data->stripdata->orig_height;
}
StripTransform *transform = strip->data->transform;
float rotation_matrix[3][3];
axis_angle_to_mat3_single(rotation_matrix, 'Z', transform->rotation);
loc_rot_size_to_mat4(r_transform_matrix,
blender::float3{transform->xofs, transform->yofs, 0.0f},
rotation_matrix,
blender::float3{transform->scale_x, transform->scale_y, 1.0f});
const float origin[2] = {image_size[0] * transform->origin[0],
image_size[1] * transform->origin[1]};
const float pivot[3] = {origin[0] - (image_size[0] / 2), origin[1] - (image_size[1] / 2), 0.0f};
transform_pivot_set_m4(r_transform_matrix, pivot);
const StripTransform *transform = strip->data->transform;
const float3 origin(
image_size.x * transform->origin[0], image_size[1] * transform->origin[1], 0.0f);
const float3 translation(transform->xofs, transform->yofs, 0.0f);
const float3 rotation(0.0f, 0.0f, apply_rotation ? transform->rotation : 0.0f);
const float2 scale(transform->scale_x, transform->scale_y);
const float3 pivot = origin - (image_size / 2);
const float4x4 matrix = math::from_loc_rot_scale<float4x4>(translation, rotation, scale);
return math::from_origin_transform(matrix, pivot);
}
static void strip_image_transform_quad_get_ex(const Scene *scene,
const Strip *strip,
bool apply_rotation,
float r_quad[4][2])
float4x4 SEQ_image_transform_matrix_get(const Scene *scene, const Strip *strip)
{
StripTransform *transform = strip->data->transform;
const StripCrop *crop = strip->data->crop;
return seq_image_transform_matrix_get_ex(scene, strip);
}
float image_size[2] = {float(scene->r.xsch), float(scene->r.ysch)};
static Array<float2> strip_image_transform_quad_get_ex(const Scene *scene,
const Strip *strip,
bool apply_rotation)
{
float3 image_size(float(scene->r.xsch), float(scene->r.ysch), 0.0f);
if (ELEM(strip->type, STRIP_TYPE_MOVIE, STRIP_TYPE_IMAGE)) {
image_size[0] = strip->data->stripdata->orig_width;
image_size[1] = strip->data->stripdata->orig_height;
image_size.x = strip->data->stripdata->orig_width;
image_size.y = strip->data->stripdata->orig_height;
}
float transform_matrix[4][4];
float rotation_matrix[3][3];
axis_angle_to_mat3_single(rotation_matrix, 'Z', apply_rotation ? transform->rotation : 0.0f);
loc_rot_size_to_mat4(transform_matrix,
blender::float3{transform->xofs, transform->yofs, 0.0f},
rotation_matrix,
blender::float3{transform->scale_x, transform->scale_y, 1.0f});
const float origin[2] = {image_size[0] * transform->origin[0],
image_size[1] * transform->origin[1]};
const float pivot[3] = {origin[0] - (image_size[0] / 2), origin[1] - (image_size[1] / 2), 0.0f};
transform_pivot_set_m4(transform_matrix, pivot);
const StripCrop *crop = strip->data->crop;
float3 quad[4]{
{(image_size[0] / 2) - crop->right, (image_size[1] / 2) - crop->top, 0.0f},
{(image_size[0] / 2) - crop->right, (-image_size[1] / 2) + crop->bottom, 0.0f},
{(-image_size[0] / 2) + crop->left, (-image_size[1] / 2) + crop->bottom, 0.0f},
{(-image_size[0] / 2) + crop->left, (image_size[1] / 2) - crop->top, 0.0f},
};
float quad_temp[4][3];
for (int i = 0; i < 4; i++) {
zero_v3(quad_temp[i]);
}
quad_temp[0][0] = (image_size[0] / 2) - crop->right;
quad_temp[0][1] = (image_size[1] / 2) - crop->top;
quad_temp[1][0] = (image_size[0] / 2) - crop->right;
quad_temp[1][1] = (-image_size[1] / 2) + crop->bottom;
quad_temp[2][0] = (-image_size[0] / 2) + crop->left;
quad_temp[2][1] = (-image_size[1] / 2) + crop->bottom;
quad_temp[3][0] = (-image_size[0] / 2) + crop->left;
quad_temp[3][1] = (image_size[1] / 2) - crop->top;
float mirror[2];
const float3 viewport_pixel_aspect(scene->r.xasp / scene->r.yasp, 1.0f, 1.0f);
const float4x4 matrix = seq_image_transform_matrix_get_ex(scene, strip, apply_rotation);
float3 mirror;
SEQ_image_transform_mirror_factor_get(strip, mirror);
const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
Array<float2> quad_transformed;
quad_transformed.reinitialize(4);
for (int i = 0; i < 4; i++) {
mul_m4_v3(transform_matrix, quad_temp[i]);
mul_v2_v2(quad_temp[i], mirror);
mul_v2_v2(quad_temp[i], viewport_pixel_aspect);
copy_v2_v2(r_quad[i], quad_temp[i]);
float3 point = math::transform_point(matrix, quad[i]);
point *= mirror;
point *= viewport_pixel_aspect;
copy_v2_v2(quad_transformed[i], point);
}
return quad_transformed;
}
void SEQ_image_transform_quad_get(const Scene *scene,
const Strip *strip,
bool apply_rotation,
float r_quad[4][2])
Array<float2> SEQ_image_transform_quad_get(const Scene *scene,
const Strip *strip,
bool apply_rotation)
{
strip_image_transform_quad_get_ex(scene, strip, apply_rotation, r_quad);
return strip_image_transform_quad_get_ex(scene, strip, apply_rotation);
}
void SEQ_image_transform_final_quad_get(const Scene *scene, const Strip *strip, float r_quad[4][2])
Array<float2> SEQ_image_transform_final_quad_get(const Scene *scene, const Strip *strip)
{
strip_image_transform_quad_get_ex(scene, strip, true, r_quad);
return strip_image_transform_quad_get_ex(scene, strip, true);
}
void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2])
@@ -712,8 +699,7 @@ void SEQ_image_transform_bounding_box_from_collection(Scene *scene,
{
INIT_MINMAX2(r_min, r_max);
for (Strip *strip : strips) {
float quad[4][2];
SEQ_image_transform_quad_get(scene, strip, apply_rotation, quad);
Array<float2> quad = SEQ_image_transform_quad_get(scene, strip, apply_rotation);
for (int i = 0; i < 4; i++) {
minmax_v2v2_v2(r_min, r_max, quad[i]);
}