Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_node / drawnode.c
index 63bd305..db718da 100644 (file)
 #include "BLF_api.h"
 #include "BLT_translation.h"
 
-#include "BIF_gl.h"
 #include "BIF_glutil.h"
 
+#include "GPU_draw.h"
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
 #include "RNA_access.h"
 #include "RNA_define.h"
 
@@ -62,6 +66,7 @@
 #include "WM_types.h"
 
 #include "UI_resources.h"
+#include "UI_view2d.h"
 
 #include "IMB_colormanagement.h"
 #include "IMB_imbuf_types.h"
@@ -80,49 +85,6 @@ static void node_socket_button_label(bContext *UNUSED(C), uiLayout *layout, Poin
        uiItemL(layout, text, 0);
 }
 
-
-/* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */
-
-#if 0 /* UNUSED */
-static void node_draw_socket_new(bNodeSocket *sock, float size)
-{
-       float x = sock->locx, y = sock->locy;
-
-       /* 16 values of sin function */
-       static float si[16] = {
-               0.00000000f, 0.39435585f, 0.72479278f, 0.93775213f,
-               0.99871650f, 0.89780453f, 0.65137248f, 0.29936312f,
-               -0.10116832f, -0.48530196f, -0.79077573f, -0.96807711f,
-               -0.98846832f, -0.84864425f, -0.57126821f, -0.20129852f
-       };
-       /* 16 values of cos function */
-       static float co[16] = {
-               1.00000000f, 0.91895781f, 0.68896691f, 0.34730525f,
-               -0.05064916f, -0.44039415f, -0.75875812f, -0.95413925f,
-               -0.99486932f, -0.87434661f, -0.61210598f, -0.25065253f,
-               0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
-       };
-       int a;
-
-       glColor3ub(180, 180, 180);
-
-       glBegin(GL_POLYGON);
-       for (a = 0; a < 16; a++)
-               glVertex2f(x + size * si[a], y + size * co[a]);
-       glEnd();
-
-       glColor4ub(0, 0, 0, 150);
-       glEnable(GL_BLEND);
-       glEnable(GL_LINE_SMOOTH);
-       glBegin(GL_LINE_LOOP);
-       for (a = 0; a < 16; a++)
-               glVertex2f(x + size * si[a], y + size * co[a]);
-       glEnd();
-       glDisable(GL_LINE_SMOOTH);
-       glDisable(GL_BLEND);
-}
-#endif
-
 /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */
 
 static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -392,6 +354,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
        const int font_size = data->label_size / aspect;
        const float margin = (float)(NODE_DY / 4);
        int label_height;
+       unsigned char color[3];
 
        nodeLabel(ntree, node, label, sizeof(label));
 
@@ -400,7 +363,8 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
        BLF_size(fontid, MIN2(24, font_size), U.dpi); /* clamp otherwise it can suck up a LOT of memory */
 
        /* title color */
-       UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
+       UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color);
+       BLF_color3ubv(fontid, color);
 
        width = BLF_width(fontid, label, sizeof(label));
        ascender = BLF_ascender(fontid);
@@ -465,7 +429,7 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
 {
        rctf *rct = &node->totr;
        int color_id = node_get_colorid(node);
-       unsigned char color[4];
+       float color[4];
        float alpha;
 
        /* skip if out of view */
@@ -475,38 +439,30 @@ static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode,
                return;
        }
 
-       UI_GetThemeColor4ubv(TH_NODE_FRAME, color);
-       alpha = (float)(color[3]) / 255.0f;
+       UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+       alpha = color[3];
 
        /* shadow */
        node_draw_shadow(snode, node, BASIS_RAD, alpha);
 
        /* body */
-       if (node->flag & NODE_CUSTOM_COLOR)
-               glColor4f(node->color[0], node->color[1], node->color[2], alpha);
+       if (node->flag & NODE_CUSTOM_COLOR) {
+               rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], alpha);
+       }
        else
-               UI_ThemeColor4(TH_NODE_FRAME);
-       glEnable(GL_BLEND);
+               UI_GetThemeColor4fv(TH_NODE_FRAME, color);
+
        UI_draw_roundbox_corner_set(UI_CNR_ALL);
-       UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
-       glDisable(GL_BLEND);
+       UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
 
        /* outline active and selected emphasis */
        if (node->flag & SELECT) {
-               glEnable(GL_BLEND);
-               glEnable(GL_LINE_SMOOTH);
-
                if (node->flag & NODE_ACTIVE)
-                       UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
+                       UI_GetThemeColorShadeAlpha4fv(TH_ACTIVE, 0, -40, color);
                else
-                       UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
-               UI_draw_roundbox_corner_set(UI_CNR_ALL);
-               UI_draw_roundbox_gl_mode(GL_LINE_LOOP,
-                         rct->xmin, rct->ymin,
-                         rct->xmax, rct->ymax, BASIS_RAD);
+                       UI_GetThemeColorShadeAlpha4fv(TH_SELECT, 0, -40, color);
 
-               glDisable(GL_LINE_SMOOTH);
-               glDisable(GL_BLEND);
+               UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
        }
 
        /* label */
