Refactor: Use C++ types for vectors strip image transform code

All 2D vectors related to image transform code were changed to float2.
Previously, it was decided, that 4x4 matrix should be used for 2D
affine transform, but this is changed to 3x3 now.

Texture painting code did rely on `IMB_transform` with 4x4 matrix.
To avoid large changes, I have added function
`BLI_rctf_transform_calc_m3_pivot_min`.

Main motivation is cleaner code - ease of use of c++ API, and avoiding
returning values by arguments.

Pull Request: https://projects.blender.org/blender/blender/pulls/133692
This commit is contained in:
Richard Antalik
2025-02-17 11:23:00 +01:00
committed by Richard Antalik
parent f89a075015
commit 2a44bdfbd0
21 changed files with 193 additions and 185 deletions

View File

@@ -63,6 +63,7 @@ void BLI_rctf_transform_pt_v(const rctf *dst,
void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y);
void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]);
void BLI_rctf_transform_calc_m3_pivot_min(const rctf *dst, const rctf *src, float matrix[3][3]);
void BLI_rctf_translate(struct rctf *rect, float x, float y);
void BLI_rcti_translate(struct rcti *rect, int x, int y);

View File

@@ -23,6 +23,7 @@
/* avoid including BLI_math */
static void unit_m4(float m[4][4]);
static void unit_m3(float m[3][3]);
bool BLI_rcti_is_empty(const rcti *rect)
{
@@ -553,6 +554,16 @@ void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, floa
BLI_rctf_transform_calc_m4_pivot_min_ex(dst, src, matrix, 0, 1);
}
void BLI_rctf_transform_calc_m3_pivot_min(const rctf *dst, const rctf *src, float matrix[3][3])
{
unit_m3(matrix);
matrix[0][0] = BLI_rctf_size_x(src) / BLI_rctf_size_x(dst);
matrix[1][1] = BLI_rctf_size_y(src) / BLI_rctf_size_y(dst);
matrix[2][0] = (src->xmin - dst->xmin) * matrix[1][1];
matrix[2][1] = (src->ymin - dst->ymin) * matrix[0][0];
}
void BLI_rcti_translate(rcti *rect, int x, int y)
{
rect->xmin += x;
@@ -1128,3 +1139,11 @@ static void unit_m4(float m[4][4])
m[2][0] = m[2][1] = m[2][3] = 0.0f;
m[3][0] = m[3][1] = m[3][2] = 0.0f;
}
static void unit_m3(float m[3][3])
{
m[0][0] = m[1][1] = m[2][2] = 1.0f;
m[0][1] = m[0][2] = 0.0f;
m[1][0] = m[1][2] = 0.0f;
m[2][0] = m[2][1] = 0.0f;
}

View File

@@ -291,7 +291,7 @@ void ScreenSpaceDrawingMode::do_full_update_texture_slot(const TextureInfo &text
/* IMB_transform works in a non-consistent space. This should be documented or fixed!.
* Construct a variant of the info_uv_to_texture that adds the texel space
* transformation. */
float4x4 uv_to_texel;
float3x3 uv_to_texel;
rctf texture_area;
rctf tile_area;
@@ -302,7 +302,7 @@ void ScreenSpaceDrawingMode::do_full_update_texture_slot(const TextureInfo &text
tile_buffer.x * (texture_info.clipping_uv_bounds.xmax - image_tile.get_tile_x_offset()),
tile_buffer.y * (texture_info.clipping_uv_bounds.ymin - image_tile.get_tile_y_offset()),
tile_buffer.y * (texture_info.clipping_uv_bounds.ymax - image_tile.get_tile_y_offset()));
BLI_rctf_transform_calc_m4_pivot_min(&tile_area, &texture_area, uv_to_texel.ptr());
BLI_rctf_transform_calc_m3_pivot_min(&tile_area, &texture_area, uv_to_texel.ptr());
uv_to_texel = math::invert(uv_to_texel);
rctf crop_rect;
@@ -321,7 +321,7 @@ void ScreenSpaceDrawingMode::do_full_update_texture_slot(const TextureInfo &text
&texture_buffer,
transform_mode,
IMB_FILTER_NEAREST,
uv_to_texel.ptr(),
uv_to_texel,
crop_rect_ptr);
}

