WIP: Experiment: Nodes: Add new shader for node sockets #119243
|
@ -37,8 +37,6 @@ void node_insert_on_link_flags_clear(bNodeTree &node_tree);
|
|||
|
||||
/**
|
||||
* Draw a single node socket at default size.
|
||||
* \note this is only called from external code, internally #node_socket_draw_nested() is used for
|
||||
* optimized drawing of multiple/all sockets of a node.
|
||||
*/
|
||||
void node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale);
|
||||
|
||||
|
|
|
@ -1799,6 +1799,152 @@ void node_link_bezier_points_evaluated(const bNodeLink &link,
|
|||
sizeof(float2));
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Node Socket Drawing
|
||||
* \{ */
|
||||
|
||||
/* Node Socket shader parameters, must match the shader layout. */
|
||||
struct NodeSocketShaderParameters {
|
||||
rctf rect;
|
||||
float color_inner[4];
|
||||
float color_outline[4];
|
||||
float outline_thickness;
|
||||
float outline_offset;
|
||||
float dot_radius;
|
||||
float shape;
|
||||
};
|
||||
|
||||
/* Keep in sync with shader. */
|
||||
#define MAX_SOCKET_PARAMETERS 4
|
||||
#define MAX_SOCKET_INSTANCE 32
|
||||
|
||||
static struct {
|
||||
blender::gpu::Batch *batch;
|
||||
NodeSocketShaderParameters params[MAX_SOCKET_INSTANCE];
|
||||
int count;
|
||||
bool enabled;
|
||||
} g_batch_nodesocket;
|
||||
|
||||
blender::gpu::Batch *nodesocket_batch_init(void)
|
||||
{
|
||||
if (g_batch_nodesocket.batch == NULL) {
|
||||
GPUVertFormat format = {0};
|
||||
blender::gpu::VertBuf *vbo = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC);
|
||||
|
||||
GPU_vertbuf_data_alloc(vbo, 6);
|
||||
|
||||
GPUIndexBufBuilder ibuf;
|
||||
GPU_indexbuf_init(&ibuf, GPU_PRIM_TRIS, 2, 4);
|
||||
/* Quad to draw the node socket in. */
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 0, 1, 2);
|
||||
GPU_indexbuf_add_tri_verts(&ibuf, 2, 1, 3);
|
||||
|
||||
g_batch_nodesocket.batch = GPU_batch_create_ex(
|
||||
GPU_PRIM_TRIS, vbo, GPU_indexbuf_build(&ibuf), GPU_BATCH_OWNS_INDEX | GPU_BATCH_OWNS_VBO);
|
||||
gpu_batch_presets_register(g_batch_nodesocket.batch);
|
||||
}
|
||||
return g_batch_nodesocket.batch;
|
||||
}
|
||||
|
||||
static void nodesocket_cache_flush()
|
||||
{
|
||||
if (g_batch_nodesocket.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
blender::gpu::Batch *batch = nodesocket_batch_init();
|
||||
if (g_batch_nodesocket.count == 1) {
|
||||
/* draw single */
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODE_SOCKET);
|
||||
GPU_batch_uniform_4fv_array(
|
||||
batch, "parameters", 4, (const float(*)[4])g_batch_nodesocket.params);
|
||||
GPU_batch_draw(batch);
|
||||
}
|
||||
else {
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODE_SOCKET_INST);
|
||||
GPU_batch_uniform_4fv_array(batch,
|
||||
"parameters",
|
||||
MAX_SOCKET_PARAMETERS * MAX_SOCKET_INSTANCE,
|
||||
(float(*)[4])g_batch_nodesocket.params);
|
||||
GPU_batch_draw_instance_range(batch, 0, g_batch_nodesocket.count);
|
||||
}
|
||||
g_batch_nodesocket.count = 0;
|
||||
}
|
||||
|
||||
void nodesocket_batch_start()
|
||||
{
|
||||
BLI_assert(g_batch_nodesocket.enabled == false);
|
||||
g_batch_nodesocket.enabled = true;
|
||||
}
|
||||
|
||||
void nodesocket_batch_end()
|
||||
{
|
||||
BLI_assert(g_batch_nodesocket.enabled == true);
|
||||
g_batch_nodesocket.enabled = false;
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
nodesocket_cache_flush();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static void draw_node_socket_batch(NodeSocketShaderParameters *socket_params)
|
||||
{
|
||||
if (g_batch_nodesocket.enabled) {
|
||||
g_batch_nodesocket.params[g_batch_nodesocket.count] = *socket_params;
|
||||
g_batch_nodesocket.count++;
|
||||
|
||||
if (g_batch_nodesocket.count >= MAX_SOCKET_INSTANCE) {
|
||||
nodesocket_cache_flush();
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* draw single */
|
||||
blender::gpu::Batch *batch = nodesocket_batch_init();
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODE_SOCKET);
|
||||
GPU_batch_uniform_4fv_array(
|
||||
batch, "parameters", MAX_SOCKET_PARAMETERS, (float(*)[4])socket_params);
|
||||
GPU_batch_draw(batch);
|
||||
}
|
||||
}
|
||||
|
||||
void node_draw_nodesocket(const rctf *rect,
|
||||
const float color_inner[4],
|
||||
const float color_outline[4],
|
||||
const float outline_thickness,
|
||||
const float outline_offset,
|
||||
const float dot_radius,
|
||||
int shape)
|
||||
{
|
||||
/* WATCH: This is assuming the ModelViewProjectionMatrix is area pixel space.
|
||||
* If it has been scaled, then it's no longer valid. */
|
||||
BLI_assert((color_inner != nullptr) && (color_outline != nullptr));
|
||||
|
||||
NodeSocketShaderParameters socket_params = {};
|
||||
socket_params.rect = *rect;
|
||||
socket_params.color_inner[0] = color_inner[0];
|
||||
socket_params.color_inner[1] = color_inner[1];
|
||||
socket_params.color_inner[2] = color_inner[2];
|
||||
socket_params.color_inner[3] = color_inner[3];
|
||||
socket_params.color_outline[0] = color_outline[0];
|
||||
socket_params.color_outline[1] = color_outline[1];
|
||||
socket_params.color_outline[2] = color_outline[2];
|
||||
socket_params.color_outline[3] = color_outline[3];
|
||||
socket_params.outline_thickness = outline_thickness;
|
||||
socket_params.dot_radius = dot_radius;
|
||||
socket_params.outline_offset = outline_offset;
|
||||
socket_params.shape = float(shape) + 0.1f;
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
draw_node_socket_batch(&socket_params);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Node Link Drawing
|
||||
* \{ */
|
||||
|
||||
#define NODELINK_GROUP_SIZE 256
|
||||
#define LINK_RESOL 24
|
||||
#define LINK_WIDTH 2.5f
|
||||
|
@ -2407,3 +2553,5 @@ void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder
|
|||
|
||||
immEnd();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -1134,78 +1134,6 @@ static void node_draw_mute_line(const bContext &C,
|
|||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static void node_socket_draw(const bNodeSocket &sock,
|
||||
const float color[4],
|
||||
const float color_outline[4],
|
||||
const float size,
|
||||
const float locx,
|
||||
const float locy,
|
||||
uint pos_id,
|
||||
uint col_id,
|
||||
uint shape_id,
|
||||
uint size_id,
|
||||
uint outline_col_id)
|
||||
{
|
||||
int flags;
|
||||
|
||||
/* Set shape flags. */
|
||||
switch (sock.display_shape) {
|
||||
case SOCK_DISPLAY_SHAPE_DIAMOND:
|
||||
case SOCK_DISPLAY_SHAPE_DIAMOND_DOT:
|
||||
flags = GPU_KEYFRAME_SHAPE_DIAMOND;
|
||||
break;
|
||||
case SOCK_DISPLAY_SHAPE_SQUARE:
|
||||
case SOCK_DISPLAY_SHAPE_SQUARE_DOT:
|
||||
flags = GPU_KEYFRAME_SHAPE_SQUARE;
|
||||
break;
|
||||
default:
|
||||
case SOCK_DISPLAY_SHAPE_CIRCLE:
|
||||
case SOCK_DISPLAY_SHAPE_CIRCLE_DOT:
|
||||
flags = GPU_KEYFRAME_SHAPE_CIRCLE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ELEM(sock.display_shape,
|
||||
SOCK_DISPLAY_SHAPE_DIAMOND_DOT,
|
||||
SOCK_DISPLAY_SHAPE_SQUARE_DOT,
|
||||
SOCK_DISPLAY_SHAPE_CIRCLE_DOT))
|
||||
{
|
||||
flags |= GPU_KEYFRAME_SHAPE_INNER_DOT;
|
||||
}
|
||||
|
||||
immAttr4fv(col_id, color);
|
||||
immAttr1u(shape_id, flags);
|
||||
immAttr1f(size_id, size);
|
||||
immAttr4fv(outline_col_id, color_outline);
|
||||
immVertex2f(pos_id, locx, locy);
|
||||
}
|
||||
|
||||
static void node_socket_draw_multi_input(const float color[4],
|
||||
const float color_outline[4],
|
||||
const float width,
|
||||
const float height,
|
||||
const float2 location)
|
||||
{
|
||||
/* The other sockets are drawn with the keyframe shader. There, the outline has a base
|
||||
* thickness that can be varied but always scales with the size the socket is drawn at. Using
|
||||
* `UI_SCALE_FAC` has the same effect here. It scales the outline correctly across different
|
||||
* screen DPI's and UI scales without being affected by the 'line-width'. */
|
||||
const float outline_width = NODE_SOCK_OUTLINE_SCALE * UI_SCALE_FAC;
|
||||
|
||||
/* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width.
|
||||
*/
|
||||
const rctf rect = {
|
||||
location.x - width + outline_width * 0.5f,
|
||||
location.x + width - outline_width * 0.5f,
|
||||
location.y - height + outline_width * 0.5f,
|
||||
location.y + height - outline_width * 0.5f,
|
||||
};
|
||||
|
||||
UI_draw_roundbox_corner_set(UI_CNR_ALL);
|
||||
UI_draw_roundbox_4fv_ex(
|
||||
&rect, color, nullptr, 1.0f, color_outline, outline_width, width - outline_width * 0.5f);
|
||||
}
|
||||
|
||||
static const float virtual_node_socket_outline_color[4] = {0.5, 0.5, 0.5, 1.0};
|
||||
|
||||
static void node_socket_outline_color_get(const bool selected,
|
||||
|
@ -1695,121 +1623,28 @@ void node_socket_add_tooltip(const bNodeTree &ntree, const bNodeSocket &sock, ui
|
|||
MEM_freeN);
|
||||
}
|
||||
|
||||
static void node_socket_draw_nested(const bContext &C,
|
||||
const bNodeTree &ntree,
|
||||
PointerRNA &node_ptr,
|
||||
uiBlock &block,
|
||||
const bNodeSocket &sock,
|
||||
const uint pos_id,
|
||||
const uint col_id,
|
||||
const uint shape_id,
|
||||
const uint size_id,
|
||||
const uint outline_col_id,
|
||||
const float size,
|
||||
const bool selected)
|
||||
{
|
||||
const float2 location = sock.runtime->location;
|
||||
|
||||
float color[4];
|
||||
float outline_color[4];
|
||||
node_socket_color_get(C, ntree, node_ptr, sock, color);
|
||||
node_socket_outline_color_get(selected, sock.type, outline_color);
|
||||
|
||||
node_socket_draw(sock,
|
||||
color,
|
||||
outline_color,
|
||||
size,
|
||||
location.x,
|
||||
location.y,
|
||||
pos_id,
|
||||
col_id,
|
||||
shape_id,
|
||||
size_id,
|
||||
outline_col_id);
|
||||
|
||||
if (!node_socket_has_tooltip(ntree, sock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ideally sockets themselves should be buttons, but they aren't currently. So add an invisible
|
||||
* button on top of them for the tooltip. */
|
||||
const eUIEmbossType old_emboss = UI_block_emboss_get(&block);
|
||||
UI_block_emboss_set(&block, UI_EMBOSS_NONE);
|
||||
uiBut *but = uiDefIconBut(&block,
|
||||
UI_BTYPE_BUT,
|
||||
0,
|
||||
ICON_NONE,
|
||||
location.x - size / 2.0f,
|
||||
location.y - size / 2.0f,
|
||||
size,
|
||||
size,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
nullptr);
|
||||
|
||||
UI_but_func_tooltip_set(
|
||||
but,
|
||||
[](bContext *C, void *argN, const char * /*tip*/) {
|
||||
const SpaceNode &snode = *CTX_wm_space_node(C);
|
||||
const bNodeTree &ntree = *snode.edittree;
|
||||
const int index_in_tree = POINTER_AS_INT(argN);
|
||||
ntree.ensure_topology_cache();
|
||||
return node_socket_get_tooltip(&snode, ntree, *ntree.all_sockets()[index_in_tree]);
|
||||
},
|
||||
POINTER_FROM_INT(sock.index_in_tree()),
|
||||
nullptr);
|
||||
/* Disable the button so that clicks on it are ignored the link operator still works. */
|
||||
UI_but_flag_enable(but, UI_BUT_DISABLED);
|
||||
UI_block_emboss_set(&block, old_emboss);
|
||||
}
|
||||
#define NODE_SOCKET_OUTLINE U.pixelsize
|
||||
#define NODE_SOCKET_DOT U.scale_factor
|
||||
|
||||
void node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
|
||||
{
|
||||
const float size = NODE_SOCKSIZE_DRAW_MULIPLIER * NODE_SOCKSIZE * scale;
|
||||
rcti draw_rect = *rect;
|
||||
const float radius = NODE_SOCKSIZE * scale;
|
||||
const float2 center = {BLI_rcti_cent_x_fl(rect), BLI_rcti_cent_y_fl(rect)};
|
||||
const rctf draw_rect = {
|
||||
center.x - radius,
|
||||
center.x + radius,
|
||||
center.y - radius,
|
||||
center.y + radius,
|
||||
};
|
||||
float outline_color[4] = {0};
|
||||
|
||||
node_socket_outline_color_get(sock->flag & SELECT, sock->type, outline_color);
|
||||
|
||||
BLI_rcti_resize(&draw_rect, size, size);
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
|
||||
uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
uint outline_col_id = GPU_vertformat_attr_add(
|
||||
format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
|
||||
eGPUBlend state = GPU_blend_get();
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
GPU_program_point_size(true);
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_SHAPE);
|
||||
immUniform1f("outline_scale", NODE_SOCK_OUTLINE_SCALE);
|
||||
immUniform2f("ViewportSize", -1.0f, -1.0f);
|
||||
|
||||
/* Single point. */
|
||||
immBegin(GPU_PRIM_POINTS, 1);
|
||||
node_socket_draw(*sock,
|
||||
color,
|
||||
outline_color,
|
||||
BLI_rcti_size_y(&draw_rect),
|
||||
BLI_rcti_cent_x(&draw_rect),
|
||||
BLI_rcti_cent_y(&draw_rect),
|
||||
pos_id,
|
||||
col_id,
|
||||
shape_id,
|
||||
size_id,
|
||||
outline_col_id);
|
||||
immEnd();
|
||||
|
||||
immUnbindProgram();
|
||||
GPU_program_point_size(false);
|
||||
|
||||
/* Restore. */
|
||||
GPU_blend(state);
|
||||
node_draw_nodesocket(&draw_rect,
|
||||
color,
|
||||
outline_color,
|
||||
NODE_SOCKET_OUTLINE * scale,
|
||||
0.0f,
|
||||
NODE_SOCKET_DOT * scale,
|
||||
sock->display_shape);
|
||||
}
|
||||
|
||||
static void node_draw_preview_background(rctf *rect)
|
||||
|
@ -1917,208 +1752,93 @@ static void node_draw_shadow(const SpaceNode &snode,
|
|||
UI_draw_roundbox_4fv(&rect, false, radius + 0.5f, color);
|
||||
}
|
||||
|
||||
static void node_draw_sockets(const View2D &v2d,
|
||||
const bContext &C,
|
||||
const bNodeTree &ntree,
|
||||
const bNode &node,
|
||||
uiBlock &block,
|
||||
const bool draw_outputs,
|
||||
const bool select_all)
|
||||
static void node_draw_socket(const bContext &C,
|
||||
const bNodeTree &ntree,
|
||||
const bNode &node,
|
||||
PointerRNA &node_ptr,
|
||||
const bNodeSocket &sock,
|
||||
const float outline_thickness,
|
||||
const float outline_offset,
|
||||
const float dot_radius,
|
||||
const bool selected)
|
||||
{
|
||||
const float half_width = NODE_SOCKSIZE;
|
||||
|
||||
const bool multi_socket = (sock.flag & SOCK_MULTI_INPUT) && !(node.flag & NODE_HIDDEN);
|
||||
float half_height = multi_socket ? node_socket_calculate_height(sock) : half_width;
|
||||
|
||||
ColorTheme4f socket_color;
|
||||
ColorTheme4f outline_color;
|
||||
node_socket_color_get(C, ntree, node_ptr, sock, socket_color);
|
||||
node_socket_outline_color_get(selected, sock.type, outline_color);
|
||||
|
||||
const float2 socket_location = sock.runtime->location;
|
||||
|
||||
const rctf rect = {
|
||||
socket_location.x - half_width,
|
||||
socket_location.x + half_width,
|
||||
socket_location.y - half_height,
|
||||
socket_location.y + half_height,
|
||||
};
|
||||
|
||||
node_draw_nodesocket(&rect,
|
||||
socket_color,
|
||||
outline_color,
|
||||
outline_thickness,
|
||||
outline_offset,
|
||||
dot_radius,
|
||||
sock.display_shape);
|
||||
}
|
||||
|
||||
/* Some elements of the node tree like labels or node sockets are hardly visible when zoomed
|
||||
* out and can slow down the drawing quite a bit.
|
||||
* This function can be used to check if it's worth to draw those details and return
|
||||
* early. */
|
||||
static bool draw_node_details(const View2D &v2d)
|
||||
{
|
||||
float scale;
|
||||
UI_view2d_scale_get(&v2d, &scale, nullptr);
|
||||
return scale > 0.2f * UI_INV_SCALE_FAC;
|
||||
}
|
||||
|
||||
void node_draw_sockets(const View2D &v2d, const bContext &C, bNodeTree &ntree, const bNode &node)
|
||||
{
|
||||
if (!draw_node_details(v2d)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.input_sockets().is_empty() && node.output_sockets().is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool selected = false;
|
||||
PointerRNA nodeptr = RNA_pointer_create(
|
||||
const_cast<ID *>(&ntree.id), &RNA_Node, const_cast<bNode *>(&node));
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
|
||||
uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
|
||||
uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
|
||||
uint outline_col_id = GPU_vertformat_attr_add(
|
||||
format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
const float outline_thickness = NODE_SOCKET_OUTLINE;
|
||||
const float border_offset = 0.0f;
|
||||
const float dot_radius = NODE_SOCKET_DOT;
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
GPU_program_point_size(true);
|
||||
immBindBuiltinProgram(GPU_SHADER_KEYFRAME_SHAPE);
|
||||
immUniform1f("outline_scale", NODE_SOCK_OUTLINE_SCALE);
|
||||
immUniform2f("ViewportSize", -1.0f, -1.0f);
|
||||
|
||||
/* Set handle size. */
|
||||
const float socket_draw_size = NODE_SOCKSIZE * NODE_SOCKSIZE_DRAW_MULIPLIER;
|
||||
float scale;
|
||||
UI_view2d_scale_get(&v2d, &scale, nullptr);
|
||||
scale *= socket_draw_size;
|
||||
|
||||
if (!select_all) {
|
||||
immBeginAtMost(GPU_PRIM_POINTS, node.input_sockets().size() + node.output_sockets().size());
|
||||
}
|
||||
|
||||
PointerRNA node_ptr = RNA_pointer_create(
|
||||
&const_cast<ID &>(ntree.id), &RNA_Node, &const_cast<bNode &>(node));
|
||||
|
||||
/* Socket inputs. */
|
||||
int selected_input_len = 0;
|
||||
nodesocket_batch_start();
|
||||
/* Input sockets. */
|
||||
for (const bNodeSocket *sock : node.input_sockets()) {
|
||||
/* In "hidden" nodes: draw sockets even when panels are collapsed. */
|
||||
if (!node.is_socket_icon_drawn(*sock)) {
|
||||
continue;
|
||||
}
|
||||
if (select_all || (sock->flag & SELECT)) {
|
||||
if (!(sock->flag & SOCK_MULTI_INPUT)) {
|
||||
/* Don't add multi-input sockets here since they are drawn in a different batch. */
|
||||
selected_input_len++;
|
||||
}
|
||||
const bool selected = (sock->flag & SELECT);
|
||||
node_draw_socket(
|
||||
C, ntree, node, nodeptr, *sock, outline_thickness, border_offset, dot_radius, selected);
|
||||
}
|
||||
|
||||
/* Output sockets. */
|
||||
for (const bNodeSocket *sock : node.output_sockets()) {
|
||||
if (!node.is_socket_icon_drawn(*sock)) {
|
||||
continue;
|
||||
}
|
||||
/* Don't draw multi-input sockets here since they are drawn in a different batch. */
|
||||
if (sock->flag & SOCK_MULTI_INPUT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
node_socket_draw_nested(C,
|
||||
ntree,
|
||||
node_ptr,
|
||||
block,
|
||||
*sock,
|
||||
pos_id,
|
||||
col_id,
|
||||
shape_id,
|
||||
size_id,
|
||||
outline_col_id,
|
||||
scale,
|
||||
selected);
|
||||
}
|
||||
|
||||
/* Socket outputs. */
|
||||
int selected_output_len = 0;
|
||||
if (draw_outputs) {
|
||||
for (const bNodeSocket *sock : node.output_sockets()) {
|
||||
/* In "hidden" nodes: draw sockets even when panels are collapsed. */
|
||||
if (!node.is_socket_icon_drawn(*sock)) {
|
||||
continue;
|
||||
}
|
||||
if (select_all || (sock->flag & SELECT)) {
|
||||
selected_output_len++;
|
||||
continue;
|
||||
}
|
||||
|
||||
node_socket_draw_nested(C,
|
||||
ntree,
|
||||
node_ptr,
|
||||
block,
|
||||
*sock,
|
||||
pos_id,
|
||||
col_id,
|
||||
shape_id,
|
||||
size_id,
|
||||
outline_col_id,
|
||||
scale,
|
||||
selected);
|
||||
}
|
||||
}
|
||||
|
||||
if (!select_all) {
|
||||
immEnd();
|
||||
}
|
||||
|
||||
/* Go back and draw selected sockets. */
|
||||
if (selected_input_len + selected_output_len > 0) {
|
||||
/* Outline for selected sockets. */
|
||||
|
||||
selected = true;
|
||||
|
||||
immBegin(GPU_PRIM_POINTS, selected_input_len + selected_output_len);
|
||||
|
||||
if (selected_input_len) {
|
||||
/* Socket inputs. */
|
||||
for (const bNodeSocket *sock : node.input_sockets()) {
|
||||
if (!node.is_socket_icon_drawn(*sock)) {
|
||||
continue;
|
||||
}
|
||||
/* Don't draw multi-input sockets here since they are drawn in a different batch. */
|
||||
if (sock->flag & SOCK_MULTI_INPUT) {
|
||||
continue;
|
||||
}
|
||||
if (select_all || (sock->flag & SELECT)) {
|
||||
node_socket_draw_nested(C,
|
||||
ntree,
|
||||
node_ptr,
|
||||
block,
|
||||
*sock,
|
||||
pos_id,
|
||||
col_id,
|
||||
shape_id,
|
||||
size_id,
|
||||
outline_col_id,
|
||||
scale,
|
||||
selected);
|
||||
if (--selected_input_len == 0) {
|
||||
/* Stop as soon as last one is drawn. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_output_len) {
|
||||
/* Socket outputs. */
|
||||
for (const bNodeSocket *sock : node.output_sockets()) {
|
||||
if (!node.is_socket_icon_drawn(*sock)) {
|
||||
continue;
|
||||
}
|
||||
if (select_all || (sock->flag & SELECT)) {
|
||||
node_socket_draw_nested(C,
|
||||
ntree,
|
||||
node_ptr,
|
||||
block,
|
||||
*sock,
|
||||
pos_id,
|
||||
col_id,
|
||||
shape_id,
|
||||
size_id,
|
||||
outline_col_id,
|
||||
scale,
|
||||
selected);
|
||||
if (--selected_output_len == 0) {
|
||||
/* Stop as soon as last one is drawn. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
immEnd();
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
|
||||
GPU_program_point_size(false);
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
/* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox`
|
||||
* rather than with `GL_POINT`. */
|
||||
for (const bNodeSocket *socket : node.input_sockets()) {
|
||||
if (!node.is_socket_icon_drawn(*socket)) {
|
||||
continue;
|
||||
}
|
||||
if (!(socket->flag & SOCK_MULTI_INPUT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool is_node_hidden = (node.flag & NODE_HIDDEN);
|
||||
const float width = 0.5f * socket_draw_size;
|
||||
float height = is_node_hidden ? width : node_socket_calculate_height(*socket) - width;
|
||||
|
||||
float color[4];
|
||||
float outline_color[4];
|
||||
node_socket_color_get(C, ntree, node_ptr, *socket, color);
|
||||
node_socket_outline_color_get(socket->flag & SELECT, socket->type, outline_color);
|
||||
|
||||
const float2 location = socket->runtime->location;
|
||||
node_socket_draw_multi_input(color, outline_color, width, height, location);
|
||||
const bool selected = (sock->flag & SELECT);
|
||||
node_draw_socket(
|
||||
C, ntree, node, nodeptr, *sock, outline_thickness, border_offset, dot_radius, selected);
|
||||
}
|
||||
nodesocket_batch_end();
|
||||
}
|
||||
|
||||
static void node_panel_toggle_button_cb(bContext *C, void *panel_state_argv, void *ntree_argv)
|
||||
|
@ -3316,13 +3036,7 @@ static void node_draw_basis(const bContext &C,
|
|||
UI_draw_roundbox_4fv(&rect, false, BASIS_RAD + outline_width, color_outline);
|
||||
}
|
||||
|
||||
float scale;
|
||||
UI_view2d_scale_get(&v2d, &scale, nullptr);
|
||||
|
||||
/* Skip slow socket drawing if zoom is small. */
|
||||
if (scale > 0.2f) {
|
||||
node_draw_sockets(v2d, C, ntree, node, block, true, false);
|
||||
}
|
||||
node_draw_sockets(v2d, C, ntree, node);
|
||||
|
||||
if (is_node_panels_supported(node)) {
|
||||
node_draw_panels(ntree, node, block);
|
||||
|
@ -3511,7 +3225,7 @@ static void node_draw_hidden(const bContext &C,
|
|||
immUnbindProgram();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
|
||||
node_draw_sockets(v2d, C, ntree, node, block, true, false);
|
||||
node_draw_sockets(v2d, C, ntree, node);
|
||||
|
||||
UI_block_end(&C, &block);
|
||||
UI_block_draw(&C, &block);
|
||||
|
@ -3660,16 +3374,16 @@ static void reroute_node_prepare_for_draw(bNode &node)
|
|||
{
|
||||
const float2 loc = node_to_view(node, float2(0));
|
||||
|
||||
/* Reroute node has exactly one input and one output, both in the same place. */
|
||||
/* When the node is hidden, the input and output socket are both in the same place. */
|
||||
node.input_socket(0).runtime->location = loc;
|
||||
node.output_socket(0).runtime->location = loc;
|
||||
|
||||
const float size = 8.0f;
|
||||
node.width = size * 2;
|
||||
node.runtime->totr.xmin = loc.x - size;
|
||||
node.runtime->totr.xmax = loc.x + size;
|
||||
node.runtime->totr.ymax = loc.y + size;
|
||||
node.runtime->totr.ymin = loc.y - size;
|
||||
const float radius = NODE_SOCKSIZE;
|
||||
node.width = radius * 2;
|
||||
node.runtime->totr.xmin = loc.x - radius;
|
||||
node.runtime->totr.xmax = loc.x + radius;
|
||||
node.runtime->totr.ymax = loc.y + radius;
|
||||
node.runtime->totr.ymin = loc.y - radius;
|
||||
}
|
||||
|
||||
static void node_update_nodetree(const bContext &C,
|
||||
|
@ -3842,35 +3556,71 @@ static void frame_node_draw(const bContext &C,
|
|||
UI_block_draw(&C, &block);
|
||||
}
|
||||
|
||||
static void reroute_node_draw(
|
||||
const bContext &C, ARegion ®ion, bNodeTree &ntree, const bNode &node, uiBlock &block)
|
||||
void reroute_node_draw_body(const bContext &C,
|
||||
const bNodeTree &ntree,
|
||||
const bNode &node,
|
||||
const bool selected)
|
||||
{
|
||||
BLI_assert(node.is_reroute());
|
||||
|
||||
bNodeSocket &sock = *static_cast<bNodeSocket *>(node.inputs.first);
|
||||
|
||||
PointerRNA nodeptr = RNA_pointer_create(
|
||||
const_cast<ID *>(&ntree.id), &RNA_Node, const_cast<bNode *>(&node));
|
||||
|
||||
ColorTheme4f socket_color;
|
||||
ColorTheme4f outline_color;
|
||||
|
||||
node_socket_color_get(C, ntree, nodeptr, sock, socket_color);
|
||||
node_socket_outline_color_get(selected, sock.type, outline_color);
|
||||
|
||||
node_draw_nodesocket(&node.runtime->totr,
|
||||
socket_color,
|
||||
outline_color,
|
||||
NODE_SOCKET_OUTLINE,
|
||||
0.0f,
|
||||
NODE_SOCKET_DOT,
|
||||
sock.display_shape);
|
||||
}
|
||||
|
||||
static void reroute_node_draw_label(const bNode &node, uiBlock &block)
|
||||
{
|
||||
/* Draw title (node label). */
|
||||
char showname[128]; /* 128 used below */
|
||||
STRNCPY(showname, node.label);
|
||||
const short width = 512;
|
||||
const int x = BLI_rctf_cent_x(&node.runtime->totr) - (width / 2);
|
||||
const int y = node.runtime->totr.ymax;
|
||||
|
||||
uiBut *label_but = uiDefBut(
|
||||
&block, UI_BTYPE_LABEL, 0, showname, x, y, width, short(NODE_DY), nullptr, 0, 0, nullptr);
|
||||
|
||||
UI_but_drawflag_disable(label_but, UI_BUT_TEXT_LEFT);
|
||||
}
|
||||
|
||||
static void reroute_node_draw(
|
||||
const bContext &C, ARegion ®ion, const bNodeTree &ntree, const bNode &node, uiBlock &block)
|
||||
{
|
||||
/* Skip if out of view. */
|
||||
const rctf &rct = node.runtime->totr;
|
||||
if (rct.xmax < region.v2d.cur.xmin || rct.xmin > region.v2d.cur.xmax ||
|
||||
rct.ymax < region.v2d.cur.ymin || node.runtime->totr.ymin > region.v2d.cur.ymax)
|
||||
const View2D &v2d = region.v2d;
|
||||
|
||||
/* Skip if out of view. */
|
||||
if (rct.xmax < v2d.cur.xmin || rct.xmin > v2d.cur.xmax || rct.ymax < v2d.cur.ymin ||
|
||||
node.runtime->totr.ymin > v2d.cur.ymax)
|
||||
{
|
||||
UI_block_end(&C, &block);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.label[0] != '\0') {
|
||||
/* Draw title (node label). */
|
||||
char showname[128]; /* 128 used below */
|
||||
STRNCPY(showname, node.label);
|
||||
const short width = 512;
|
||||
const int x = BLI_rctf_cent_x(&node.runtime->totr) - (width / 2);
|
||||
const int y = node.runtime->totr.ymax;
|
||||
|
||||
uiBut *label_but = uiDefBut(
|
||||
&block, UI_BTYPE_LABEL, 0, showname, x, y, width, short(NODE_DY), nullptr, 0, 0, nullptr);
|
||||
|
||||
UI_but_drawflag_disable(label_but, UI_BUT_TEXT_LEFT);
|
||||
if (draw_node_details(v2d)) {
|
||||
if (node.label[0] != '\n') {
|
||||
reroute_node_draw_label(node, block);
|
||||
}
|
||||
}
|
||||
|
||||
/* Only draw input socket as they all are placed on the same position highlight
|
||||
* if node itself is selected, since we don't display the node body separately. */
|
||||
node_draw_sockets(region.v2d, C, ntree, node, block, false, node.flag & SELECT);
|
||||
/* Only draw the input socket, since all sockets are at the same location. */
|
||||
const bool selected = node.flag & NODE_SELECT;
|
||||
reroute_node_draw_body(C, ntree, node, selected);
|
||||
|
||||
UI_block_end(&C, &block);
|
||||
UI_block_draw(&C, &block);
|
||||
|
|
|
@ -107,7 +107,7 @@ struct CompoJob {
|
|||
|
||||
float node_socket_calculate_height(const bNodeSocket &socket)
|
||||
{
|
||||
float sock_height = NODE_SOCKSIZE * NODE_SOCKSIZE_DRAW_MULIPLIER;
|
||||
float sock_height = NODE_SOCKSIZE;
|
||||
if (socket.flag & SOCK_MULTI_INPUT) {
|
||||
sock_height += max_ii(NODE_MULTI_INPUT_LINK_GAP * 0.5f * socket.runtime->total_inputs,
|
||||
NODE_SOCKSIZE);
|
||||
|
|
|
@ -144,7 +144,6 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
|
|||
#define NODE_HEIGHT(node) (node.height * UI_SCALE_FAC)
|
||||
#define NODE_MARGIN_X (1.2f * U.widget_unit)
|
||||
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
|
||||
#define NODE_SOCKSIZE_DRAW_MULIPLIER 2.25f
|
||||
#define NODE_SOCK_OUTLINE_SCALE 1.0f
|
||||
#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit)
|
||||
#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
|
||||
|
@ -245,6 +244,18 @@ NodeResizeDirection node_get_resize_direction(const SpaceNode &snode,
|
|||
int x,
|
||||
int y);
|
||||
|
||||
/* node socket batched drawing */
|
||||
void UI_node_socket_draw_cache_flush();
|
||||
void nodesocket_batch_start();
|
||||
void nodesocket_batch_end();
|
||||
void node_draw_nodesocket(const rctf *rect,
|
||||
const float color_inner[4],
|
||||
const float color_outline[4],
|
||||
const float outline_thickness,
|
||||
const float outline_offset,
|
||||
const float dot_radius,
|
||||
int shape);
|
||||
|
||||
void nodelink_batch_start(SpaceNode &snode);
|
||||
void nodelink_batch_end(SpaceNode &snode);
|
||||
|
||||
|
|
|
@ -150,13 +150,6 @@ static bool node_under_mouse_tweak(const SpaceNode &snode, const float2 &mouse)
|
|||
{
|
||||
for (bNode *node : tree_draw_order_calc_nodes_reversed(*snode.edittree)) {
|
||||
switch (node->type) {
|
||||
case NODE_REROUTE: {
|
||||
const float2 location = node_to_view(*node, {node->locx, node->locy});
|
||||
if (math::distance_squared(mouse, location) < square_f(24.0f)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NODE_FRAME: {
|
||||
if (node_frame_select_isect_mouse(snode, *node, mouse)) {
|
||||
return true;
|
||||
|
|
|
@ -425,6 +425,8 @@ set(GLSL_SRC
|
|||
shaders/gpu_shader_2D_widget_base_frag.glsl
|
||||
shaders/gpu_shader_2D_widget_shadow_vert.glsl
|
||||
shaders/gpu_shader_2D_widget_shadow_frag.glsl
|
||||
shaders/gpu_shader_2D_node_socket_frag.glsl
|
||||
shaders/gpu_shader_2D_node_socket_vert.glsl
|
||||
shaders/gpu_shader_2D_nodelink_frag.glsl
|
||||
shaders/gpu_shader_2D_nodelink_vert.glsl
|
||||
shaders/gpu_shader_2D_line_dashed_frag.glsl
|
||||
|
@ -745,6 +747,7 @@ set(SRC_SHADER_CREATE_INFOS
|
|||
shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_rect_color_info.hh
|
||||
shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh
|
||||
shaders/infos/gpu_shader_2D_node_socket_info.hh
|
||||
shaders/infos/gpu_shader_2D_nodelink_info.hh
|
||||
shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh
|
||||
shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh
|
||||
|
|
|
@ -58,6 +58,10 @@ enum eGPUBuiltinShader {
|
|||
GPU_SHADER_2D_WIDGET_BASE,
|
||||
GPU_SHADER_2D_WIDGET_BASE_INST,
|
||||
GPU_SHADER_2D_WIDGET_SHADOW,
|
||||
/** Draw a node socket given it's bounding rectangle. All socket shapes are supported through
|
||||
* a single shader. */
|
||||
GPU_SHADER_2D_NODE_SOCKET,
|
||||
GPU_SHADER_2D_NODE_SOCKET_INST,
|
||||
/** Draw a node link given an input quadratic Bezier curve. */
|
||||
GPU_SHADER_2D_NODELINK,
|
||||
GPU_SHADER_2D_NODELINK_INST,
|
||||
|
|
|
@ -81,6 +81,10 @@ static const char *builtin_shader_create_info_name(eGPUBuiltinShader shader)
|
|||
return "gpu_shader_2D_widget_base_inst";
|
||||
case GPU_SHADER_2D_WIDGET_SHADOW:
|
||||
return "gpu_shader_2D_widget_shadow";
|
||||
case GPU_SHADER_2D_NODE_SOCKET:
|
||||
return "gpu_shader_2D_node_socket";
|
||||
case GPU_SHADER_2D_NODE_SOCKET_INST:
|
||||
return "gpu_shader_2D_node_socket_inst";
|
||||
case GPU_SHADER_2D_NODELINK:
|
||||
return "gpu_shader_2D_nodelink";
|
||||
case GPU_SHADER_2D_NODELINK_INST:
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* SPDX-FileCopyrightText: 2018-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#define COS45 (0.70710678118)
|
||||
#define SIN45 (0.70710678118)
|
||||
|
||||
float square_sdf(vec2 absCo, float half_width)
|
||||
{
|
||||
vec2 extruded = vec2(max(0.0, absCo.x - half_width), max(0.0, absCo.y - half_width));
|
||||
return dot(extruded, extruded);
|
||||
}
|
||||
|
||||
vec2 rotate_45(vec2 co)
|
||||
{
|
||||
return vec2(COS45 * co.x - SIN45 * co.y, SIN45 * co.x + COS45 * co.y);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 absUV = abs(uv);
|
||||
vec2 co = vec2(max(absUV.x - extrusion.x, 0.0), max(absUV.y - extrusion.y, 0.0));
|
||||
|
||||
co = (is_diamond == 1) ? abs(rotate_45(co)) : co;
|
||||
float distSquared = square_sdf(co, sdf_shape_radius);
|
||||
|
||||
/* Needed to draw two dots for the wide reroute nodes. */
|
||||
vec2 biCenteredUV = abs(absUV - extrusion);
|
||||
|
||||
/* Black mask with a white dot */
|
||||
float mask_dot = smoothstep(dotThresholds[1], dotThresholds[0], dot(biCenteredUV, biCenteredUV));
|
||||
|
||||
/* Alpha for the socket: White where the socket is, black outside of it. */
|
||||
float mask_all = smoothstep(thresholds[3], thresholds[2], distSquared);
|
||||
|
||||
/* Mask for the outline. The inner part of the socket is masked with black. */
|
||||
bool noOutline = thresholds[2] - thresholds[0] < 0.0001;
|
||||
float mask_outline = noOutline ? 0.0 : smoothstep(thresholds[0], thresholds[1], distSquared);
|
||||
mask_outline += mask_dot;
|
||||
|
||||
fragColor = mix(finalColor, finalOutlineColor, mask_outline);
|
||||
fragColor.a *= mask_all;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/* SPDX-FileCopyrightText: 2018-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* Values in `eNodeSocketDisplayShape` in DNA_node_types.h. Keep in sync. */
|
||||
#define SOCK_DISPLAY_SHAPE_CIRCLE 0
|
||||
#define SOCK_DISPLAY_SHAPE_SQUARE 1
|
||||
#define SOCK_DISPLAY_SHAPE_DIAMOND 2
|
||||
#define SOCK_DISPLAY_SHAPE_CIRCLE_DOT 3
|
||||
#define SOCK_DISPLAY_SHAPE_SQUARE_DOT 4
|
||||
#define SOCK_DISPLAY_SHAPE_DIAMOND_DOT 5
|
||||
|
||||
#define rect parameters[widgetID * MAX_PARAM + 0]
|
||||
#define colorInner parameters[widgetID * MAX_PARAM + 1]
|
||||
#define colorOutline parameters[widgetID * MAX_PARAM + 2]
|
||||
#define outlineThickness parameters[widgetID * MAX_PARAM + 3].x
|
||||
#define outlineOffset parameters[widgetID * MAX_PARAM + 3].y
|
||||
#define dotRadius parameters[widgetID * MAX_PARAM + 3].z
|
||||
#define shape parameters[widgetID * MAX_PARAM + 3].w
|
||||
|
||||
#define AA_SIZE 0.75
|
||||
#define IS_DIAMOND \
|
||||
(shapeFlags == SOCK_DISPLAY_SHAPE_DIAMOND || shapeFlags == SOCK_DISPLAY_SHAPE_DIAMOND_DOT)
|
||||
#define HAS_DOT \
|
||||
(shapeFlags > 2)
|
||||
|
||||
/* Offsetting by a pixel further to avoid losing pixels. */
|
||||
vec2 ofs = vec2(outlineOffset + 1.0, -outlineOffset - 1.0);
|
||||
|
||||
/* Calculate size of the original rectangle before expanding it based on the offset for the outline
|
||||
*/
|
||||
vec2 rectSize = rect.yw - rect.xz;
|
||||
float minSize = min(rectSize.x, rectSize.y);
|
||||
|
||||
/* Set the parameters for the sdf function that is used to draw the socket. */
|
||||
#define CIRCLE_RADIUS 0.5
|
||||
#define SQUARE_RADIUS 0.5
|
||||
#define DIAMOND_RADIUS 0.4
|
||||
|
||||
vec3 shapeRadii = vec3(CIRCLE_RADIUS, SQUARE_RADIUS, DIAMOND_RADIUS);
|
||||
vec3 cornerRoundness = vec3(1.0, 0.4, 0.4);
|
||||
|
||||
int shapeFlags = int(shape);
|
||||
int shapeIndex = shapeFlags % 3;
|
||||
float shapeRadius = shapeRadii[shapeIndex];
|
||||
float cornerRadius = shapeRadius * cornerRoundness[shapeIndex];
|
||||
|
||||
float pow2(float x)
|
||||
{
|
||||
return x * x;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 pos;
|
||||
switch (gl_VertexID) {
|
||||
default:
|
||||
case 0: {
|
||||
pos = rect.xz + ofs.yy;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
pos = rect.xw + ofs.yx;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
pos = rect.yz + ofs.xy;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
pos = rect.yw + ofs.xx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
|
||||
|
||||
vec2 centeredCoordinates = pos - ((rect.xz + rect.yw) / 2.0);
|
||||
uv = centeredCoordinates / minSize;
|
||||
|
||||
/* Calculate the necessary "extrusion" of the coordinates to draw the middle part of
|
||||
* multi sockets. */
|
||||
float aspect = rectSize.x / rectSize.y;
|
||||
extrusion = (aspect > 1.0) ? vec2((aspect - 1.0) / 2.0, 0.0) :
|
||||
vec2(0.0, ((1.0 / aspect) - 1.0) / 2.0);
|
||||
|
||||
/* Thresholds for the masks in UV Space. Use squared values, so we can use the squared length in
|
||||
* the fragment shader. */
|
||||
float InnerOutlineUVSquared1 = pow2(
|
||||
((outlineOffset - 0.5 * outlineThickness - AA_SIZE) / minSize) + cornerRadius);
|
||||
float InnerOutlineUVSquared2 = pow2(((outlineOffset - 0.5 * outlineThickness) / minSize) +
|
||||
cornerRadius);
|
||||
float OuterOutlineUVSquared1 = pow2(
|
||||
((outlineOffset + 0.5 * outlineThickness - AA_SIZE) / minSize) + cornerRadius);
|
||||
float OuterOutlineUVSquared2 = pow2(((outlineOffset + 0.5 * outlineThickness) / minSize) +
|
||||
cornerRadius);
|
||||
|
||||
thresholds = vec4(InnerOutlineUVSquared1,
|
||||
InnerOutlineUVSquared2,
|
||||
OuterOutlineUVSquared1,
|
||||
OuterOutlineUVSquared2);
|
||||
|
||||
/* Thresholds for the mask of the dot. */
|
||||
bool has_dot = HAS_DOT;
|
||||
float dotRadiusSquared1 = has_dot ? pow2((dotRadius - AA_SIZE) / minSize) : (-1.0f);
|
||||
float dotRadiusSquared2 = has_dot ? pow2(dotRadius / minSize) : 0.0f;
|
||||
|
||||
dotThresholds = vec2(dotRadiusSquared1, dotRadiusSquared2);
|
||||
|
||||
/* Shape parameters. */
|
||||
sdf_shape_radius = shapeRadius - cornerRadius;
|
||||
is_diamond = IS_DIAMOND ? 1 : 0;
|
||||
|
||||
/* Pass through parameters. */
|
||||
finalColor = colorInner;
|
||||
finalOutlineColor = colorOutline;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "gpu_interface_info.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
GPU_SHADER_INTERFACE_INFO(gpu_node_socket_iface, "")
|
||||
.flat(Type::FLOAT, "sdf_shape_radius")
|
||||
.flat(Type::VEC4, "finalColor")
|
||||
.flat(Type::VEC4, "finalOutlineColor")
|
||||
.flat(Type::VEC4, "thresholds")
|
||||
.flat(Type::VEC2, "dotThresholds")
|
||||
.flat(Type::VEC2, "extrusion")
|
||||
.flat(Type::INT, "is_diamond")
|
||||
.smooth(Type::VEC2, "uv");
|
||||
|
||||
/* TODO(Leon): Share with C code. */
|
||||
/* TODO(Leon): Tweak the instance count to test if there's a noticable sweet spot. */
|
||||
#define MAX_SOCKET_PARAMETERS 4
|
||||
#define MAX_SOCKET_INSTANCE 32
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_2D_node_socket_shared)
|
||||
.define("MAX_PARAM", STRINGIFY(MAX_SOCKET_PARAMETERS))
|
||||
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
|
||||
.vertex_out(gpu_node_socket_iface)
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
.vertex_source("gpu_shader_2D_node_socket_vert.glsl")
|
||||
.fragment_source("gpu_shader_2D_node_socket_frag.glsl");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_2D_node_socket)
|
||||
.do_static_compilation(true)
|
||||
/* gl_InstanceID is supposed to be 0 if not drawing instances, but this seems
|
||||
* to be violated in some drivers. For example, macOS 10.15.4 and Intel Iris
|
||||
* causes #78307 when using gl_InstanceID outside of instance. */
|
||||
.define("widgetID", "0")
|
||||
.push_constant(Type::VEC4, "parameters", MAX_SOCKET_PARAMETERS)
|
||||
.additional_info("gpu_shader_2D_node_socket_shared");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_2D_node_socket_inst)
|
||||
.do_static_compilation(true)
|
||||
.define("widgetID", "gl_InstanceID")
|
||||
.push_constant(Type::VEC4, "parameters", (MAX_SOCKET_PARAMETERS * MAX_SOCKET_INSTANCE))
|
||||
.additional_info("gpu_shader_2D_node_socket_shared");
|
Loading…
Reference in New Issue