@@ -580,15 +536,9 @@ static void node_draw_reroute_prepare(const bContext *UNUSED(C), bNodeTree *UNUS
 static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(snode),
                               bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key))
 {
-       bNodeSocket *sock;
        char showname[128]; /* 128 used below */
        rctf *rct = &node->totr;
 
-#if 0   /* UNUSED */
-       float size = NODE_REROUTE_SIZE;
-#endif
-       float socket_size = NODE_SOCKSIZE;
-
        /* skip if out of view */
        if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
            node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax)
@@ -602,23 +552,26 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
         * selection state is indicated by socket outline below!
         */
 #if 0
+       float size = NODE_REROUTE_SIZE;
+
        /* body */
+       float debug_color[4];
        UI_draw_roundbox_corner_set(UI_CNR_ALL);
-       UI_ThemeColor4(TH_NODE);
-       glEnable(GL_BLEND);
-       UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
-       glDisable(GL_BLEND);
+       UI_GetThemeColor4fv(TH_NODE, debug_color);
+       UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
 
        /* outline active and selected emphasis */
        if (node->flag & SELECT) {
                glEnable(GL_BLEND);
                glEnable(GL_LINE_SMOOTH);
                /* using different shades of TH_TEXT_HI for the empasis, like triangle */
-               if (node->flag & NODE_ACTIVE)
-                       UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
-               else
-                       UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
-               UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size);
+               if (node->flag & NODE_ACTIVE) {
+                       UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, 0, -40, debug_color);
+               }
+               else {
+                       UI_GetThemeColorShadeAlpha4fv(TH_TEXT_HI, -20, -120, debug_color);
+               }
+               UI_draw_roundbox_4fv(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, size, debug_color);
 
                glDisable(GL_LINE_SMOOTH);
                glDisable(GL_BLEND);
@@ -637,9 +590,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
        /* only draw input socket. as they all are placed on the same position.
         * highlight also if node itself is selected, since we don't display the node body separately!
         */
-       for (sock = node->inputs.first; sock; sock = sock->next) {
-               node_socket_draw(C, ntree, node, sock, socket_size, (sock->flag & SELECT) || (node->flag & SELECT));
-       }
+       node_draw_sockets(&ar->v2d, C, ntree, node, false, node->flag & SELECT);
 
        UI_block_end(C, node->block);
        UI_block_draw(C, node->block);
@@ -728,21 +679,6 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
        }
 }
 
-static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
-       bNode *node = ptr->data;
-       uiLayout *col;
-
-       uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL);
-
-       if (!node->id) return;
-
-       col = uiLayoutColumn(layout, false);
-       uiItemR(col, ptr, "use_diffuse", 0, NULL, ICON_NONE);
-       uiItemR(col, ptr, "use_specular", 0, NULL, ICON_NONE);
-       uiItemR(col, ptr, "invert_normal", 0, NULL, ICON_NONE);
-}
-
 static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiLayout *row, *col, *sub;
@@ -790,30 +726,6 @@ static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C
        uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE);
 }
 
-static void node_shader_buts_geometry(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
-       PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-       uiLayout *col;
-
-       col = uiLayoutColumn(layout, false);
-
-       if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
-               PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-
-               uiItemPointerR(col, ptr, "uv_layer", &dataptr, "uv_textures", "", ICON_NONE);
-               uiItemPointerR(col, ptr, "color_layer", &dataptr, "vertex_colors", "", ICON_NONE);
-       }
-       else {
-               uiItemR(col, ptr, "uv_layer", 0, IFACE_("UV"), ICON_NONE);
-               uiItemR(col, ptr, "color_layer", 0, IFACE_("VCol"), ICON_NONE);
-       }
-}
-
-static void node_shader_buts_lamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
-       uiItemR(layout, ptr, "lamp_object", 0, IFACE_("Lamp Object"), ICON_NONE);
-}
-
 static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE);
@@ -1022,7 +934,7 @@ static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *pt
 
                if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
                        PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-                       uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_textures", "", ICON_NONE);
+                       uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
                }
        }
 }
@@ -1041,7 +953,7 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN
 
                if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
                        PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-                       uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_textures", "", ICON_NONE);
+                       uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
                }
                else
                        uiItemR(layout, ptr, "uv_map", 0, "", 0);
@@ -1068,7 +980,7 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
 
                if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
                        PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-                       uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_textures", "", ICON_NONE);
+                       uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
                }
                else
                        uiItemR(row, ptr, "uv_map", 0, "", 0);
@@ -1172,13 +1084,6 @@ static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), Pointe
 static void node_shader_set_butfunc(bNodeType *ntype)
 {
        switch (ntype->type) {
-               case SH_NODE_MATERIAL:
-               case SH_NODE_MATERIAL_EXT:
-                       ntype->draw_buttons = node_shader_buts_material;
-                       break;
-               case SH_NODE_TEXTURE:
-                       ntype->draw_buttons = node_buts_texture;
-                       break;
                case SH_NODE_NORMAL:
                        ntype->draw_buttons = node_buts_normal;
                        break;
@@ -1212,12 +1117,6 @@ static void node_shader_set_butfunc(bNodeType *ntype)
                case SH_NODE_VECT_TRANSFORM:
                        ntype->draw_buttons = node_shader_buts_vect_transform;
                        break;
-               case SH_NODE_GEOMETRY:
-                       ntype->draw_buttons = node_shader_buts_geometry;
-                       break;
-               case SH_NODE_LAMP:
-                       ntype->draw_buttons = node_shader_buts_lamp;
-                       break;
                case SH_NODE_ATTRIBUTE:
                        ntype->draw_buttons = node_shader_buts_attribute;
                        break;
@@ -1363,7 +1262,7 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN
        uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 1);
 }
 