View File

@@ -3418,7 +3418,8 @@ static int sequencer_set_2d_cursor_exec(bContext *C, wmOperator *op)
float cursor_pixel[2];
RNA_float_get_array(op->ptr, "location", cursor_pixel);
SEQ_image_preview_unit_from_px(scene, cursor_pixel, sseq->cursor);
blender::float2 cursor_region = SEQ_image_preview_unit_from_px(scene, cursor_pixel);
copy_v2_v2(sseq->cursor, cursor_region);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_SEQUENCER, nullptr);

View File

@@ -1069,8 +1069,8 @@ static void strip_draw_image_origin_and_outline(const bContext *C,
return;
}
float origin[2];
SEQ_image_transform_origin_offset_pixelspace_get(CTX_data_scene(C), strip, origin);
const blender::float2 origin = SEQ_image_transform_origin_offset_pixelspace_get(
CTX_data_scene(C), strip);
/* Origin. */
GPUVertFormat *format = immVertexFormat();
@@ -1146,14 +1146,14 @@ static void text_selection_draw(const bContext *C, const Strip *strip, uint pos)
const float line_y = character_start.position.y + text->font_descender;
const blender::float3 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f, 0.0f};
const blender::float2 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f};
const float view_aspect = scene->r.xasp / scene->r.yasp;
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},
{character_end.position.x + character_end.advance_x, line_y + text->line_height, 0.0f},
{character_end.position.x + character_end.advance_x, line_y, 0.0f},
blender::float3x3 transform_mat = SEQ_image_transform_matrix_get(scene, strip);
blender::float4x2 selection_quad{
{character_start.position.x, line_y},
{character_start.position.x, line_y + text->line_height},
{character_end.position.x + character_end.advance_x, line_y + text->line_height},
{character_end.position.x + character_end.advance_x, line_y},
};
immBegin(GPU_PRIM_TRIS, 6);
@@ -1190,9 +1190,9 @@ static void text_edit_draw_cursor(const bContext *C, const Strip *strip, uint po
const TextVarsRuntime *text = data->runtime;
const Scene *scene = CTX_data_scene(C);
const blender::float3 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f, 0.0f};
const blender::float2 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f};
const float view_aspect = scene->r.xasp / scene->r.yasp;
blender::float4x4 transform_mat = SEQ_image_transform_matrix_get(scene, strip);
blender::float3x3 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;
@@ -1208,13 +1208,13 @@ static void text_edit_draw_cursor(const bContext *C, const Strip *strip, uint po
cursor_coords.x, float(text_boundbox.xmin), float(text_boundbox.xmax));
cursor_coords = coords_region_view_align(UI_view2d_fromcontext(C), cursor_coords);
blender::float4x3 cursor_quad{
{cursor_coords.x, cursor_coords.y, 0.0f},
{cursor_coords.x, cursor_coords.y + text->line_height, 0.0f},
{cursor_coords.x + cursor_width, cursor_coords.y + text->line_height, 0.0f},
{cursor_coords.x + cursor_width, cursor_coords.y, 0.0f},
blender::float4x2 cursor_quad{
{cursor_coords.x, cursor_coords.y},
{cursor_coords.x, cursor_coords.y + text->line_height},
{cursor_coords.x + cursor_width, cursor_coords.y + text->line_height},
{cursor_coords.x + cursor_width, cursor_coords.y},
};
const blender::float3 descender_offs{0.0f, float(text->font_descender), 0.0f};
const blender::float2 descender_offs{0.0f, float(text->font_descender)};
immBegin(GPU_PRIM_TRIS, 6);
immUniformThemeColor(TH_SEQ_TEXT_CURSOR);
@@ -1237,14 +1237,14 @@ static void text_edit_draw_box(const bContext *C, const Strip *strip, uint pos)
const TextVarsRuntime *text = data->runtime;
const Scene *scene = CTX_data_scene(C);
const blender::float3 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f, 0.0f};
const blender::float2 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.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);
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},
{float(text->text_boundbox.xmax), float(text->text_boundbox.ymax), 0.0f},
{float(text->text_boundbox.xmax), float(text->text_boundbox.ymin), 0.0f},
blender::float3x3 transform_mat = SEQ_image_transform_matrix_get(CTX_data_scene(C), strip);
blender::float4x2 box_quad{
{float(text->text_boundbox.xmin), float(text->text_boundbox.ymin)},
{float(text->text_boundbox.xmin), float(text->text_boundbox.ymax)},
{float(text->text_boundbox.xmax), float(text->text_boundbox.ymax)},
{float(text->text_boundbox.xmax), float(text->text_boundbox.ymin)},
};
GPU_blend(GPU_BLEND_NONE);

