diff options
Diffstat (limited to 'source/blender/editors/space_node/drawnode.c')
-rw-r--r-- | source/blender/editors/space_node/drawnode.c | 740 |
1 files changed, 349 insertions, 391 deletions
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index fff6c5d9f2c..a162a863038 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -50,9 +50,13 @@ #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); @@ -1179,13 +1091,6 @@ static void node_shader_buts_ambient_occlusion(uiLayout *layout, bContext *UNUSE 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; @@ -1219,12 +1124,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; @@ -1373,7 +1272,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; @@ -2271,14 +2170,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(); } } @@ -2297,9 +2203,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; @@ -2312,12 +2215,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) @@ -2335,9 +2247,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; @@ -2350,13 +2259,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) @@ -2556,7 +2473,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; @@ -3246,6 +3163,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; @@ -3261,14 +3179,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; @@ -3278,60 +3192,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) @@ -3356,30 +3247,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; @@ -3447,13 +3341,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); @@ -3465,186 +3369,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) @@ -3652,8 +3612,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... */ @@ -3674,39 +3633,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(); } |