-static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
+static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
 {
        bNode *node = ptr->data;
        uiLayout *col, *row;
@@ -2261,14 +2160,21 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
                const float cy = y + snode->zoom * backdropHeight * node->custom4;
                const float cross_size = 12 * U.pixelsize;
 
-               glColor3f(1.0, 1.0, 1.0);
+               Gwn_VertFormat *format = immVertexFormat();
+               unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+               immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 
-               glBegin(GL_LINES);
-               glVertex2f(cx - cross_size, cy - cross_size);
-               glVertex2f(cx + cross_size, cy + cross_size);
-               glVertex2f(cx + cross_size, cy - cross_size);
-               glVertex2f(cx - cross_size, cy + cross_size);
-               glEnd();
+               immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+               immBegin(GWN_PRIM_LINES, 4);
+               immVertex2f(pos, cx - cross_size, cy - cross_size);
+               immVertex2f(pos, cx + cross_size, cy + cross_size);
+               immVertex2f(pos, cx + cross_size, cy - cross_size);
+               immVertex2f(pos, cx - cross_size, cy + cross_size);
+               immEnd();
+
+               immUnbindProgram();
        }
 }
 
@@ -2287,9 +2193,6 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN
        float cx, cy, x1, x2, x3, x4;
        float y1, y2, y3, y4;
 
-
-       glColor3f(1.0, 1.0, 1.0);
-
        cx  = x + snode->zoom * backdropWidth * boxmask->x;
        cy = y + snode->zoom * backdropHeight * boxmask->y;
 
@@ -2302,12 +2205,21 @@ static void node_composit_backdrop_boxmask(SpaceNode *snode, ImBuf *backdrop, bN
        y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
        y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
 
-       glBegin(GL_LINE_LOOP);
-       glVertex2f(x1, y1);
-       glVertex2f(x2, y2);
-       glVertex2f(x3, y3);
-       glVertex2f(x4, y4);
-       glEnd();
+       Gwn_VertFormat *format = immVertexFormat();
+       unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+       immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+       immBegin(GWN_PRIM_LINE_LOOP, 4);
+       immVertex2f(pos, x1, y1);
+       immVertex2f(pos, x2, y2);
+       immVertex2f(pos, x3, y3);
+       immVertex2f(pos, x4, y4);
+       immEnd();
+
+       immUnbindProgram();
 }
 
 static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
@@ -2325,9 +2237,6 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop
        float cx, cy, x1, x2, x3, x4;
        float y1, y2, y3, y4;
 
-
-       glColor3f(1.0, 1.0, 1.0);
-
        cx  = x + snode->zoom * backdropWidth * ellipsemask->x;
        cy = y + snode->zoom * backdropHeight * ellipsemask->y;
 