View File

@@ -728,8 +728,7 @@ static Strip *strip_select_seq_from_preview(
float center_dist_sq_test = 0.0f;
if (center) {
/* Detect overlapping center points (scaled by the zoom level). */
float co[2];
SEQ_image_transform_origin_offset_pixelspace_get(scene, strip, co);
blender::float2 co = SEQ_image_transform_origin_offset_pixelspace_get(scene, strip);
sub_v2_v2(co, mouseco_view);
mul_v2_v2(co, center_scale_px);
center_dist_sq_test = len_squared_v2(co);

View File

@@ -668,13 +668,13 @@ static void cursor_set_by_mouse_position(const bContext *C, const wmEvent *event
int2 mval_region;
WM_event_drag_start_mval(event, CTX_wm_region(C), mval_region);
float3 mouse_loc;
float2 mouse_loc;
UI_view2d_region_to_view(v2d, mval_region.x, mval_region.y, &mouse_loc.x, &mouse_loc.y);
/* 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 blender::float2 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.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);
blender::float3x3 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

@@ -6,6 +6,7 @@
* \ingroup spseq
*/
#include "BLI_bounds_types.hh"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -294,13 +295,13 @@ static void seq_view_collection_rect_preview(Scene *scene,
blender::Span<Strip *> strips,
rctf *rect)
{
float min[2], max[2];
SEQ_image_transform_bounding_box_from_collection(scene, strips, true, min, max);
const blender::Bounds<blender::float2> box = SEQ_image_transform_bounding_box_from_collection(
scene, strips, true);
rect->xmin = min[0];
rect->xmax = max[0];
rect->ymin = min[1];
rect->ymax = max[1];
rect->xmin = box.min[0];
rect->xmax = box.max[0];
rect->ymin = box.min[1];
rect->ymax = box.max[1];
float minsize = min_ff(BLI_rctf_size_x(rect), BLI_rctf_size_y(rect));

View File

@@ -877,9 +877,7 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
GPU_depth_mask(false);
GPU_depth_test(GPU_DEPTH_NONE);
float cursor_pixel[2];
SEQ_image_preview_unit_to_px(scene, sseq->cursor, cursor_pixel);
const blender::float2 cursor_pixel = SEQ_image_preview_unit_to_px(scene, sseq->cursor);
DRW_draw_cursor_2d_ex(region, cursor_pixel);
}

View File

@@ -125,7 +125,8 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
}
else if (t->spacetype == SPACE_SEQ) {
if (t->options & CTX_CURSOR) {
SEQ_image_preview_unit_to_px(t->scene, r_aspect, r_aspect);
const float2 aspect = SEQ_image_preview_unit_to_px(t->scene, r_aspect);
copy_v2_v2(r_aspect, aspect);
}
}
else if (t->spacetype == SPACE_CLIP) {

View File

@@ -46,8 +46,7 @@ static TransData *SeqToTransData(const Scene *scene,
int vert_index)
{
const StripTransform *transform = strip->data->transform;
float origin[2];
SEQ_image_transform_origin_offset_pixelspace_get(scene, strip, origin);
const blender::float2 origin = SEQ_image_transform_origin_offset_pixelspace_get(scene, strip);
float vertex[2] = {origin[0], origin[1]};
/* Add control vertex, so rotation and scale can be calculated.
@@ -220,8 +219,7 @@ static void recalcData_sequencer_image(TransInfo *t)
TransDataSeq *tdseq = static_cast<TransDataSeq *>(td->extra);
Strip *strip = tdseq->strip;
StripTransform *transform = strip->data->transform;
float mirror[2];
SEQ_image_transform_mirror_factor_get(strip, mirror);
const blender::float2 mirror = SEQ_image_transform_mirror_factor_get(strip);
/* Calculate translation. */
float translation[2];

View File

@@ -957,7 +957,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
}
if (t->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first;
SEQ_image_preview_unit_to_px(t->scene, sseq->cursor, cursor_local_buf);
const float2 cursor_pixel = SEQ_image_preview_unit_to_px(t->scene, sseq->cursor);
copy_v2_v2(cursor_local_buf, cursor_pixel);
cursor = cursor_local_buf;
}
else if (t->spacetype == SPACE_CLIP) {

View File

@@ -255,8 +255,10 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
int selected_strips = strips.size();
if (selected_strips > 0) {
has_select = true;
SEQ_image_transform_bounding_box_from_collection(
scene, strips, selected_strips != 1, r_min, r_max);
const blender::Bounds<blender::float2> box =
SEQ_image_transform_bounding_box_from_collection(scene, strips, selected_strips != 1);
copy_v2_v2(r_min, box.min);
copy_v2_v2(r_max, box.max);
}
if (selected_strips > 1) {
/* Don't draw the cage as transforming multiple strips isn't currently very useful as it
@@ -270,7 +272,8 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
if (pivot_point == V3D_AROUND_CURSOR) {
SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_center);
const blender::float2 cursor_pixel = SEQ_image_preview_unit_to_px(scene, sseq->cursor);
copy_v2_v2(r_center, cursor_pixel);
}
else {
mid_v2_v2v2(r_center, r_min, r_max);
@@ -332,8 +335,7 @@ static float gizmo2d_calc_rotation(const bContext *C)
/* Only return the strip rotation if only one is selected. */
for (Strip *strip : strips) {
StripTransform *transform = strip->data->transform;
float mirror[2];
SEQ_image_transform_mirror_factor_get(strip, mirror);
const blender::float2 mirror = SEQ_image_transform_mirror_factor_get(strip);
return transform->rotation * mirror[0] * mirror[1];
}
}
@@ -355,8 +357,8 @@ static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
if (has_select) {
for (Strip *strip : strips) {
float origin[2];
SEQ_image_transform_origin_offset_pixelspace_get(scene, strip, origin);
const blender::float2 origin = SEQ_image_transform_origin_offset_pixelspace_get(scene,
strip);
add_v2_v2(r_pivot, origin);
}
mul_v2_fl(r_pivot, 1.0f / strips.size());
@@ -381,7 +383,8 @@ static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
if (pivot_point == V3D_AROUND_CURSOR) {
SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_pivot);
const blender::float2 cursor_pixel = SEQ_image_preview_unit_to_px(scene, sseq->cursor);
copy_v2_v2(r_pivot, cursor_pixel);
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);

View File

@@ -13,8 +13,8 @@
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_math_base.h"
#include "BLI_vector.hh"
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
@@ -143,8 +143,8 @@ static void points_build_sources_preview(const Scene *scene,
}
/* Add origins last */
float image_origin[2];
SEQ_image_transform_origin_offset_pixelspace_get(scene, strip, image_origin);
const blender::float2 image_origin = SEQ_image_transform_origin_offset_pixelspace_get(scene,
strip);
snap_data->source_snap_points.append(image_origin);
}
}
@@ -322,12 +322,12 @@ static void points_build_targets_preview(const Scene *scene,
const Array<float2> strip_image_quad = SEQ_image_transform_final_quad_get(scene, strip);
for (int j = 0; j < 4; j++) {
snap_data->target_snap_points.append(float2(strip_image_quad[j]));
snap_data->target_snap_points.append(strip_image_quad[j]);
}
float image_origin[2];
SEQ_image_transform_origin_offset_pixelspace_get(scene, strip, image_origin);
snap_data->target_snap_points.append(float2(image_origin));
const blender::float2 image_origin = SEQ_image_transform_origin_offset_pixelspace_get(scene,
strip);
snap_data->target_snap_points.append(image_origin);
}
}
}

