Nodes: Move preview images to an overlay

Move the node previews to the overlay region, atop each node.
It allows nodes to keep the same size when the preview is toggled,
which is more convenient for large nodes and large nodetrees.

The preview has to be drawn from `node_draw_extra_info_panel`
because there could be overlapping between info text and the preview.
When the node is out of the view, it also has to make sure that the
preview is also out of the view before exiting the draw function.

Pull Request: https://projects.blender.org/blender/blender/pulls/108001
This commit is contained in:
Colin Marmond
2023-07-12 16:14:12 +02:00
committed by Brecht Van Lommel
parent a5a72019a9
commit 1ebdd2d9cf
10 changed files with 110 additions and 70 deletions

View File

@@ -817,6 +817,10 @@ class NODE_PT_overlay(Panel):
col.prop(overlay, "show_context_path", text="Context Path")
col.prop(snode, "show_annotation", text="Annotations")
if snode.supports_preview:
col.separator()
col.prop(overlay, "show_previews", text="Previews")
if snode.tree_type == 'GeometryNodeTree':
col.separator()
col.prop(overlay, "show_timing", text="Timings")

View File

@@ -27,7 +27,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 9
#define BLENDER_FILE_SUBVERSION 10
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@@ -259,8 +259,6 @@ class bNodeRuntime : NonCopyable, NonMovable {
short preview_xsize, preview_ysize = 0;
/** Entire bound-box (world-space). */
rctf totr{};
/** Optional preview area. */
rctf prvr{};
/** Used at runtime when going through the tree. Initialize before use. */
short tmp_flag = 0;

View File

@@ -324,6 +324,19 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 400, 10)) {
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
if (space->spacetype == SPACE_NODE) {
SpaceNode *snode = reinterpret_cast<SpaceNode *>(space);
snode->overlay.flag |= SN_OVERLAY_SHOW_PREVIEWS;
}
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@@ -93,6 +93,7 @@ bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
bool ED_node_is_geometry(struct SpaceNode *snode);
bool ED_node_supports_preview(struct SpaceNode *snode);
/**
* Assumes nothing being done in ntree yet, sets the default in/out node.

View File

@@ -434,44 +434,6 @@ static void node_update_basis(const bContext &C,
dy -= NODE_DY / 4;
}
node.runtime->prvr.xmin = loc.x + NODE_DYS;
node.runtime->prvr.xmax = loc.x + NODE_WIDTH(node) - NODE_DYS;
/* preview rect? */
if (node.flag & NODE_PREVIEW) {
float aspect = 1.0f;
if (node.runtime->preview_xsize && node.runtime->preview_ysize) {
aspect = float(node.runtime->preview_ysize) / float(node.runtime->preview_xsize);
}
dy -= NODE_DYS / 2;
node.runtime->prvr.ymax = dy;
if (aspect <= 1.0f) {
node.runtime->prvr.ymin = dy - aspect * (NODE_WIDTH(node) - NODE_DY);
}
else {
/* Width correction of image. XXX huh? (ton) */
float dx = (NODE_WIDTH(node) - NODE_DYS) - (NODE_WIDTH(node) - NODE_DYS) / aspect;
node.runtime->prvr.ymin = dy - (NODE_WIDTH(node) - NODE_DY);
node.runtime->prvr.xmin += 0.5f * dx;
node.runtime->prvr.xmax -= 0.5f * dx;
}
dy = node.runtime->prvr.ymin - NODE_DYS / 2;
/* Make sure that maximums are bigger or equal to minimums. */
if (node.runtime->prvr.xmax < node.runtime->prvr.xmin) {
std::swap(node.runtime->prvr.xmax, node.runtime->prvr.xmin);
}
if (node.runtime->prvr.ymax < node.runtime->prvr.ymin) {
std::swap(node.runtime->prvr.ymax, node.runtime->prvr.ymin);
}
}
/* Buttons rect? */
if (node_options) {
dy -= NODE_DYS / 2;
@@ -1408,11 +1370,14 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
GPU_blend(GPU_BLEND_NONE);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_BACK, -15, +100);
imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
immUnbindProgram();
float black[4] = {0.f, 0.f, 0.f, 1.f};
UI_draw_roundbox_corner_set(UI_CNR_ALL);
const float outline_width = 1.0f;
draw_rect.xmin -= outline_width;
draw_rect.xmax += outline_width;
draw_rect.ymin -= outline_width;
draw_rect.ymax += outline_width;
UI_draw_roundbox_4fv(&draw_rect, false, BASIS_RAD / 2, black);
}
/* Common handle function for operator buttons that need to select the node first. */
@@ -2121,10 +2086,11 @@ static void node_draw_extra_info_row(const bNode &node,
static void node_draw_extra_info_panel(TreeDrawContext &tree_draw_ctx,
const SpaceNode &snode,
const bNode &node,
bNodePreview *preview,
uiBlock &block)
{
Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(tree_draw_ctx, snode, node);
if (extra_info_rows.size() == 0) {
if (extra_info_rows.size() == 0 && !preview) {
return;
}
@@ -2141,10 +2107,38 @@ static void node_draw_extra_info_panel(TreeDrawContext &tree_draw_ctx,
extra_info_rect.ymax = rct.ymin + 2.0f * UI_SCALE_FAC;
}
else {
float preview_height = 0;
rctf preview_rect;
extra_info_rect.xmin = rct.xmin + 3.0f * UI_SCALE_FAC;
extra_info_rect.xmax = rct.xmin + width;
extra_info_rect.xmax = extra_info_rect.xmin + width;
extra_info_rect.ymin = rct.ymax;
extra_info_rect.ymax = rct.ymax + extra_info_rows.size() * (20.0f * UI_SCALE_FAC);
if (preview) {
if (preview->xsize > preview->ysize) {
const float preview_padding = 3.0f * UI_SCALE_FAC;
preview_height = (width - 2.0 * preview_padding) * float(preview->ysize) /
float(preview->xsize) +
2.0 * preview_padding;
preview_rect.ymin = extra_info_rect.ymin + preview_padding;
preview_rect.ymax = extra_info_rect.ymin + preview_height - preview_padding;
preview_rect.xmin = extra_info_rect.xmin + preview_padding;
preview_rect.xmax = extra_info_rect.xmax - preview_padding;
extra_info_rect.ymax += preview_height;
}
else {
const float preview_padding = 3.0f * UI_SCALE_FAC;
preview_height = width;
const float preview_width = (width - 2.0 * preview_padding) * float(preview->xsize) /
float(preview->ysize) +
2.0 * preview_padding;
preview_rect.ymin = extra_info_rect.ymin + preview_padding;
preview_rect.ymax = extra_info_rect.ymin + preview_height - preview_padding;
preview_rect.xmin = extra_info_rect.xmin + preview_padding + (width - preview_width) / 2;
preview_rect.xmax = extra_info_rect.xmax - preview_padding - (width - preview_width) / 2;
extra_info_rect.ymax += preview_height;
}
}
if (node.flag & NODE_MUTED) {
UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color);
@@ -2160,17 +2154,23 @@ static void node_draw_extra_info_panel(TreeDrawContext &tree_draw_ctx,
/* Draw outline. */
const float outline_width = 1.0f;
extra_info_rect.xmin = rct.xmin + 3.0f * UI_SCALE_FAC - outline_width;
extra_info_rect.xmax = rct.xmin + width + outline_width;
extra_info_rect.ymin = rct.ymax - outline_width;
extra_info_rect.ymax = rct.ymax + outline_width +
extra_info_rows.size() * (20.0f * UI_SCALE_FAC);
extra_info_rect.xmin -= outline_width;
extra_info_rect.xmax += outline_width;
extra_info_rect.ymin -= outline_width;
extra_info_rect.ymax += outline_width;
UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color);
UI_draw_roundbox_corner_set(
UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT &
((rct.xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL));
UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color);
if (preview) {
node_draw_preview(preview, &preview_rect);
}
/* Resize the rect to draw the textual infos on top of the preview. */
extra_info_rect.ymin += preview_height;
}
for (int row : extra_info_rows.index_range()) {
@@ -2188,9 +2188,15 @@ static void node_draw_basis(const bContext &C,
bNodeInstanceKey key)
{
const float iconbutw = NODE_HEADER_ICON_SIZE;
bNodeInstanceHash *previews =
static_cast<bNodeInstanceHash *>(CTX_data_pointer_get(&C, "node_previews").data);
/* Skip if out of view. */
if (BLI_rctf_isect(&node.runtime->totr, &v2d.cur, nullptr) == false) {
rctf rect_with_preview = node.runtime->totr;
if (node.flag & NODE_PREVIEW && previews && snode.overlay.flag & SN_OVERLAY_SHOW_PREVIEWS) {
rect_with_preview.ymax += NODE_WIDTH(node);
}
if (BLI_rctf_isect(&rect_with_preview, &v2d.cur, nullptr) == false) {
UI_block_end(&C, &block);
return;
}
@@ -2211,7 +2217,15 @@ static void node_draw_basis(const bContext &C,
GPU_line_width(1.0f);
node_draw_extra_info_panel(tree_draw_ctx, snode, node, block);
bNodePreview *preview = nullptr;
if (node.flag & NODE_PREVIEW && previews && snode.overlay.flag & SN_OVERLAY_SHOW_PREVIEWS) {
preview = static_cast<bNodePreview *>(BKE_node_instance_hash_lookup(previews, key));
if (!preview || !(preview->xsize && preview->ysize)) {
preview = nullptr;
}
}
node_draw_extra_info_panel(tree_draw_ctx, snode, node, preview, block);
/* Header. */
{
@@ -2501,18 +2515,6 @@ static void node_draw_basis(const bContext &C,
node_draw_sockets(v2d, C, ntree, node, block, true, false);
}
/* Preview. */
bNodeInstanceHash *previews =
(bNodeInstanceHash *)CTX_data_pointer_get(&C, "node_previews").data;
if (node.flag & NODE_PREVIEW && previews) {
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (preview && (preview->xsize && preview->ysize)) {
if (preview->rect && !BLI_rctf_is_empty(&node.runtime->prvr)) {
node_draw_preview(preview, &node.runtime->prvr);
}
}
}
UI_block_end(&C, &block);
UI_block_draw(&C, &block);
}
@@ -2534,7 +2536,7 @@ static void node_draw_hidden(const bContext &C,
const int color_id = node_get_colorid(tree_draw_ctx, node);
node_draw_extra_info_panel(tree_draw_ctx, snode, node, block);
node_draw_extra_info_panel(tree_draw_ctx, snode, node, nullptr, block);
/* Shadow. */
node_draw_shadow(snode, node, hiddenrad, 1.0f);
@@ -3020,7 +3022,7 @@ static void frame_node_draw(const bContext &C,
/* Label and text. */
frame_node_draw_label(tree_draw_ctx, ntree, node, snode);
node_draw_extra_info_panel(tree_draw_ctx, snode, node, block);
node_draw_extra_info_panel(tree_draw_ctx, snode, node, nullptr, block);
UI_block_end(&C, &block);
UI_block_draw(&C, &block);

View File

@@ -503,6 +503,11 @@ bool ED_node_is_geometry(SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
}
bool ED_node_supports_preview(SpaceNode *snode)
{
return ED_node_is_compositor(snode);
}
void ED_node_shader_default(const bContext *C, ID *id)
{
Main *bmain = CTX_data_main(C);

View File

@@ -242,7 +242,7 @@ static SpaceLink *node_create(const ScrArea * /*area*/, const Scene * /*scene*/)
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
snode->overlay.flag = (SN_OVERLAY_SHOW_OVERLAYS | SN_OVERLAY_SHOW_WIRE_COLORS |
SN_OVERLAY_SHOW_PATH);
SN_OVERLAY_SHOW_PATH | SN_OVERLAY_SHOW_PREVIEWS);
/* backdrop */
snode->zoom = 1.0f;

View File

@@ -1566,6 +1566,7 @@ typedef enum eSpaceNodeOverlay_Flag {
SN_OVERLAY_SHOW_TIMINGS = (1 << 3),
SN_OVERLAY_SHOW_PATH = (1 << 4),
SN_OVERLAY_SHOW_NAMED_ATTRIBUTES = (1 << 5),
SN_OVERLAY_SHOW_PREVIEWS = (1 << 6),
} eSpaceNodeOverlay_Flag;
typedef struct SpaceNode {

View File

@@ -2502,6 +2502,11 @@ static PointerRNA rna_SpaceNode_overlay_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_SpaceNodeOverlay, ptr->data);
}
static bool rna_SpaceNode_supports_previews(PointerRNA *ptr)
{
return ED_node_supports_preview(static_cast<SpaceNode *>(ptr->data));
}
static char *rna_SpaceNodeOverlay_path(const PointerRNA * /*ptr*/)
{
return BLI_strdup("overlay");
@@ -7404,6 +7409,13 @@ static void rna_def_space_node_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Show Named Attributes", "Show when nodes are using named attributes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, nullptr);
prop = RNA_def_property(srna, "show_previews", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "overlay.flag", SN_OVERLAY_SHOW_PREVIEWS);
RNA_def_property_boolean_default(prop, false);
RNA_def_property_ui_text(
prop, "Show Node Previews", "Display each node's preview if node is toggled");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, nullptr);
}
static void rna_def_space_node(BlenderRNA *brna)
@@ -7623,6 +7635,10 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Overlay Settings", "Settings for display of overlays in the Node Editor");
prop = RNA_def_property(srna, "supports_preview", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_SpaceNode_supports_previews", nullptr);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
rna_def_space_node_overlay(brna);
RNA_api_space_node(srna);
}