@@ -2340,13 +2249,21 @@ static void node_composit_backdrop_ellipsemask(SpaceNode *snode, ImBuf *backdrop
        y3 = cy - (-sine * -halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
        y4 = cy - (-sine * halveBoxWidth + cosine * -halveBoxHeight) * snode->zoom;
 
-       glBegin(GL_LINE_LOOP);
+       Gwn_VertFormat *format = immVertexFormat();
+       unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 
-       glVertex2f(x1, y1);
-       glVertex2f(x2, y2);
-       glVertex2f(x3, y3);
-       glVertex2f(x4, y4);
-       glEnd();
+       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+       immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+       immBegin(GWN_PRIM_LINE_LOOP, 4);
+       immVertex2f(pos, x1, y1);
+       immVertex2f(pos, x2, y2);
+       immVertex2f(pos, x3, y3);
+       immVertex2f(pos, x4, y4);
+       immEnd();
+
+       immUnbindProgram();
 }
 
 static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2546,7 +2463,7 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                        ntype->draw_buttons_ex = node_composit_buts_image_ex;
                        break;
                case CMP_NODE_R_LAYERS:
-                       ntype->draw_buttons = node_composit_buts_renderlayers;
+                       ntype->draw_buttons = node_composit_buts_viewlayers;
                        break;
                case CMP_NODE_NORMAL:
                        ntype->draw_buttons = node_buts_normal;
@@ -3236,6 +3153,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
 {
        Main *bmain = CTX_data_main(C);
        bNodeInstanceKey active_viewer_key = (snode->nodetree ? snode->nodetree->active_viewer_key : NODE_INSTANCE_KEY_NONE);
+       float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f};
        Image *ima;
        void *lock;
        ImBuf *ibuf;
@@ -3251,14 +3169,10 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
        if (ibuf) {
                float x, y;
 
-               glMatrixMode(GL_PROJECTION);
-               glPushMatrix();
-               glMatrixMode(GL_MODELVIEW);
-               glPushMatrix();
+               gpuPushProjectionMatrix();
+               gpuPushMatrix();
 
                /* somehow the offset has to be calculated inverse */
-
-               glaDefine2DArea(&ar->winrct);
                wmOrtho2_region_pixelspace(ar);
 
                x = (ar->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
@@ -3268,60 +3182,37 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
                        unsigned char *display_buffer = NULL;
                        void *cache_handle = NULL;
 
-                       if (snode->flag & (SNODE_SHOW_R | SNODE_SHOW_G | SNODE_SHOW_B)) {
-                               int ofs;
+                       if (snode->flag & (SNODE_SHOW_R | SNODE_SHOW_G | SNODE_SHOW_B | SNODE_SHOW_ALPHA)) {
 
                                display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
 
-#ifdef __BIG_ENDIAN__
-                               if      (snode->flag & SNODE_SHOW_R) ofs = 0;
-                               else if (snode->flag & SNODE_SHOW_G) ofs = 1;
-                               else                                 ofs = 2;
-#else
-                               if      (snode->flag & SNODE_SHOW_R) ofs = 1;
-                               else if (snode->flag & SNODE_SHOW_G) ofs = 2;
-                               else                                 ofs = 3;
-#endif
+                               if (snode->flag & SNODE_SHOW_R)
+                                       shuffle[0] = 1.0f;
+                               else if (snode->flag & SNODE_SHOW_G)
+                                       shuffle[1] = 1.0f;
+                               else if (snode->flag & SNODE_SHOW_B)
+                                       shuffle[2] = 1.0f;
+                               else
+                                       shuffle[3] = 1.0f;
 
-                               glPixelZoom(snode->zoom, snode->zoom);
-                               /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
+                               IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+                               GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle);
 
-                               glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT,
-                                                 display_buffer - (4 - ofs));
+                               immDrawPixelsTex(&state, x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+                                                display_buffer, snode->zoom, snode->zoom, NULL);
 
-                               glPixelZoom(1.0f, 1.0f);
-                       }
-                       else if (snode->flag & SNODE_SHOW_ALPHA) {
-                               display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
-
-                               glPixelZoom(snode->zoom, snode->zoom);
-                               /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
-#ifdef __BIG_ENDIAN__
-                               glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
-#endif
-                               glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT, display_buffer);
-
-#ifdef __BIG_ENDIAN__
-                               glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
-#endif
-                               glPixelZoom(1.0f, 1.0f);
+                               GPU_shader_unbind();
                        }
                        else if (snode->flag & SNODE_USE_ALPHA) {
                                glEnable(GL_BLEND);
-                               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-                               glPixelZoom(snode->zoom, snode->zoom);
+                               glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 
-                               glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+                               glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, snode->zoom, snode->zoom);
 
-                               glPixelZoom(1.0f, 1.0f);
                                glDisable(GL_BLEND);
                        }
                        else {
-                               glPixelZoom(snode->zoom, snode->zoom);
-
-                               glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
-
-                               glPixelZoom(1.0f, 1.0f);
+                               glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST, snode->zoom, snode->zoom);
                        }
 
                        if (cache_handle)
@@ -3346,30 +3237,33 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
                            viewer_border->ymin < viewer_border->ymax)
                        {
                                rcti pixel_border;
-                               UI_ThemeColor(TH_ACTIVE);
                                BLI_rcti_init(&pixel_border,
                                              x + snode->zoom * viewer_border->xmin * ibuf->x,
                                              x + snode->zoom * viewer_border->xmax * ibuf->x,
                                              y + snode->zoom * viewer_border->ymin * ibuf->y,
                                              y + snode->zoom * viewer_border->ymax * ibuf->y);
-                               glaDrawBorderCorners(&pixel_border, 1.0f, 1.0f);
+
+                               unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+                               immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+                               immUniformThemeColor(TH_ACTIVE);
+
+                               immDrawBorderCorners(pos, &pixel_border, 1.0f, 1.0f);
+
+                               immUnbindProgram();
                        }
                }
 
-               glMatrixMode(GL_PROJECTION);
-               glPopMatrix();
-               glMatrixMode(GL_MODELVIEW);
-               glPopMatrix();
+               gpuPopProjectionMatrix();
+               gpuPopMatrix();
        }
 
        BKE_image_release_ibuf(ima, ibuf, lock);
 }
 
-
-/* if v2d not NULL, it clips and returns 0 if not visible */
-bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
+/* return quadratic beziers points for a given nodelink and clip if v2d is not NULL. */
+static bool node_link_bezier_handles(View2D *v2d, SpaceNode *snode, bNodeLink *link, float vec[4][2])
 {
-       float dist, vec[4][2];
+       float dist;
        float deltax, deltay;
        float cursor[2] = {0.0f, 0.0f};
        int toreroute, fromreroute;
@@ -3437,13 +3331,23 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo
                vec[2][0] = vec[3][0] - dist;
                vec[2][1] = vec[3][1];
        }