View File

@@ -42,6 +42,7 @@
#include "../gpu/GPU_texture.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_utildefines.h"
#include "IMB_imbuf_types.hh"
@@ -625,7 +626,7 @@ void IMB_transform(const ImBuf *src,
ImBuf *dst,
eIMBTransformMode mode,
eIMBInterpolationFilterMode filter,
const float transform_matrix[4][4],
const blender::float3x3 &transform_matrix,
const rctf *src_crop);
GPUTexture *IMB_create_gpu_texture(const char *name,

View File

@@ -12,6 +12,7 @@
#include "BLI_math_color.h"
#include "BLI_math_interp.hh"
#include "BLI_math_matrix.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector.h"
#include "BLI_rect.h"
#include "BLI_task.hh"
@@ -47,7 +48,7 @@ struct TransformContext {
/* Cropping region in source image pixel space. */
rctf src_crop;
void init(const float4x4 &transform_matrix, const bool has_source_crop)
void init(const float3x3 &transform_matrix, const bool has_source_crop)
{
start_uv = transform_matrix.location().xy();
add_x = transform_matrix.x_axis().xy();
@@ -56,7 +57,7 @@ struct TransformContext {
}
private:
void init_destination_region(const float4x4 &transform_matrix, const bool has_source_crop)
void init_destination_region(const float3x3 &transform_matrix, const bool has_source_crop)
{
if (!has_source_crop) {
dst_region_x_range = IndexRange(dst->x);
@@ -68,14 +69,14 @@ struct TransformContext {
const int2 margin(2);
rcti rect;
BLI_rcti_init_minmax(&rect);
float4x4 inverse = math::invert(transform_matrix);
float3x3 inverse = math::invert(transform_matrix);
const int2 src_coords[4] = {int2(src_crop.xmin, src_crop.ymin),
int2(src_crop.xmax, src_crop.ymin),
int2(src_crop.xmax, src_crop.ymax),
int2(src_crop.xmin, src_crop.ymax)};
for (int i = 0; i < 4; i++) {
int2 src_co = src_coords[i];
float3 dst_co = math::transform_point(inverse, float3(src_co.x, src_co.y, 0.0f));
float2 dst_co = math::transform_point(inverse, float2(src_co));
src_corners[i] = float2(dst_co.x, dst_co.y);
BLI_rcti_do_minmax_v(&rect, int2(dst_co) + margin);
@@ -467,7 +468,7 @@ void IMB_transform(const ImBuf *src,
ImBuf *dst,
const eIMBTransformMode mode,
const eIMBInterpolationFilterMode filter,
const float transform_matrix[4][4],
const float3x3 &transform_matrix,
const rctf *src_crop)
{
BLI_assert_msg(mode != IMB_TRANSFORM_MODE_CROP_SRC || src_crop != nullptr,
@@ -483,7 +484,7 @@ void IMB_transform(const ImBuf *src,
if (crop) {
ctx.src_crop = *src_crop;
}
ctx.init(blender::float4x4(transform_matrix), crop);
ctx.init(transform_matrix, crop);
threading::parallel_for(ctx.dst_region_y_range, 8, [&](IndexRange y_range) {
if (filter == IMB_FILTER_NEAREST) {

View File

@@ -41,8 +41,8 @@ static ImBuf *transform_2x_smaller(eIMBInterpolationFilterMode filter)
{
ImBuf *src = create_6x2_test_image();
ImBuf *dst = IMB_allocImBuf(3, 1, 32, IB_rect);
float4x4 matrix = math::from_scale<float4x4>(float4(2.0f));
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix.ptr(), nullptr);
float3x3 matrix = math::from_scale<float3x3>(float3(2.0f));
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix, nullptr);
IMB_freeImBuf(src);
return dst;
}
@@ -51,8 +51,8 @@ static ImBuf *transform_fractional_larger(eIMBInterpolationFilterMode filter)
{
ImBuf *src = create_6x2_test_image();
ImBuf *dst = IMB_allocImBuf(9, 7, 32, IB_rect);
float4x4 matrix = math::from_scale<float4x4>(float4(6.0f / 9.0f, 2.0f / 7.0f, 1.0f, 1.0f));
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix.ptr(), nullptr);
float3x3 matrix = math::from_scale<float3x3>(float3(6.0f / 9.0f, 2.0f / 7.0f, 1.0f));
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix, nullptr);
IMB_freeImBuf(src);
return dst;
}
@@ -137,9 +137,9 @@ TEST(imbuf_transform, nearest_very_large_scale)
/* Create 3841x1 image, and scale the input image so that the three middle
* pixels cover almost all of it, except the rightmost pixel. */
ImBuf *res = IMB_allocImBuf(3841, 1, 32, IB_rect);
float4x4 matrix = math::from_loc_rot_scale<float4x4>(
float3(254, 0, 0), math::Quaternion::identity(), float3(3.0f / 3840.0f, 1, 1));
IMB_transform(src, res, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, matrix.ptr(), nullptr);
float3x3 matrix = math::from_loc_rot_scale<float3x3>(
float2(254, 0), 0.0f, float2(3.0f / 3840.0f, 1));
IMB_transform(src, res, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, matrix, nullptr);
/* Check result: leftmost red, middle green, two rightmost pixels blue and black.
* If the transform code internally does not have enough precision while stepping

View File

@@ -53,9 +53,9 @@ static void imb_scale_via_transform(ImBuf *&src,
eIMBInterpolationFilterMode filter)
{
ImBuf *dst = IMB_allocImBuf(width, height, src->planes, src->flags);
float4x4 matrix = math::from_scale<float4x4>(
float4(float(src->x) / dst->x, float(src->y) / dst->y, 1.0f, 1.0f));
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix.ptr(), nullptr);
float3x3 matrix = math::from_scale<float3x3>(
float3(float(src->x) / dst->x, float(src->y) / dst->y, 1.0f));
IMB_transform(src, dst, IMB_TRANSFORM_MODE_REGULAR, filter, matrix, nullptr);
IMB_freeImBuf(src);
src = dst;
}

View File

@@ -9,6 +9,7 @@
*/
#include "BLI_array.hh"
#include "BLI_bounds_types.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_span.hh"
@@ -75,18 +76,16 @@ bool SEQ_transform_is_locked(ListBase *channels, const Strip *strip);
/* Image transformation. */
void SEQ_image_transform_mirror_factor_get(const Strip *strip, float r_mirror[2]);
blender::float2 SEQ_image_transform_mirror_factor_get(const Strip *strip);
/**
* Get strip transform origin offset from image center
* NOTE: This function does not apply axis mirror.
*
* \param scene: Scene in which strips are located
* \param seq: Sequence to calculate image transform origin
* \param r_origin: return value
*/
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
const Strip *strip,
float r_origin[2]);
blender::float2 SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
const Strip *strip);
/**
* Get 4 corner points of strip image, optionally without rotation component applied.
* Corner vectors are in viewport space.
@@ -109,8 +108,8 @@ blender::Array<blender::float2> SEQ_image_transform_quad_get(const Scene *scene,
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]);
blender::float2 SEQ_image_preview_unit_to_px(const Scene *scene, blender::float2 co_src);
blender::float2 SEQ_image_preview_unit_from_px(const Scene *scene, blender::float2 co_src);
/**
* Get viewport axis aligned bounding box from a collection of sequences.
@@ -122,11 +121,8 @@ void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], f
* \param r_min: Minimum x and y values
* \param r_max: Maximum x and y values
*/
void SEQ_image_transform_bounding_box_from_collection(Scene *scene,
blender::Span<Strip *> strips,
bool apply_rotation,
float r_min[2],
float r_max[2]);
blender::Bounds<blender::float2> SEQ_image_transform_bounding_box_from_collection(
Scene *scene, blender::Span<Strip *> strips, bool apply_rotation);
/**
* Get strip image transformation matrix. Pivot point is set to correspond with viewport coordinate
@@ -135,4 +131,4 @@ 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
*/
blender::float4x4 SEQ_image_transform_matrix_get(const Scene *scene, const Strip *strip);
blender::float3x3 SEQ_image_transform_matrix_get(const Scene *scene, const Strip *strip);

View File

@@ -296,14 +296,14 @@ StripScreenQuad get_strip_screen_quad(const SeqRenderData *context, const Strip
Scene *scene = context->scene;
const int x = context->rectx;
const int y = context->recty;
float2 offset{x * 0.5f, y * 0.5f};
const float2 offset{x * 0.5f, y * 0.5f};
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{quad[0] * scale + offset,
quad[1] * scale + offset,
quad[2] * scale + offset,
quad[3] * scale + offset};
return StripScreenQuad{float2(quad[0] * scale + offset),
float2(quad[1] * scale + offset),
float2(quad[2] * scale + offset),
float2(quad[3] * scale + offset)};
}
/* Is quad `a` fully contained (i.e. covered by) quad `b`? For that to happen,
@@ -459,7 +459,7 @@ static bool seq_need_scale_to_render_size(const Strip *strip, bool is_proxy_imag
return false;
}
static float4x4 sequencer_image_crop_transform_matrix(const Strip *strip,
static float3x3 sequencer_image_crop_transform_matrix(const Strip *strip,
const ImBuf *in,
const ImBuf *out,
const float image_scale_factor,
@@ -472,16 +472,16 @@ static float4x4 sequencer_image_crop_transform_matrix(const Strip *strip,
* 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 translation(transform->xofs * preview_scale_factor,
transform->yofs * preview_scale_factor);
const float rotation = 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 float2 pivot(in->x * transform->origin[0], in->y * transform->origin[1]);
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);
const float3x3 matrix = math::from_loc_rot_scale<float3x3>(
translation + float2(image_center_offs), rotation, scale);
const float3x3 mat_pivot = math::from_origin_transform(matrix, pivot);
return math::invert(mat_pivot);
}
@@ -558,7 +558,7 @@ 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;
float4x4 matrix = sequencer_image_crop_transform_matrix(
float3x3 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.
@@ -590,8 +590,7 @@ static void sequencer_preprocess_transform_crop(
break;
}
IMB_transform(
in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, (float(*)[4])matrix.base_ptr(), &source_crop);
IMB_transform(in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, matrix, &source_crop);
if (is_strip_covering_screen(context, strip)) {
out->planes = in->planes;

View File

@@ -8,12 +8,13 @@
* \ingroup bke
*/
#include "BLI_bounds.hh"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "BLI_listbase.h"
#include "BLI_math_base.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
#include "SEQ_animation.hh"
@@ -565,68 +566,61 @@ bool SEQ_transform_is_locked(ListBase *channels, const Strip *strip)
(SEQ_channel_is_locked(channel) && ((strip->flag & SEQ_IGNORE_CHANNEL_LOCK) == 0));
}
void SEQ_image_transform_mirror_factor_get(const Strip *strip, float r_mirror[2])
float2 SEQ_image_transform_mirror_factor_get(const Strip *strip)
{
r_mirror[0] = 1.0f;
r_mirror[1] = 1.0f;
float2 mirror(1.0f, 1.0f);
if ((strip->flag & SEQ_FLIPX) != 0) {
r_mirror[0] = -1.0f;
mirror.x = -1.0f;
}
if ((strip->flag & SEQ_FLIPY) != 0) {
r_mirror[1] = -1.0f;
mirror.y = -1.0f;
}
return mirror;
}
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
const Strip *strip,
float r_origin[2])
static float2 strip_raw_image_size_get(const Scene *scene, const Strip *strip)
{
float image_size[2];
const StripElem *strip_elem = strip->data->stripdata;
if (strip_elem == nullptr) {
image_size[0] = scene->r.xsch;
image_size[1] = scene->r.ysch;
}
else {
image_size[0] = strip_elem->orig_width;
image_size[1] = strip_elem->orig_height;
if (ELEM(strip->type, STRIP_TYPE_MOVIE, STRIP_TYPE_IMAGE)) {
const StripElem *selem = strip->data->stripdata;
return {float(selem->orig_width), float(selem->orig_height)};
}
const StripTransform *transform = strip->data->transform;
r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs;
r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs;
const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
float mirror[2];
SEQ_image_transform_mirror_factor_get(strip, mirror);
mul_v2_v2(r_origin, mirror);
mul_v2_v2(r_origin, viewport_pixel_aspect);
return {float(scene->r.xsch), float(scene->r.ysch)};
}
static float4x4 seq_image_transform_matrix_get_ex(const Scene *scene,
float2 SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene, const Strip *strip)
{
const float2 image_size = strip_raw_image_size_get(scene, strip);
const StripTransform *transform = strip->data->transform;
const float2 origin(
(image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs,
(image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs);
const float2 viewport_pixel_aspect(scene->r.xasp / scene->r.yasp, 1.0f);
const float2 mirror = SEQ_image_transform_mirror_factor_get(strip);
return origin * mirror * viewport_pixel_aspect;
}
static float3x3 seq_image_transform_matrix_get_ex(const Scene *scene,
const Strip *strip,
bool apply_rotation = true)
{
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.x = strip->data->stripdata->orig_width;
image_size.y = strip->data->stripdata->orig_height;
}
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 image_size = strip_raw_image_size_get(scene, strip);
const float2 origin(image_size.x * transform->origin[0], image_size[1] * transform->origin[1]);
const float2 translation(transform->xofs, transform->yofs);
const float rotation = apply_rotation ? transform->rotation : 0.0f;
const float2 scale(transform->scale_x, transform->scale_y);
const float3 pivot = origin - (image_size / 2);
const float2 pivot = origin - (image_size / 2);
const float4x4 matrix = math::from_loc_rot_scale<float4x4>(translation, rotation, scale);
const float3x3 matrix = math::from_loc_rot_scale<float3x3>(translation, rotation, scale);
return math::from_origin_transform(matrix, pivot);
}
float4x4 SEQ_image_transform_matrix_get(const Scene *scene, const Strip *strip)
float3x3 SEQ_image_transform_matrix_get(const Scene *scene, const Strip *strip)
{
return seq_image_transform_matrix_get_ex(scene, strip);
}
@@ -635,34 +629,26 @@ 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.x = strip->data->stripdata->orig_width;
image_size.y = strip->data->stripdata->orig_height;
}
const float2 image_size = strip_raw_image_size_get(scene, strip);
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},
float2 quad[4]{
{(image_size[0] / 2) - crop->right, (image_size[1] / 2) - crop->top},
{(image_size[0] / 2) - crop->right, (-image_size[1] / 2) + crop->bottom},
{(-image_size[0] / 2) + crop->left, (-image_size[1] / 2) + crop->bottom},
{(-image_size[0] / 2) + crop->left, (image_size[1] / 2) - crop->top},
};
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 float3x3 matrix = seq_image_transform_matrix_get_ex(scene, strip, apply_rotation);
const float2 viewport_pixel_aspect(scene->r.xasp / scene->r.yasp, 1.0f);
const float2 mirror = SEQ_image_transform_mirror_factor_get(strip);
Array<float2> quad_transformed;
quad_transformed.reinitialize(4);
for (int i = 0; i < 4; i++) {
float3 point = math::transform_point(matrix, quad[i]);
point *= mirror;
point *= viewport_pixel_aspect;
copy_v2_v2(quad_transformed[i], point);
const float2 point = math::transform_point(matrix, quad[i]);
quad_transformed[i] = point * mirror * viewport_pixel_aspect;
}
return quad_transformed;
}
@@ -679,29 +665,32 @@ Array<float2> SEQ_image_transform_final_quad_get(const Scene *scene, const Strip
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])
float2 SEQ_image_preview_unit_to_px(const Scene *scene, const float2 co_src)
{
co_dst[0] = co_src[0] * scene->r.xsch;
co_dst[1] = co_src[1] * scene->r.ysch;
return {co_src.x * scene->r.xsch, co_src.y * scene->r.ysch};
}
void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], float co_dst[2])
float2 SEQ_image_preview_unit_from_px(const Scene *scene, const float2 co_src)
{
co_dst[0] = co_src[0] / scene->r.xsch;
co_dst[1] = co_src[1] / scene->r.ysch;
return {co_src.x / scene->r.xsch, co_src.y / scene->r.ysch};
}
void SEQ_image_transform_bounding_box_from_collection(Scene *scene,
blender::Span<Strip *> strips,
bool apply_rotation,
float r_min[2],
float r_max[2])
static Bounds<float2> negative_bounds()
{
INIT_MINMAX2(r_min, r_max);
return {float2(std::numeric_limits<float>::max()), float2(std::numeric_limits<float>::lowest())};
}
Bounds<float2> SEQ_image_transform_bounding_box_from_collection(Scene *scene,
blender::Span<Strip *> strips,
bool apply_rotation)
{
Bounds<float2> box = negative_bounds();
for (Strip *strip : strips) {
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]);
}
const Array<float2> quad = SEQ_image_transform_quad_get(scene, strip, apply_rotation);
const Bounds<float2> strip_box = *blender::bounds::min_max(quad.as_span());
box = blender::bounds::merge(box, strip_box);
}
return box;
}