Compositor: Support backdrop offset for the Viewer node
This is only part of the experimental "Full Frame" mode (disabled by default). See T88150. Currently the viewer node uses buffer paddings to display image offset in the backdrop as a temporal solution implemented for {D12466}. This solution is inefficient memory and performance-wise. Another issue is that the paddings are part the image when saved. This patch instead sets the offset in the Viewer node image as variables and makes the backdrop take it into account when drawing the image or any related gizmo. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D12750
This commit is contained in:
parent
22de21bef1
commit
33409f9f1c
Notes:
blender-bot
2023-02-14 03:13:26 +01:00
Referenced by commit fe9e7036b0
, Fix UV's not aligning with image.
Referenced by issue #96554, No more panning in Image Editor
Referenced by issue #96543, Panning Broken in the Image Editor (Image Editor: Incorrect Image Offsets)
|
@ -10,9 +10,9 @@
|
|||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
namespace blender::compositor {
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
static int MAX_VIEWER_TRANSLATION_PADDING = 12000;
|
||||
namespace blender::compositor {
|
||||
|
||||
ViewerOperation::ViewerOperation()
|
||||
{
|
||||
|
@ -137,23 +137,12 @@ void ViewerOperation::init_image()
|
|||
return;
|
||||
}
|
||||
|
||||
int padding_x = abs(canvas_.xmin) * 2;
|
||||
int padding_y = abs(canvas_.ymin) * 2;
|
||||
if (padding_x > MAX_VIEWER_TRANSLATION_PADDING) {
|
||||
padding_x = MAX_VIEWER_TRANSLATION_PADDING;
|
||||
}
|
||||
if (padding_y > MAX_VIEWER_TRANSLATION_PADDING) {
|
||||
padding_y = MAX_VIEWER_TRANSLATION_PADDING;
|
||||
}
|
||||
|
||||
display_width_ = get_width() + padding_x;
|
||||
display_height_ = get_height() + padding_y;
|
||||
if (ibuf->x != display_width_ || ibuf->y != display_height_) {
|
||||
if (ibuf->x != get_width() || ibuf->y != get_height()) {
|
||||
imb_freerectImBuf(ibuf);
|
||||
imb_freerectfloatImBuf(ibuf);
|
||||
IMB_freezbuffloatImBuf(ibuf);
|
||||
ibuf->x = display_width_;
|
||||
ibuf->y = display_height_;
|
||||
ibuf->x = get_width();
|
||||
ibuf->y = get_height();
|
||||
/* zero size can happen if no image buffers exist to define a sensible resolution */
|
||||
if (ibuf->x > 0 && ibuf->y > 0) {
|
||||
imb_addrectfloatImBuf(ibuf);
|
||||
|
@ -187,11 +176,13 @@ void ViewerOperation::update_image(const rcti *rect)
|
|||
return;
|
||||
}
|
||||
|
||||
image_->display_offset_x = canvas_.xmin;
|
||||
image_->display_offset_y = canvas_.ymin;
|
||||
float *buffer = output_buffer_;
|
||||
IMB_partial_display_buffer_update(ibuf_,
|
||||
buffer,
|
||||
nullptr,
|
||||
display_width_,
|
||||
get_width(),
|
||||
0,
|
||||
0,
|
||||
view_settings_,
|
||||
|
@ -224,32 +215,23 @@ void ViewerOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(output),
|
|||
return;
|
||||
}
|
||||
|
||||
const int offset_x = area.xmin + (canvas_.xmin > 0 ? canvas_.xmin * 2 : 0);
|
||||
const int offset_y = area.ymin + (canvas_.ymin > 0 ? canvas_.ymin * 2 : 0);
|
||||
MemoryBuffer output_buffer(
|
||||
output_buffer_, COM_DATA_TYPE_COLOR_CHANNELS, display_width_, display_height_);
|
||||
output_buffer_, COM_DATA_TYPE_COLOR_CHANNELS, get_width(), get_height());
|
||||
const MemoryBuffer *input_image = inputs[0];
|
||||
output_buffer.copy_from(input_image, area, offset_x, offset_y);
|
||||
output_buffer.copy_from(input_image, area);
|
||||
if (use_alpha_input_) {
|
||||
const MemoryBuffer *input_alpha = inputs[1];
|
||||
output_buffer.copy_from(
|
||||
input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, offset_x, offset_y, 3);
|
||||
output_buffer.copy_from(input_alpha, area, 0, COM_DATA_TYPE_VALUE_CHANNELS, 3);
|
||||
}
|
||||
|
||||
if (depth_buffer_) {
|
||||
MemoryBuffer depth_buffer(
|
||||
depth_buffer_, COM_DATA_TYPE_VALUE_CHANNELS, display_width_, display_height_);
|
||||
depth_buffer_, COM_DATA_TYPE_VALUE_CHANNELS, get_width(), get_height());
|
||||
const MemoryBuffer *input_depth = inputs[2];
|
||||
depth_buffer.copy_from(input_depth, area, offset_x, offset_y);
|
||||
depth_buffer.copy_from(input_depth, area);
|
||||
}
|
||||
|
||||
rcti display_area;
|
||||
BLI_rcti_init(&display_area,
|
||||
offset_x,
|
||||
offset_x + BLI_rcti_size_x(&area),
|
||||
offset_y,
|
||||
offset_y + BLI_rcti_size_y(&area));
|
||||
update_image(&display_area);
|
||||
update_image(&area);
|
||||
}
|
||||
|
||||
void ViewerOperation::clear_display_buffer()
|
||||
|
|
|
@ -35,9 +35,6 @@ class ViewerOperation : public MultiThreadedOperation {
|
|||
SocketReader *alpha_input_;
|
||||
SocketReader *depth_input_;
|
||||
|
||||
int display_width_;
|
||||
int display_height_;
|
||||
|
||||
public:
|
||||
ViewerOperation();
|
||||
void init_execution() override;
|
||||
|
|
|
@ -129,7 +129,6 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
|
|||
{
|
||||
GPUShader *shader = IMAGE_shader_depth_get();
|
||||
DRWShadingGroup *shgrp = DRW_shgroup_create(shader, instance_data.passes.depth_pass);
|
||||
|
||||
float image_mat[4][4];
|
||||
unit_m4(image_mat);
|
||||
|
||||
|
|
|
@ -99,8 +99,11 @@ class ImageEngine {
|
|||
/* Setup the matrix to go from screen UV coordinates to UV texture space coordinates. */
|
||||
float image_resolution[2] = {image_buffer ? image_buffer->x : 1024.0f,
|
||||
image_buffer ? image_buffer->y : 1024.0f};
|
||||
space->init_ss_to_texture_matrix(
|
||||
draw_ctx->region, image_resolution, instance_data->ss_to_texture);
|
||||
float image_display_offset[2] = {(float)instance_data->image->display_offset_x,
|
||||
(float)instance_data->image->display_offset_y};
|
||||
space->init_ss_to_texture_matrix(draw_ctx->region,
|
||||
image_display_offset,
|
||||
image_resolution, instance_data->ss_to_texture);
|
||||
|
||||
const Scene *scene = DRW_context_state_get()->scene;
|
||||
instance_data->sh_params.update(space.get(), scene, instance_data->image, image_buffer);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
/**
|
||||
* \brief max allowed textures to use by the ScreenSpaceDrawingMode.
|
||||
*
|
||||
* 4 textures are used to reduce uploading screen space textures when translating the image.
|
||||
* 1 texture is used to reduce uploading screen space textures when translating the image.
|
||||
*/
|
||||
constexpr int SCREEN_SPACE_DRAWING_MODE_TEXTURE_LEN = 1;
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ class AbstractSpaceAccessor {
|
|||
* (0..1) to texture space UV coordinates.
|
||||
*/
|
||||
virtual void init_ss_to_texture_matrix(const ARegion *region,
|
||||
const float image_display_offset[2],
|
||||
const float image_resolution[2],
|
||||
float r_uv_to_texture[4][4]) const = 0;
|
||||
|
||||
|
|
|
@ -148,20 +148,29 @@ class SpaceImageAccessor : public AbstractSpaceAccessor {
|
|||
}
|
||||
|
||||
void init_ss_to_texture_matrix(const ARegion *region,
|
||||
const float UNUSED(image_resolution[2]),
|
||||
const float image_display_offset[2],
|
||||
const float image_resolution[2],
|
||||
float r_uv_to_texture[4][4]) const override
|
||||
{
|
||||
unit_m4(r_uv_to_texture);
|
||||
float scale_x = 1.0 / BLI_rctf_size_x(®ion->v2d.cur);
|
||||
float scale_y = 1.0 / BLI_rctf_size_y(®ion->v2d.cur);
|
||||
float translate_x = scale_x * -region->v2d.cur.xmin;
|
||||
float translate_y = scale_y * -region->v2d.cur.ymin;
|
||||
float zoom_x = image_resolution[0] * sima->zoom;
|
||||
float zoom_y = image_resolution[1] * sima ->zoom;
|
||||
float image_offset_x = (region->winx - zoom_x) / 2 + sima->xof + image_display_offset[0];
|
||||
float image_offset_y = (region->winy - zoom_y) / 2 + sima->yof + image_display_offset[1];
|
||||
|
||||
r_uv_to_texture[0][0] = scale_x;
|
||||
r_uv_to_texture[1][1] = scale_y;
|
||||
r_uv_to_texture[3][0] = translate_x;
|
||||
r_uv_to_texture[3][1] = translate_y;
|
||||
}
|
||||
unit_m4(r_uv_to_texture);
|
||||
float scale_x = 1.0 / BLI_rctf_size_x(®ion->v2d.cur);
|
||||
float scale_y = 1.0 / BLI_rctf_size_y(®ion->v2d.cur);
|
||||
float offset_x = 1.0 / image_resolution[0] * image_offset_x;
|
||||
float offset_y = 1.0 / image_resolution[1] * image_offset_y;
|
||||
|
||||
float translate_x = scale_x * (-region->v2d.cur.xmin + offset_x);
|
||||
float translate_y = scale_y * (-region->v2d.cur.ymin + offset_y);
|
||||
|
||||
r_uv_to_texture[0][0] = scale_x;
|
||||
r_uv_to_texture[1][1] = scale_y;
|
||||
r_uv_to_texture[3][0] = translate_x;
|
||||
r_uv_to_texture[3][1] = translate_y;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::image_engine
|
||||
|
|
|
@ -99,6 +99,7 @@ class SpaceNodeAccessor : public AbstractSpaceAccessor {
|
|||
* screen.
|
||||
*/
|
||||
void init_ss_to_texture_matrix(const ARegion *region,
|
||||
const float image_display_offset[2],
|
||||
const float image_resolution[2],
|
||||
float r_uv_to_texture[4][4]) const override
|
||||
{
|
||||
|
@ -107,10 +108,10 @@ class SpaceNodeAccessor : public AbstractSpaceAccessor {
|
|||
mul_v2_v2fl(display_resolution, image_resolution, snode->zoom);
|
||||
const float scale_x = display_resolution[0] / region->winx;
|
||||
const float scale_y = display_resolution[1] / region->winy;
|
||||
const float translate_x = ((region->winx - display_resolution[0]) * 0.5f + snode->xof) /
|
||||
region->winx;
|
||||
const float translate_y = ((region->winy - display_resolution[1]) * 0.5f + snode->yof) /
|
||||
region->winy;
|
||||
const float translate_x = ((region->winx - display_resolution[0]) * 0.5f + snode->xof + image_display_offset[0]) /
|
||||
region->winx ;
|
||||
const float translate_y = ((region->winy - display_resolution[1]) * 0.5f + snode->yof + image_display_offset[1]) /
|
||||
region->winy;
|
||||
|
||||
r_uv_to_texture[0][0] = scale_x;
|
||||
r_uv_to_texture[1][1] = scale_y;
|
||||
|
|
|
@ -1499,8 +1499,10 @@ void draw_nodespace_back_pix(const bContext &C,
|
|||
if (ibuf) {
|
||||
/* somehow the offset has to be calculated inverse */
|
||||
wmOrtho2_region_pixelspace(®ion);
|
||||
const float x = (region.winx - snode.zoom * ibuf->x) / 2 + snode.xof;
|
||||
const float y = (region.winy - snode.zoom * ibuf->y) / 2 + snode.yof;
|
||||
const float offset_x = snode.xof + ima->display_offset_x;
|
||||
const float offset_y = snode.yof + ima->display_offset_y;
|
||||
const float x = (region.winx - snode.zoom * ibuf->x) / 2 + offset_x;
|
||||
const float y = (region.winy - snode.zoom * ibuf->y) / 2 + offset_y;
|
||||
|
||||
/** \note draw selected info on backdrop */
|
||||
if (snode.edittree) {
|
||||
|
|
|
@ -38,25 +38,39 @@ namespace blender::ed::space_node {
|
|||
|
||||
static void node_gizmo_calc_matrix_space(const SpaceNode *snode,
|
||||
const ARegion *region,
|
||||
const float image_offset[2],
|
||||
float matrix_space[4][4])
|
||||
{
|
||||
unit_m4(matrix_space);
|
||||
mul_v3_fl(matrix_space[0], snode->zoom);
|
||||
mul_v3_fl(matrix_space[1], snode->zoom);
|
||||
matrix_space[3][0] = (region->winx / 2) + snode->xof;
|
||||
matrix_space[3][1] = (region->winy / 2) + snode->yof;
|
||||
const float offset_x = snode->xof + image_offset[0];
|
||||
const float offset_y = snode->yof + image_offset[1];
|
||||
matrix_space[3][0] = (region->winx / 2) + offset_x;
|
||||
matrix_space[3][1] = (region->winy / 2) + offset_y;
|
||||
}
|
||||
|
||||
static void node_gizmo_calc_matrix_space_with_image_dims(const SpaceNode *snode,
|
||||
const ARegion *region,
|
||||
const float image_offset[2],
|
||||
const float image_dims[2],
|
||||
float matrix_space[4][4])
|
||||
{
|
||||
unit_m4(matrix_space);
|
||||
mul_v3_fl(matrix_space[0], snode->zoom * image_dims[0]);
|
||||
mul_v3_fl(matrix_space[1], snode->zoom * image_dims[1]);
|
||||
matrix_space[3][0] = ((region->winx / 2) + snode->xof) - ((image_dims[0] / 2.0f) * snode->zoom);
|
||||
matrix_space[3][1] = ((region->winy / 2) + snode->yof) - ((image_dims[1] / 2.0f) * snode->zoom);
|
||||
const float offset_x = snode->xof + image_offset[0];
|
||||
const float offset_y = snode->yof + image_offset[1];
|
||||
matrix_space[3][0] = ((region->winx / 2) + offset_x) - ((image_dims[0] / 2.0f) * snode->zoom);
|
||||
matrix_space[3][1] = ((region->winy / 2) + offset_y) - ((image_dims[1] / 2.0f) * snode->zoom);
|
||||
}
|
||||
|
||||
static void get_viewer_image_offset(const bContext *C, float r_offset[2])
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
const Image *image = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
|
||||
r_offset[0] = image->display_offset_x;
|
||||
r_offset[1] = image->display_offset_y;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -127,11 +141,13 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup *
|
|||
Main *bmain = CTX_data_main(C);
|
||||
wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo;
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
/* center is always at the origin */
|
||||
const float origin[3] = {float(region->winx / 2), float(region->winy / 2), 0.0f};
|
||||
|
||||
Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
|
||||
/* Center is always at the origin. */
|
||||
const float origin[3] ={ (region->winx / 2) + (float)ima->display_offset_x,
|
||||
(region->winy / 2) + (float)ima->display_offset_y};
|
||||
|
||||
void *lock;
|
||||
Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
|
||||
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
|
||||
|
||||
if (ibuf) {
|
||||
|
@ -340,7 +356,9 @@ static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *
|
|||
|
||||
SpaceNode *snode = CTX_wm_space_node(C);
|
||||
|
||||
node_gizmo_calc_matrix_space(snode, region, gz->matrix_space);
|
||||
float image_offset[2];
|
||||
get_viewer_image_offset(C, image_offset);
|
||||
node_gizmo_calc_matrix_space(snode, region, image_offset, gz->matrix_space);
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
|
@ -453,8 +471,10 @@ static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup
|
|||
|
||||
SpaceNode *snode = CTX_wm_space_node(C);
|
||||
|
||||
float image_offset[2];
|
||||
get_viewer_image_offset(C, image_offset);
|
||||
node_gizmo_calc_matrix_space_with_image_dims(
|
||||
snode, region, sbeam_group->state.dims, gz->matrix_space);
|
||||
snode, region, image_offset, sbeam_group->state.dims, gz->matrix_space);
|
||||
}
|
||||
|
||||
static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
||||
|
@ -560,9 +580,12 @@ static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoG
|
|||
|
||||
SpaceNode *snode = CTX_wm_space_node(C);
|
||||
|
||||
float image_offset[2];
|
||||
get_viewer_image_offset(C, image_offset);
|
||||
|
||||
float matrix_space[4][4];
|
||||
node_gizmo_calc_matrix_space_with_image_dims(
|
||||
snode, region, cpin_group->state.dims, matrix_space);
|
||||
snode, region, image_offset, cpin_group->state.dims, matrix_space);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
wmGizmo *gz = cpin_group->gizmos[i];
|
||||
|
|
|
@ -352,9 +352,14 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
|
|||
case ND_FRAME:
|
||||
ED_area_tag_refresh(area);
|
||||
break;
|
||||
case ND_COMPO_RESULT:
|
||||
case ND_COMPO_RESULT: {
|
||||
ED_area_tag_redraw(area);
|
||||
/* Backdrop image offset is calculated during compositing so gizmos need to be updated
|
||||
* afterwards. */
|
||||
const ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
||||
WM_gizmomap_tag_refresh(region->gizmo_map);
|
||||
break;
|
||||
}
|
||||
case ND_TRANSFORM_DONE:
|
||||
if (ED_node_is_compositor(snode)) {
|
||||
if (snode->flag & SNODE_AUTO_RENDER) {
|
||||
|
|
|
@ -199,6 +199,9 @@ typedef struct Image {
|
|||
char eye;
|
||||
char views_format;
|
||||
|
||||
/** Displayed offset in backdrop for viewer nodes in pixel space. */
|
||||
int display_offset_x, display_offset_y;
|
||||
|
||||
/* ImageTile list for UDIMs. */
|
||||
int active_tile_index;
|
||||
ListBase tiles;
|
||||
|
|
Loading…
Reference in New Issue