+
        if (v2d && min_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax) {
-               /* clipped */
+               return 0; /* clipped */
        }
        else if (v2d && max_ffff(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < v2d->cur.xmin) {
-               /* clipped */
+               return 0; /* clipped */
        }
-       else {
+
+       return 1;
+}
+
+/* if v2d not NULL, it clips and returns 0 if not visible */
+bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
+{
+       float vec[4][2];
+
+       if (node_link_bezier_handles(v2d, snode, link, vec)) {
                /* always do all three, to prevent data hanging around */
                BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0],
                                              coord_array[0] + 0, resol, sizeof(float) * 2);
@@ -3455,186 +3359,242 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo
        return 0;
 }
 
+#define NODELINK_GROUP_SIZE 256
 #define LINK_RESOL  24
-#define LINK_ARROW  12  /* position of arrow on the link, LINK_RESOL/2 */
-#define ARROW_SIZE (7 * UI_DPI_FAC)
-void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
-                           int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3)
-{
-       float coord_array[LINK_RESOL + 1][2];
-
-       if (node_link_bezier_points(v2d, snode, link, coord_array, LINK_RESOL)) {
-               float dist, spline_step = 0.0f;
-               int i;
-               int drawarrow;
-               /* store current linewidth */
-               float linew;
-               float arrow[2], arrow1[2], arrow2[2];
-               glGetFloatv(GL_LINE_WIDTH, &linew);
+#define LINK_WIDTH  (2.5f * UI_DPI_FAC)
+#define ARROW_SIZE  (7 * UI_DPI_FAC)
+
+static float arrow_verts[3][2] = {{-1.0f, 1.0f}, {0.0f, 0.0f}, {-1.0f, -1.0f}};
+static float arrow_expand_axis[3][2] = {{0.7071f, 0.7071f}, {M_SQRT2, 0.0f}, {0.7071f, -0.7071f}};
+
+struct {
+       Gwn_Batch *batch; /* for batching line together */
+       Gwn_Batch *batch_single; /* for single line */
+       Gwn_VertBuf *inst_vbo;
+       unsigned int p0_id, p1_id, p2_id, p3_id;
+       unsigned int colid_id;
+       Gwn_VertBufRaw p0_step, p1_step, p2_step, p3_step;
+       Gwn_VertBufRaw colid_step;
+       unsigned int count;
+       bool enabled;
+} g_batch_link = {0};
+
+static void nodelink_batch_reset(void)
+{
+       GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p0_id, &g_batch_link.p0_step);
+       GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p1_id, &g_batch_link.p1_step);
+       GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p2_id, &g_batch_link.p2_step);
+       GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.p3_id, &g_batch_link.p3_step);
+       GWN_vertbuf_attr_get_raw_data(g_batch_link.inst_vbo, g_batch_link.colid_id, &g_batch_link.colid_step);
+       g_batch_link.count = 0;
+}
+
+static void set_nodelink_vertex(
+        Gwn_VertBuf *vbo,
+        unsigned int uv_id, unsigned int pos_id, unsigned int exp_id, unsigned int v,
+        const unsigned char uv[2], const float pos[2], const float exp[2])
+{
+       GWN_vertbuf_attr_set(vbo, uv_id, v, uv);
+       GWN_vertbuf_attr_set(vbo, pos_id, v, pos);
+       GWN_vertbuf_attr_set(vbo, exp_id, v, exp);
+}
+
+static void nodelink_batch_init(void)
+{
+       Gwn_VertFormat format = {0};
+       unsigned int uv_id = GWN_vertformat_attr_add(&format, "uv", GWN_COMP_U8, 2, GWN_FETCH_INT_TO_FLOAT_UNIT);
+       unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+       unsigned int expand_id = GWN_vertformat_attr_add(&format, "expand", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+       Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format_ex(&format, GWN_USAGE_STATIC);
+       int vcount = LINK_RESOL * 2; /* curve */
+       vcount += 2; /* restart strip */
+       vcount += 3 * 2; /* arrow */
+       vcount *= 2; /* shadow */
+       vcount += 2; /* restart strip */
+       GWN_vertbuf_data_alloc(vbo, vcount);
+       int v = 0;
+
+       for (int k = 0; k < 2; ++k) {
+               unsigned char uv[2] = {0, 0};
+               float pos[2] = {0.0f, 0.0f};
+               float exp[2] = {0.0f, 1.0f};
+
+               /* restart */
+               if (k == 1)
+                       set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+               /* curve strip */
+               for (int i = 0; i < LINK_RESOL; ++i) {
+                       uv[0] = 255 * (i / (float)(LINK_RESOL - 1));
+                       uv[1] = 0;
+                       set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+                       uv[1] = 255;
+                       set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+               }
+               /* restart */
+               set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+               uv[0] = 127;
+               uv[1] = 0;
+               copy_v2_v2(pos, arrow_verts[0]);
+               copy_v2_v2(exp, arrow_expand_axis[0]);
+               set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+               /* arrow */
+               for (int i = 0; i < 3; ++i) {
+                       uv[1] = 0;
+                       copy_v2_v2(pos, arrow_verts[i]);
+                       copy_v2_v2(exp, arrow_expand_axis[i]);
+                       set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+
+                       uv[1] = 255;
+                       set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+               }
 
-               /* we can reuse the dist variable here to increment the GL curve eval amount*/
-               dist = 1.0f / (float)LINK_RESOL;
+               /* restart */
+               if (k == 0)
+                       set_nodelink_vertex(vbo, uv_id, pos_id, expand_id, v++, uv, pos, exp);
+       }
 
-               glEnable(GL_LINE_SMOOTH);
+       g_batch_link.batch = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
+       gpu_batch_presets_register(g_batch_link.batch);
 
-               drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
-                            (link->fromnode && (link->fromnode->type == NODE_REROUTE)));
-
-               if (drawarrow) {
-                       /* draw arrow in line segment LINK_ARROW */
-                       float d_xy[2], len;
-
-                       sub_v2_v2v2(d_xy, coord_array[LINK_ARROW], coord_array[LINK_ARROW - 1]);
-                       len = len_v2(d_xy);
-                       mul_v2_fl(d_xy, ARROW_SIZE / len);
-                       arrow1[0] = coord_array[LINK_ARROW][0] - d_xy[0] + d_xy[1];
-                       arrow1[1] = coord_array[LINK_ARROW][1] - d_xy[1] - d_xy[0];
-                       arrow2[0] = coord_array[LINK_ARROW][0] - d_xy[0] - d_xy[1];
-                       arrow2[1] = coord_array[LINK_ARROW][1] - d_xy[1] + d_xy[0];
-                       arrow[0] = coord_array[LINK_ARROW][0];
-                       arrow[1] = coord_array[LINK_ARROW][1];
-               }
-               if (do_triple) {
-                       UI_ThemeColorShadeAlpha(th_col3, -80, -120);
-                       glLineWidth(4.0f);
+       g_batch_link.batch_single = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, 0);
+       gpu_batch_presets_register(g_batch_link.batch_single);
 
-                       glBegin(GL_LINE_STRIP);
-                       for (i = 0; i <= LINK_RESOL; i++) {
-                               glVertex2fv(coord_array[i]);
-                       }
-                       glEnd();
-                       if (drawarrow) {
-                               glBegin(GL_LINE_STRIP);
-                               glVertex2fv(arrow1);
-                               glVertex2fv(arrow);
-                               glVertex2fv(arrow2);
-                               glEnd();
-                       }
-               }
+       /* Instances data */
+       Gwn_VertFormat format_inst = {0};
+       g_batch_link.p0_id = GWN_vertformat_attr_add(&format_inst, "P0", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+       g_batch_link.p1_id = GWN_vertformat_attr_add(&format_inst, "P1", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+       g_batch_link.p2_id = GWN_vertformat_attr_add(&format_inst, "P2", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+       g_batch_link.p3_id = GWN_vertformat_attr_add(&format_inst, "P3", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+       g_batch_link.colid_id = GWN_vertformat_attr_add(&format_inst, "colid_doarrow", GWN_COMP_U8, 4, GWN_FETCH_INT);
+       g_batch_link.inst_vbo = GWN_vertbuf_create_with_format_ex(&format_inst, GWN_USAGE_STREAM);
+       GWN_vertbuf_data_alloc(g_batch_link.inst_vbo, NODELINK_GROUP_SIZE); /* Alloc max count but only draw the range we need. */
 
-               /* XXX using GL_LINES for shaded node lines is a workaround
-                * for Intel hardware, this breaks with GL_LINE_STRIP and
-                * changing color in begin/end blocks.
-                */
-               glLineWidth(1.5f);
-               if (do_shaded) {
-                       glBegin(GL_LINES);
-                       for (i = 0; i < LINK_RESOL; i++) {
-                               UI_ThemeColorBlend(th_col1, th_col2, spline_step);
-                               glVertex2fv(coord_array[i]);
-
-                               UI_ThemeColorBlend(th_col1, th_col2, spline_step + dist);
-                               glVertex2fv(coord_array[i + 1]);
-
-                               spline_step += dist;
-                       }
-                       glEnd();
-               }
-               else {
-                       UI_ThemeColor(th_col1);
-                       glBegin(GL_LINE_STRIP);
-                       for (i = 0; i <= LINK_RESOL; i++) {
-                               glVertex2fv(coord_array[i]);
-                       }
-                       glEnd();
-               }
+       GWN_batch_instbuf_set(g_batch_link.batch, g_batch_link.inst_vbo, true);
 
-               if (drawarrow) {
-                       glBegin(GL_LINE_STRIP);
-                       glVertex2fv(arrow1);
-                       glVertex2fv(arrow);
-                       glVertex2fv(arrow2);
-                       glEnd();
-               }
+       nodelink_batch_reset();
+}
 
-               glDisable(GL_LINE_SMOOTH);
+static char nodelink_get_color_id(int th_col)
+{
+       switch (th_col) {
+               case TH_WIRE:        return 1;
+               case TH_WIRE_INNER:  return 2;
+               case TH_ACTIVE:      return 3;
+               case TH_EDGE_SELECT: return 4;
+               case TH_REDALERT:    return 5;
        }
+       return 0;
 }
 
-#if 0 /* not used in 2.5x yet */
-static void node_link_straight_points(View2D *UNUSED(v2d), SpaceNode *snode, bNodeLink *link, float coord_array[][2])
+static void nodelink_batch_draw(SpaceNode *snode)
 {
-       if (link->fromsock) {
-               coord_array[0][0] = link->fromsock->locx;
-               coord_array[0][1] = link->fromsock->locy;
-       }
-       else {
-               if (snode == NULL) return;
-               coord_array[0][0] = snode->mx;
-               coord_array[0][1] = snode->my;
-       }
-       if (link->tosock) {
-               coord_array[1][0] = link->tosock->locx;
-               coord_array[1][1] = link->tosock->locy;
-       }
-       else {
-               if (snode == NULL) return;
-               coord_array[1][0] = snode->mx;
-               coord_array[1][1] = snode->my;
-       }
+       if (g_batch_link.count == 0)
+               return;
+
+       glEnable(GL_BLEND);
+
+       float colors[6][4] = {{0.0f}};
+       UI_GetThemeColor4fv(TH_WIRE_INNER,  colors[nodelink_get_color_id(TH_WIRE_INNER)]);
+       UI_GetThemeColor4fv(TH_WIRE,        colors[nodelink_get_color_id(TH_WIRE)]);
+       UI_GetThemeColor4fv(TH_ACTIVE,      colors[nodelink_get_color_id(TH_ACTIVE)]);
+       UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
+       UI_GetThemeColor4fv(TH_REDALERT,    colors[nodelink_get_color_id(TH_REDALERT)]);
+
+       GWN_vertbuf_vertex_count_set(g_batch_link.inst_vbo, g_batch_link.count);
+       GWN_vertbuf_use(g_batch_link.inst_vbo); /* force update. */
+
+       GWN_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST);
+       GWN_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, (float *)colors);
+       GWN_batch_uniform_1f(g_batch_link.batch, "expandSize", snode->aspect * LINK_WIDTH);
+       GWN_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE);
+       GWN_batch_draw(g_batch_link.batch);
+
+       nodelink_batch_reset();
+
+       glDisable(GL_BLEND);
 }
 
-void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link,
-                             int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3)
+void nodelink_batch_start(SpaceNode *UNUSED(snode))
 {
-       float coord_array[2][2];
-       int i;
+       g_batch_link.enabled = true;
+}
 
-       node_link_straight_points(v2d, snode, link, coord_array);
+void nodelink_batch_end(SpaceNode *snode)
+{
+       nodelink_batch_draw(snode);
+       g_batch_link.enabled = false;
+}
 
-       glEnable(GL_LINE_SMOOTH);
+static void nodelink_batch_add_link(
+        SpaceNode *snode,
+        const float p0[2], const float p1[2], const float p2[2], const float p3[2],
+        int th_col1, int th_col2, int th_col3, bool drawarrow)
+{
+       /* Only allow these colors. If more is needed, you need to modify the shader accordingly. */
+       BLI_assert(ELEM(th_col1, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
+       BLI_assert(ELEM(th_col2, TH_WIRE_INNER, TH_WIRE, TH_ACTIVE, TH_EDGE_SELECT, TH_REDALERT));
+       BLI_assert(ELEM(th_col3, TH_WIRE, -1));
 
-       if (do_triple) {
-               UI_ThemeColorShadeAlpha(th_col3, -80, -120);
-               glLineWidth(4.0f);
+       g_batch_link.count++;
+       copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p0_step), p0);
+       copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p1_step), p1);
+       copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p2_step), p2);
+       copy_v2_v2(GWN_vertbuf_raw_step(&g_batch_link.p3_step), p3);
+       char *colid = GWN_vertbuf_raw_step(&g_batch_link.colid_step);
+       colid[0] = nodelink_get_color_id(th_col1);
+       colid[1] = nodelink_get_color_id(th_col2);
+       colid[2] = nodelink_get_color_id(th_col3);
+       colid[3] = drawarrow;
 
-               glBegin(GL_LINES);
-               glVertex2fv(coord_array[0]);
-               glVertex2fv(coord_array[1]);
-               glEnd();
+       if (g_batch_link.count == NODELINK_GROUP_SIZE) {
+               nodelink_batch_draw(snode);
        }
+}
 
-       UI_ThemeColor(th_col1);
-       glLineWidth(1.5f);
+/* don't do shadows if th_col3 is -1. */
+void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
+                           int th_col1, int th_col2, int th_col3)
+{
+       float vec[4][2];
 
-       /* XXX using GL_LINES for shaded node lines is a workaround
-        * for Intel hardware, this breaks with GL_LINE_STRIP and
-        * changing color in begin/end blocks.
-        */
-       if (do_shaded) {
-               glBegin(GL_LINES);
-               for (i = 0; i < LINK_RESOL - 1; ++i) {
-                       float t = (float)i / (float)(LINK_RESOL - 1);
-                       UI_ThemeColorBlend(th_col1, th_col2, t);
-                       glVertex2f((1.0f - t) * coord_array[0][0] + t * coord_array[1][0],
-                                  (1.0f - t) * coord_array[0][1] + t * coord_array[1][1]);
-
-                       t = (float)(i + 1) / (float)(LINK_RESOL - 1);
-                       UI_ThemeColorBlend(th_col1, th_col2, t);
-                       glVertex2f((1.0f - t) * coord_array[0][0] + t * coord_array[1][0],
-                                  (1.0f - t) * coord_array[0][1] + t * coord_array[1][1]);
+       if (node_link_bezier_handles(v2d, snode, link, vec)) {
+               int drawarrow = ((link->tonode && (link->tonode->type == NODE_REROUTE)) &&
+                                (link->fromnode && (link->fromnode->type == NODE_REROUTE)));
+
+               if (g_batch_link.batch == NULL) {
+                       nodelink_batch_init();
                }
-               glEnd();
-       }
-       else {
-               glBegin(GL_LINE_STRIP);
-               for (i = 0; i < LINK_RESOL; ++i) {
-                       float t = (float)i / (float)(LINK_RESOL - 1);
-                       glVertex2f((1.0f - t) * coord_array[0][0] + t * coord_array[1][0],
-                                  (1.0f - t) * coord_array[0][1] + t * coord_array[1][1]);
+
+               if (g_batch_link.enabled) {
+                       /* Add link to batch. */
+                       nodelink_batch_add_link(snode, vec[0], vec[1], vec[2], vec[3], th_col1, th_col2, th_col3, drawarrow);
+               }
+               else {
+                       /* Draw single link. */
+                       float colors[3][4] = {{0.0f}};
+                       if (th_col3 != -1) {
+                               UI_GetThemeColor4fv(th_col3, colors[0]);
+                       }
+                       UI_GetThemeColor4fv(th_col1, colors[1]);
+                       UI_GetThemeColor4fv(th_col2, colors[2]);
+
+                       Gwn_Batch *batch = g_batch_link.batch_single;
+                       GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK);
+                       GWN_batch_uniform_2fv_array(batch, "bezierPts", 4, (float *)vec);
+                       GWN_batch_uniform_4fv_array(batch, "colors", 3, (float *)colors);
+                       GWN_batch_uniform_1f(batch, "expandSize", snode->aspect * LINK_WIDTH);
+                       GWN_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE);
+                       GWN_batch_uniform_1i(batch, "doArrow", drawarrow);
+                       GWN_batch_draw(batch);
                }
-               glEnd();
        }
-
-       glDisable(GL_LINE_SMOOTH);
 }
-#endif
 
 /* note; this is used for fake links in groups too */
 void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
 {
-       bool do_shaded = false;
-       bool do_triple = false;
        int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE;
 
        if (link->fromsock == NULL && link->tosock == NULL)
@@ -3642,8 +3602,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
 
        /* new connection */
        if (!link->fromsock || !link->tosock) {
-               th_col1 = TH_ACTIVE;
-               do_triple = true;
+               th_col1 = th_col2 = TH_ACTIVE;
        }
        else {
                /* going to give issues once... */
@@ -3664,39 +3623,38 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
                                if (link->tonode && link->tonode->flag & SELECT)
                                        th_col2 = TH_EDGE_SELECT;
                        }
-                       do_shaded = true;
-                       do_triple = true;
                }
                else {
-                       th_col1 = TH_REDALERT;
+                       th_col1 = th_col2 = TH_REDALERT;
+                       // th_col3 = -1; /* no shadow */
                }
        }
 
-       node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
+       node_draw_link_bezier(v2d, snode, link, th_col1, th_col2, th_col3);
 //     node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
 }
 
-void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border)
+void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned pos)
 {
-       glBegin(GL_LINES);
+       immBegin(GWN_PRIM_LINES, 4);
 
        if (border & (NODE_LEFT | NODE_RIGHT)) {
-               glVertex2f(cent[0], v2d->cur.ymin);
-               glVertex2f(cent[0], v2d->cur.ymax);
+               immVertex2f(pos, cent[0], v2d->cur.ymin);
+               immVertex2f(pos, cent[0], v2d->cur.ymax);
        }
        else {
-               glVertex2f(cent[0], cent[1] - size);
-               glVertex2f(cent[0], cent[1] + size);
+               immVertex2f(pos, cent[0], cent[1] - size);
+               immVertex2f(pos, cent[0], cent[1] + size);
        }
 
        if (border & (NODE_TOP | NODE_BOTTOM)) {
-               glVertex2f(v2d->cur.xmin, cent[1]);
-               glVertex2f(v2d->cur.xmax, cent[1]);
+               immVertex2f(pos, v2d->cur.xmin, cent[1]);
+               immVertex2f(pos, v2d->cur.xmax, cent[1]);
        }
        else {
-               glVertex2f(cent[0] - size, cent[1]);
-               glVertex2f(cent[0] + size, cent[1]);
+               immVertex2f(pos, cent[0] - size, cent[1]);
+               immVertex2f(pos, cent[0] + size, cent[1]);
        }
 
-       glEnd();
+       immEnd();
 }