Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Wed, 5 Jul 2017 07:20:48 +0000 (09:20 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Wed, 5 Jul 2017 07:20:48 +0000 (09:20 +0200)
Conflicts:
source/blender/editors/space_view3d/drawobject.c

1  2 
source/blender/editors/space_view3d/drawobject.c

index 8b1f44557e4229e4698e017d7b6a7cdadce471cf,3f11703973dda1a6f01cdce7cd9f3ac51f7c6151..799fb6d501886b6dc327e3118c7bec634a46c3bb
@@@ -62,7 -62,6 +62,7 @@@
  #include "BKE_global.h"
  #include "BKE_image.h"
  #include "BKE_key.h"
 +#include "BKE_layer.h"
  #include "BKE_lattice.h"
  #include "BKE_main.h"
  #include "BKE_mesh.h"
  #include "GPU_select.h"
  #include "GPU_basic_shader.h"
  #include "GPU_shader.h"
 +#include "GPU_immediate.h"
 +#include "GPU_immediate_util.h"
 +#include "GPU_batch.h"
 +#include "GPU_matrix.h"
  
  #include "ED_mesh.h"
  #include "ED_particle.h"
  
  #include "view3d_intern.h"  /* bad level include */
  
 +#include "../../draw/intern/draw_cache_impl.h"  /* bad level include (temporary) */
 +
 +/* prototypes */
 +static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos);
 +
  /* Workaround for sequencer scene render mode.
   *
   * Strips doesn't use DAG to update objects or so, which
@@@ -139,7 -129,6 +139,7 @@@ typedef struct drawDMVerts_userData 
  
        BMVert *eve_act;
        char sel;
 +      unsigned int pos, color;
  
        /* cached theme values */
        unsigned char th_editmesh_active[4];
@@@ -192,7 -181,6 +192,7 @@@ typedef struct drawDMFacesSel_userData 
  } drawDMFacesSel_userData;
  
  typedef struct drawDMNormal_userData {
 +      unsigned int pos;
        BMesh *bm;
        int uniform_scale;
        float normalsize;
  } drawDMNormal_userData;
  
  typedef struct drawMVertOffset_userData {
 +      unsigned int pos, col;
        MVert *mvert;
        int offset;
  } drawMVertOffset_userData;
  typedef struct drawDMLayer_userData {
        BMesh *bm;
        int cd_layer_offset;
 +      unsigned int pos, col;
  } drawDMLayer_userData;
  
  typedef struct drawBMOffset_userData {
 +      unsigned int pos, col;
        BMesh *bm;
        int offset;
  } drawBMOffset_userData;
  typedef struct drawBMSelect_userData {
        BMesh *bm;
        bool select;
 +      unsigned int pos;
  } drawBMSelect_userData;
  
 -static void draw_bounding_volume(Object *ob, char type);
  
 -static void drawcube_size(float size);
 -static void drawcircle_size(float size);
 -static void draw_empty_sphere(float size);
 -static void draw_empty_cone(float size);
 -static void draw_box(const float vec[8][3], bool solid);
 +static void drawcube_size(float size, unsigned pos);
 +static void drawcircle_size(float size, unsigned pos);
 +static void draw_empty_sphere(float size, unsigned pos);
 +static void draw_empty_cone(float size, unsigned pos);
  
 -static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
 +static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac, float r_col[3])
  {
 -      float col_wire[3], col_bg[3], col[3];
 +      float col_wire[3], col_bg[3];
  
        rgb_uchar_to_float(col_wire, ob_wire_col);
  
        UI_GetThemeColor3fv(theme_id, col_bg);
 -      interp_v3_v3v3(col, col_bg, col_wire, fac);
 -      glColor3fv(col);
 +      interp_v3_v3v3(r_col, col_bg, col_wire, fac);
  }
  
  int view3d_effective_drawtype(const struct View3D *v3d)
@@@ -309,13 -296,13 +309,13 @@@ static bool check_ob_drawface_dot(Scen
  
  /* check for glsl drawing */
  
 -bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
 +bool draw_glsl_material(Scene *scene, SceneLayer *sl, Object *ob, View3D *v3d, const char dt)
  {
        if (G.f & G_PICKSEL)
                return false;
        if (!check_object_draw_texture(scene, v3d, dt))
                return false;
 -      if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
 +      if (ob == OBACT_NEW && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
                return false;
        
        if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
  
  static bool check_alpha_pass(Base *base)
  {
 -      if (base->flag & OB_FROMDUPLI)
 +      if (base->flag_legacy & OB_FROMDUPLI)
                return false;
  
        if (G.f & G_PICKSEL)
@@@ -427,9 -414,9 +427,9 @@@ static const float cosval[CIRCLE_RESOL
   * \param viewmat_local_unit is typically the 'rv3d->viewmatob'
   * copied into a 3x3 matrix and normalized.
   */
 -static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis)
 +static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis, unsigned pos)
  {
 -      int line_type;
 +      Gwn_PrimType line_type = GWN_PRIM_LINES;
        float buffer[4][3];
        int n = 0;
  
  
        switch (axis) {
                case 0:     /* x axis */
 -                      line_type = GL_LINES;
 -
                        /* bottom left to top right */
                        negate_v3_v3(v1, dx);
                        sub_v3_v3(v1, dy);
  
                        break;
                case 1:     /* y axis */
 -                      line_type = GL_LINES;
 -                      
                        /* bottom left to top right */
                        mul_v3_fl(dx, 0.75f);
                        negate_v3_v3(v1, dx);
                        
                        break;
                case 2:     /* z axis */
 -                      line_type = GL_LINE_STRIP;
 +                      line_type = GWN_PRIM_LINE_STRIP;
                        
                        /* start at top left */
                        negate_v3_v3(v1, dx);
                        return;
        }
  
 +      immBegin(line_type, n);
        for (int i = 0; i < n; i++) {
                mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
                add_v3_v3(buffer[i], c);
 +              immVertex3fv(pos, buffer[i]);
        }
 +      immEnd();
  
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, buffer);
 -      glDrawArrays(line_type, 0, n);
 -      glDisableClientState(GL_VERTEX_ARRAY);
 +      /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */
  }
  
 -void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
 +void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4])
  {
        int axis;
        float v1[3] = {0.0, 0.0, 0.0};
        float v2[3] = {0.0, 0.0, 0.0};
        float v3[3] = {0.0, 0.0, 0.0};
  
 -      glLineWidth(1);
 +      glLineWidth(1.0f);
 +
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (color) {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformColor4ubv(color);
 +      }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
 +      }
  
        switch (drawtype) {
 -
                case OB_PLAINAXES:
 +                      immBegin(GWN_PRIM_LINES, 6);
                        for (axis = 0; axis < 3; axis++) {
 -                              glBegin(GL_LINES);
 -
                                v1[axis] = size;
                                v2[axis] = -size;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
  
                                /* reset v1 & v2 to zero */
                                v1[axis] = v2[axis] = 0.0f;
 -
 -                              glEnd();
                        }
 +                      immEnd();
                        break;
 -              case OB_SINGLE_ARROW:
  
 -                      glBegin(GL_LINES);
 +              case OB_SINGLE_ARROW:
 +                      immBegin(GWN_PRIM_LINES, 2);
                        /* in positive z direction only */
                        v1[2] = size;
 -                      glVertex3fv(v1);
 -                      glVertex3fv(v2);
 -                      glEnd();
 +                      immVertex3fv(pos, v1);
 +                      immVertex3fv(pos, v2);
 +                      immEnd();
  
                        /* square pyramid */
 -                      glBegin(GL_TRIANGLES);
 +                      immBegin(GWN_PRIM_TRIS, 12);
  
                        v2[0] = size * 0.035f; v2[1] = size * 0.035f;
                        v3[0] = size * -0.035f; v3[1] = size * 0.035f;
                                        v3[0] = -v3[0];
                                }
  
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 -                              glVertex3fv(v3);
 -
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
 +                              immVertex3fv(pos, v3);
                        }
 -                      glEnd();
 -
 +                      immEnd();
                        break;
 +
                case OB_CUBE:
 -                      drawcube_size(size);
 +                      drawcube_size(size, pos);
                        break;
  
                case OB_CIRCLE:
 -                      drawcircle_size(size);
 +                      drawcircle_size(size, pos);
                        break;
  
                case OB_EMPTY_SPHERE:
 -                      draw_empty_sphere(size);
 +                      draw_empty_sphere(size, pos);
                        break;
  
                case OB_EMPTY_CONE:
 -                      draw_empty_cone(size);
 +                      draw_empty_cone(size, pos);
                        break;
  
                case OB_ARROWS:
                        for (axis = 0; axis < 3; axis++) {
                                const int arrow_axis = (axis == 0) ? 1 : 0;
  
 -                              glBegin(GL_LINES);
 +                              immBegin(GWN_PRIM_LINES, 6);
  
                                v2[axis] = size;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 -                              
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
 +
                                v1[axis] = size * 0.85f;
                                v1[arrow_axis] = -size * 0.08f;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 -                              
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
 +
                                v1[arrow_axis] = size * 0.08f;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
  
 -                              glEnd();
 -                              
 -                              v2[axis] += size * 0.125f;
 +                              immEnd();
  
 -                              draw_xyz_wire(viewmat_local_unit, v2, size, axis);
 +                              v2[axis] += size * 0.125f;
  
 +                              draw_xyz_wire(viewmat_local_unit, v2, size, axis, pos);
  
                                /* reset v1 & v2 to zero */
                                v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
                        }
 -                      break;
                }
        }
 +
 +      immUnbindProgram();
  }
  
  
  static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview)
  {
        Image *ima = ob->data;
 -      ImBuf *ibuf;
 -      ImageUser iuser = *ob->iuser;
  
 -      /* Support multi-view */
 -      if (ima && (sview == STEREO_RIGHT_ID)) {
 -              iuser.multiview_eye = sview;
 -              iuser.flag |= IMA_SHOW_STEREO;
 -              BKE_image_multiview_index(ima, &iuser);
 -      }
 +      const float ob_alpha = ob->col[3];
 +      float ima_x, ima_y;
  
 -      ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
 +      int bindcode = 0;
  
 -      if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
 -              IMB_rect_from_float(ibuf);
 -      }
 +      if (ima) {
 +              ImageUser iuser = *ob->iuser;
  
 -      int ima_x, ima_y;
 +              /* Support multi-view */
 +              if (ima && (sview == STEREO_RIGHT_ID)) {
 +                      iuser.multiview_eye = sview;
 +                      iuser.flag |= IMA_SHOW_STEREO;
 +                      BKE_image_multiview_index(ima, &iuser);
 +              }
 +
 +              if (ob_alpha > 0.0f) {
 +                      bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false);
 +                      /* don't bother drawing the image if alpha = 0 */
 +              }
  
 -      /* Get the buffer dimensions so we can fallback to fake ones */
 -      if (ibuf && ibuf->rect) {
 -              ima_x = ibuf->x;
 -              ima_y = ibuf->y;
 +              int w, h;
 +              BKE_image_get_size(ima, &iuser, &w, &h);
 +              ima_x = w;
 +              ima_y = h;
        }
        else {
 -              ima_x = 1;
 -              ima_y = 1;
 +              /* if no image, make it a 1x1 empty square, honor scale & offset */
 +              ima_x = ima_y = 1.0f;
        }
  
 -      float sca_x = 1.0f;
 -      float sca_y = 1.0f;
 -
        /* Get the image aspect even if the buffer is invalid */
 +      float sca_x = 1.0f, sca_y = 1.0f;
        if (ima) {
                if (ima->aspx > ima->aspy) {
                        sca_y = ima->aspy / ima->aspx;
                }
        }
  
 -      /* Calculate the scale center based on object's origin */
 -      float ofs_x = ob->ima_ofs[0] * ima_x;
 -      float ofs_y = ob->ima_ofs[1] * ima_y;
 +      float scale_x;
 +      float scale_y;
 +      {
 +              const float scale_x_inv = ima_x * sca_x;
 +              const float scale_y_inv = ima_y * sca_y;
 +              if (scale_x_inv > scale_y_inv) {
 +                      scale_x = ob->empty_drawsize;
 +                      scale_y = ob->empty_drawsize * (scale_y_inv / scale_x_inv);
 +              }
 +              else {
 +                      scale_x = ob->empty_drawsize * (scale_x_inv / scale_y_inv);
 +                      scale_y = ob->empty_drawsize;
 +              }
 +      }
  
 -      glMatrixMode(GL_MODELVIEW);
 -      glPushMatrix();
 +      const float ofs_x = ob->ima_ofs[0] * scale_x;
 +      const float ofs_y = ob->ima_ofs[1] * scale_y;
  
 -      /* Calculate Image scale */
 -      float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
 +      const rctf rect = {
 +              .xmin = ofs_x,
 +              .xmax = ofs_x + scale_x,
 +              .ymin = ofs_y,
 +              .ymax = ofs_y + scale_y,
 +      };
  
 -      /* Set the object scale */
 -      glScalef(scale * sca_x, scale * sca_y, 1.0f);
 +      bool use_blend = false;
  
 -      if (ibuf && ibuf->rect) {
 -              const bool use_clip = (U.glalphaclip != 1.0f);
 -              int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP) ? GL_NEAREST : GL_LINEAR;
 -              /* Setup GL params */
 -              glEnable(GL_BLEND);
 -              glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +      if (bindcode) {
 +              use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima);
  
 -              if (use_clip) {
 -                      glEnable(GL_ALPHA_TEST);
 -                      glAlphaFunc(GL_GREATER, U.glalphaclip);
 +              if (use_blend) {
 +                      glEnable(GL_BLEND);
 +                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                }
  
 -              /* Use the object color and alpha */
 -              glColor4fv(ob->col);
 +              Gwn_VertFormat *format = immVertexFormat();
 +              unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +              unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
 +              immUniform1f("alpha", ob_alpha);
 +              immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
  
 -              /* Draw the Image on the screen */
 -              glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
 +              immBegin(GWN_PRIM_TRI_FAN, 4);
 +              immAttrib2f(texCoord, 0.0f, 0.0f);
 +              immVertex2f(pos, rect.xmin, rect.ymin);
  
 -              glDisable(GL_BLEND);
 +              immAttrib2f(texCoord, 1.0f, 0.0f);
 +              immVertex2f(pos, rect.xmax, rect.ymin);
  
 -              if (use_clip) {
 -                      glDisable(GL_ALPHA_TEST);
 -                      glAlphaFunc(GL_ALWAYS, 0.0f);
 -              }
 +              immAttrib2f(texCoord, 1.0f, 1.0f);
 +              immVertex2f(pos, rect.xmax, rect.ymax);
 +
 +              immAttrib2f(texCoord, 0.0f, 1.0f);
 +              immVertex2f(pos, rect.xmin, rect.ymax);
 +              immEnd();
 +
 +              immUnbindProgram();
 +
 +              glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */
        }
  
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              glColor3ubv(ob_wire_col);
 +      /* Draw the image outline */
 +      glLineWidth(1.5f);
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +
 +      const bool picking = dflag & DRAW_CONSTCOLOR;
 +      if (picking) {
 +              /* TODO: deal with picking separately, use this function just to draw */
 +              immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
 +              if (use_blend) {
 +                      glDisable(GL_BLEND);
 +              }
 +
 +              imm_draw_line_box(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
        }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformColor3ubv(ob_wire_col);
 +              glEnable(GL_LINE_SMOOTH);
  
 -      /* Calculate the outline vertex positions */
 -      glBegin(GL_LINE_LOOP);
 -      glVertex2f(ofs_x, ofs_y);
 -      glVertex2f(ofs_x + ima_x, ofs_y);
 -      glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
 -      glVertex2f(ofs_x, ofs_y + ima_y);
 -      glEnd();
 +              if (!use_blend) {
 +                      glEnable(GL_BLEND);
 +                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +              }
  
 -      /* Reset GL settings */
 -      glPopMatrix();
 +              imm_draw_line_box(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 +
 +              glDisable(GL_LINE_SMOOTH);
 +              glDisable(GL_BLEND);
 +      }
  
 -      BKE_image_release_ibuf(ima, ibuf, NULL);
 +      immUnbindProgram();
  }
  
  static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
        }
  }
  
 -void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4])
 +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos)
  {
        float verts[CIRCLE_RESOL][3];
  
        circball_array_fill(verts, cent, rad, tmat);
  
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, verts);
 -      glDrawArrays(mode, 0, CIRCLE_RESOL);
 -      glDisableClientState(GL_VERTEX_ARRAY);
 +      immBegin(GWN_PRIM_LINE_LOOP, CIRCLE_RESOL);
 +      for (int i = 0; i < CIRCLE_RESOL; ++i) {
 +              immVertex3fv(pos, verts[i]);
 +      }
 +      immEnd();
  }
  
  /* circle for object centers, special_color is for library or ob users */
 -static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color)
 +static void drawcentercircle(View3D *v3d, RegionView3D *UNUSED(rv3d), const float co[3], int selstate, bool special_color)
  {
 -      const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
 -      float verts[CIRCLE_RESOL][3];
 +      const float outlineWidth = 1.0f * U.pixelsize;
 +      const float size = U.obcenter_dia * U.pixelsize + outlineWidth;
 +
 +      if (v3d->zbuf) {
 +              glDisable(GL_DEPTH_TEST);
 +              /* TODO(merwin): fit things like this into plates/buffers design */
 +      }
  
 -      /* using glDepthFunc guarantees that it does write z values,
 -       * but not checks for it, so centers remain visible independent of draw order */
 -      if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
 -      /* write to near buffer always */
 -      glDepthRange(0.0, 0.0);
        glEnable(GL_BLEND);
 -      
 +      GPU_enable_program_point_size();
 +
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
 +      immUniform1f("size", size);
 +
        if (special_color) {
 -              if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
 -              else glColor4ub(0x55, 0xCC, 0xCC, 155);
 +              if (selstate == ACTIVE || selstate == SELECT) immUniformColor4ub(0x88, 0xFF, 0xFF, 155);
 +              else immUniformColor4ub(0x55, 0xCC, 0xCC, 155);
        }
        else {
 -              if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
 -              else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
 -              else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
 +              if (selstate == ACTIVE) immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
 +              else if (selstate == SELECT) immUniformThemeColorShadeAlpha(TH_SELECT, 0, -80);
 +              else if (selstate == DESELECT) immUniformThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
        }
  
 -      circball_array_fill(verts, co, size, rv3d->viewinv);
 -
 -      /* enable vertex array */
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, verts);
 -
 -      /* 1. draw filled, blended polygon */
 -      glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
 +      /* set up outline */
 +      float outlineColor[4];
 +      UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor);
 +      immUniform4fv("outlineColor", outlineColor);
 +      immUniform1f("outlineWidth", outlineWidth);
  
 -      /* 2. draw outline */
 -      glLineWidth(1);
 -      UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
 -      glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
 +      immBegin(GWN_PRIM_POINTS, 1);
 +      immVertex3fv(pos, co);
 +      immEnd();
  
 -      /* finish up */
 -      glDisableClientState(GL_VERTEX_ARRAY);
 +      immUnbindProgram();
  
 -      glDepthRange(0.0, 1.0);
 +      GPU_disable_program_point_size();
        glDisable(GL_BLEND);
  
 -      if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
 +      if (v3d->zbuf) {
 +              glEnable(GL_DEPTH_TEST);
 +      }
  }
  
  /* *********** text drawing for object/particles/armature ************* */
@@@ -948,30 -893,36 +948,30 @@@ void view3d_cached_text_draw_end(View3
        if (tot) {
                int col_pack_prev = 0;
  
 -#if 0
 -              bglMats mats; /* ZBuffer depth vars */
 -              double ux, uy, uz;
 -              float depth;
 -
 -              if (v3d->zbuf)
 -                      bgl_get_mats(&mats);
 -#endif
                if (rv3d->rflag & RV3D_CLIPPING) {
                        ED_view3d_clipping_disable();
                }
  
 -              glMatrixMode(GL_PROJECTION);
 -              glPushMatrix();
 -              glMatrixMode(GL_MODELVIEW);
 -              glPushMatrix();
 +              float original_proj[4][4];
 +              gpuGetProjectionMatrix(original_proj);
                wmOrtho2_region_pixelspace(ar);
 -              glLoadIdentity();
 +
 +              gpuPushMatrix();
 +              gpuLoadIdentity();
                
                if (depth_write) {
                        if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
                }
                else {
 -                      glDepthMask(0);
 +                      glDepthMask(GL_FALSE);
                }
                
 +              const int font_id = BLF_default();
 +
                for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
                        if (vos->sco[0] != IS_CLIPPED) {
                                if (col_pack_prev != vos->col.pack) {
 -                                      glColor3ubv(vos->col.ub);
 +                                      BLF_color3ubv(font_id, vos->col.ub);
                                        col_pack_prev = vos->col.pack;
                                }
  
                        if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
                }
                else {
 -                      glDepthMask(1);
 +                      glDepthMask(GL_TRUE);
                }
                
 -              glMatrixMode(GL_PROJECTION);
 -              glPopMatrix();
 -              glMatrixMode(GL_MODELVIEW);
 -              glPopMatrix();
 +              gpuPopMatrix();
 +              gpuLoadProjectionMatrix(original_proj);
  
                if (rv3d->rflag & RV3D_CLIPPING) {
                        ED_view3d_clipping_enable();
  /* draws a cube given the scaling of the cube, assuming that
   * all required matrices have been set (used for drawing empties)
   */
 -static void drawcube_size(float size)
 +static void drawcube_size(float size, unsigned pos)
  {
 -      const GLfloat pos[8][3] = {
 +      const float verts[8][3] = {
                {-size, -size, -size},
                {-size, -size,  size},
                {-size,  size, -size},
  
        const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6};
  
 +#if 0
        glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, pos);
 +      glVertexPointer(3, GL_FLOAT, 0, verts);
        glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
        glDisableClientState(GL_VERTEX_ARRAY);
 +#else
 +      immBegin(GWN_PRIM_LINES, 24);
 +      for (int i = 0; i < 24; ++i) {
 +              immVertex3fv(pos, verts[indices[i]]);
 +      }
 +      immEnd();
 +#endif
  }
  
 -static void drawshadbuflimits(Lamp *la, float mat[4][4])
 +static void drawshadbuflimits(const Lamp *la, const float mat[4][4], unsigned pos)
  {
        float sta[3], end[3], lavec[3];
  
        madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
        madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
  
 -      glBegin(GL_LINES);
 -      glVertex3fv(sta);
 -      glVertex3fv(end);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 2);
 +      immVertex3fv(pos, sta);
 +      immVertex3fv(pos, end);
 +      immEnd();
  
 -      glPointSize(3.0);
 -      glBegin(GL_POINTS);
 -      glVertex3fv(sta);
 -      glVertex3fv(end);
 -      glEnd();
 +      glPointSize(3.0f);
 +      immBegin(GWN_PRIM_POINTS, 2);
 +      immVertex3fv(pos, sta);
 +      immVertex3fv(pos, end);
 +      immEnd();
  }
  
  static void spotvolume(float lvec[3], float vvec[3], const float inp)
        mul_m3_v3(mat2, vvec);
  }
  
 -static void draw_spot_cone(Lamp *la, float x, float z)
 +static void draw_spot_cone(Lamp *la, float x, float z, unsigned pos)
  {
        z = fabsf(z);
  
 -      glBegin(GL_TRIANGLE_FAN);
 -      glVertex3f(0.0f, 0.0f, -x);
 +      const bool square = (la->mode & LA_SQUARE);
  
 -      if (la->mode & LA_SQUARE) {
 -              glVertex3f(z, z, 0);
 -              glVertex3f(-z, z, 0);
 -              glVertex3f(-z, -z, 0);
 -              glVertex3f(z, -z, 0);
 -              glVertex3f(z, z, 0);
 +      immBegin(GWN_PRIM_TRI_FAN, square ? 6 : 34);
 +      immVertex3f(pos, 0.0f, 0.0f, -x);
 +
 +      if (square) {
 +              immVertex3f(pos, z, z, 0);
 +              immVertex3f(pos, -z, z, 0);
 +              immVertex3f(pos, -z, -z, 0);
 +              immVertex3f(pos, z, -z, 0);
 +              immVertex3f(pos, z, z, 0);
        }
        else {
                for (int a = 0; a < 33; a++) {
                        float angle = a * M_PI * 2 / (33 - 1);
 -                      glVertex3f(z * cosf(angle), z * sinf(angle), 0);
 +                      immVertex3f(pos, z * cosf(angle), z * sinf(angle), 0.0f);
                }
        }
  
 -      glEnd();
 +      immEnd();
  }
  
 -static void draw_transp_spot_volume(Lamp *la, float x, float z)
 +static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos)
  {
        glEnable(GL_CULL_FACE);
        glEnable(GL_BLEND);
 -      glDepthMask(0);
 +      glDepthMask(GL_FALSE);
  
        /* draw backside darkening */
        glCullFace(GL_FRONT);
  
        glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
 -      glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
 +      immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
  
 -      draw_spot_cone(la, x, z);
 +      draw_spot_cone(la, x, z, pos);
  
        /* draw front side lighting */
        glCullFace(GL_BACK);
  
        glBlendFunc(GL_ONE, GL_ONE);
 -      glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
 +      immUniformColor3f(0.2f, 0.2f, 0.2f);
  
 -      draw_spot_cone(la, x, z);
 +      draw_spot_cone(la, x, z, pos);
  
        /* restore state */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDisable(GL_BLEND);
 -      glDepthMask(1);
 +      glDepthMask(GL_TRUE);
        glDisable(GL_CULL_FACE);
 -      glCullFace(GL_BACK);
  }
  
  #ifdef WITH_GAMEENGINE
 -static void draw_transp_sun_volume(Lamp *la)
 +static void draw_transp_sun_volume(Lamp *la, unsigned pos)
  {
        float box[8][3];
  
        box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
  
        /* draw edges */
 -      draw_box(box, false);
 +      imm_draw_box(box, false, pos);
  
        /* draw faces */
        glEnable(GL_CULL_FACE);
        glEnable(GL_BLEND);
 -      glDepthMask(0);
 +      glDepthMask(GL_FALSE);
  
        /* draw backside darkening */
        glCullFace(GL_FRONT);
  
        glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
 -      glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
 +      immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
  
 -      draw_box(box, true);
 +      imm_draw_box(box, true, pos);
  
        /* draw front side lighting */
        glCullFace(GL_BACK);
  
        glBlendFunc(GL_ONE, GL_ONE);
 -      glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
 +      immUniformColor3f(0.2f, 0.2f, 0.2f);
  
 -      draw_box(box, true);
 +      imm_draw_box(box, true, pos);
  
        /* restore state */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDisable(GL_BLEND);
 -      glDepthMask(1);
 +      glDepthMask(GL_TRUE);
        glDisable(GL_CULL_FACE);
 -      glCullFace(GL_BACK);
  }
  #endif
  
 -static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
 -                     const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
 +void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
 +              const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
  {
        Object *ob = base->object;
        const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
        Lamp *la = ob->data;
        float vec[3], lvec[3], vvec[3], circrad;
 -      float lampsize;
        float imat[4][4];
  
 -      unsigned char curcol[4];
 -      unsigned char col[4];
        /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
        /* the moment of view3d_draw_transp() call */
        const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
                               !(G.f & G_PICKSEL) &&
                               (la->type == LA_SPOT) &&
                               (la->mode & LA_SHOW_CONE) &&
 -                             !(base->flag & OB_FROMDUPLI) &&
 +                             !(base->flag_legacy & OB_FROMDUPLI) &&
                               !is_view);
  
  #ifdef WITH_GAMEENGINE
                ((la->mode & LA_SHAD_BUF) || 
                (la->mode & LA_SHAD_RAY)) &&
                (la->mode & LA_SHOW_SHADOW_BOX) &&
 -              !(base->flag & OB_FROMDUPLI) &&
 +              !(base->flag_legacy & OB_FROMDUPLI) &&
                !is_view);
  #else
        const bool drawshadowbox = false;
  
        if ((drawcone || drawshadowbox) && !v3d->transp) {
                /* in this case we need to draw delayed */
 -              ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag);
 +              ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
                return;
        }
 -      
 +
        /* we first draw only the screen aligned & fixed scale stuff */
 -      glPushMatrix();
 -      glLoadMatrixf(rv3d->viewmat);
 +      gpuPushMatrix();
 +      gpuLoadMatrix(rv3d->viewmat);
  
        /* lets calculate the scale: */
 -      lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
 +      const float lampsize_px = U.obcenter_dia;
 +      const float lampsize = pixsize * lampsize_px * 0.5f;
  
        /* and view aligned matrix: */
        copy_m4_m4(imat, rv3d->viewinv);
        normalize_v3(imat[0]);
        normalize_v3(imat[1]);
  
 +      const unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
        /* lamp center */
        copy_v3_v3(vec, ob->obmat[3]);
  
 +      float curcol[4];
        if ((dflag & DRAW_CONSTCOLOR) == 0) {
                /* for AA effects */
 -              curcol[0] = ob_wire_col[0];
 -              curcol[1] = ob_wire_col[1];
 -              curcol[2] = ob_wire_col[2];
 -              curcol[3] = 154;
 -              glColor4ubv(curcol);
 +              rgb_uchar_to_float(curcol, ob_wire_col);
 +              curcol[3] = 0.6f;
 +              /* TODO: pay attention to GL_BLEND */
        }
  
 -      glLineWidth(1);
 +      glLineWidth(1.0f);
 +      setlinestyle(3);
  
        if (lampsize > 0.0f) {
 +              const float outlineWidth = 1.5f * U.pixelsize;
 +              const float lampdot_size = lampsize_px * U.pixelsize + outlineWidth;
  
 +              /* Inner Circle */
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                      const float *color = curcol;
                        if (ob->id.us > 1) {
 -                              if (is_obact || (ob->flag & SELECT)) {
 -                                      glColor4ub(0x88, 0xFF, 0xFF, 155);
 +                              if (is_obact || ((base->flag & BASE_SELECTED) != 0)) {
 +                                      static const float active_color[4] = {0.533f, 1.0f, 1.0f, 1.0f};
 +                                      color = active_color;
                                }
                                else {
 -                                      glColor4ub(0x77, 0xCC, 0xCC, 155);
 +                                      static const float inactive_color[4] = {0.467f, 0.8f, 0.8f, 1.0f};
 +                                      color = inactive_color;
                                }
                        }
 +
 +                      GPU_enable_program_point_size();
 +                      glEnable(GL_BLEND);
 +                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +
 +                      immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
 +                      immUniform1f("size", lampdot_size);
 +                      immUniform1f("outlineWidth", outlineWidth);
 +                      immUniformColor3fvAlpha(color, 0.3f);
 +                      immUniform4fv("outlineColor", color);
 +
 +                      immBegin(GWN_PRIM_POINTS, 1);
 +                      immVertex3fv(pos, vec);
 +                      immEnd();
 +
 +                      immUnbindProgram();
 +
 +                      glDisable(GL_BLEND);
 +                      GPU_disable_program_point_size();
                }
 -              
 -              /* Inner Circle */
 -              glEnable(GL_BLEND);
 -              drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
 -              glDisable(GL_BLEND);
 -              drawcircball(GL_POLYGON, vec, lampsize, imat);
 -              
 +              else {
 +                      /* CONSTCOLOR in effect */
 +                      /* TODO: separate picking from drawing */
 +                      immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
 +                      /* color doesn't matter, so don't set */
 +                      glPointSize(lampdot_size);
 +
 +                      immBegin(GWN_PRIM_POINTS, 1);
 +                      immVertex3fv(pos, vec);
 +                      immEnd();
 +
 +                      immUnbindProgram();
 +              }
 +
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              /* TODO(merwin): short term, use DEPTH_ONLY for picking
 +               *               long term, separate picking from drawing
 +               */
 +
                /* restore */
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                      if (ob->id.us > 1)
 -                              glColor4ubv(curcol);
 +                      immUniformColor4fv(curcol);
                }
  
                /* Outer circle */
                circrad = 3.0f * lampsize;
 -              setlinestyle(3);
  
 -              drawcircball(GL_LINE_LOOP, vec, circrad, imat);
 +              imm_drawcircball(vec, circrad, imat, pos);
  
                /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
                if (la->type != LA_HEMI) {
                        if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
 -                              drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
 +                              imm_drawcircball(vec, circrad + 3.0f * pixsize, imat, pos);
                        }
                }
        }
        else {
 -              setlinestyle(3);
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                      immUniformColor4fv(curcol);
 +              }
                circrad = 0.0f;
        }
 -      
 +
        /* draw the pretty sun rays */
        if (la->type == LA_SUN) {
                float v1[3], v2[3], mat[3][3];
                short axis;
 -              
 +
                /* setup a 45 degree rotation matrix */
                axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2);
  
                /* vectors */
                mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
                mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
 -              
 +
                /* center */
 -              glTranslate3fv(vec);
 -              
 +              gpuPushMatrix();
 +              gpuTranslate3fv(vec);
 +
                setlinestyle(3);
 -              
 -              glBegin(GL_LINES);
 +
 +              immBegin(GWN_PRIM_LINES, 16);
                for (axis = 0; axis < 8; axis++) {
 -                      glVertex3fv(v1);
 -                      glVertex3fv(v2);
 +                      immVertex3fv(pos, v1);
 +                      immVertex3fv(pos, v2);
                        mul_m3_v3(mat, v1);
                        mul_m3_v3(mat, v2);
                }
 -              glEnd();
 -              
 -              glTranslatef(-vec[0], -vec[1], -vec[2]);
 +              immEnd();
  
 +              gpuPopMatrix();
        }
 -      
 +
        if (la->type == LA_LOCAL) {
                if (la->mode & LA_SPHERE) {
 -                      drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
 +                      imm_drawcircball(vec, la->dist, imat, pos);
                }
        }
 -      
 -      glPopMatrix();  /* back in object space */
 +
 +      gpuPopMatrix();  /* back in object space */
        zero_v3(vec);
 -      
 +
        if (is_view) {
                /* skip drawing extra info */
        }
                            {z_abs, -z_abs, x},
                            {-z_abs, z_abs, x},
                        };
 -                      const unsigned char indices[] = {
 -                          0, 1, 3,
 -                          0, 3, 2,
 -                          0, 2, 4,
 -                          0, 1, 4,
 -                      };
 -
 -                      /* Draw call:
 -                       * activate and specify pointer to vertex array */
 -                      glEnableClientState(GL_VERTEX_ARRAY);
 -                      glVertexPointer(3, GL_FLOAT, 0, vertices);
 -                      /* draw the pyramid */
 -                      glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices);
  
 -                      /* deactivate vertex arrays after drawing */
 -                      glDisableClientState(GL_VERTEX_ARRAY);
 +                      immBegin(GWN_PRIM_LINES, 16);
 +                      for (int i = 1; i <= 4; ++i) {
 +                              immVertex3fv(pos, vertices[0]); /* apex to corner */
 +                              immVertex3fv(pos, vertices[i]);
 +                              int next_i = (i == 4) ? 1 : (i + 1);
 +                              immVertex3fv(pos, vertices[i]); /* corner to next corner */
 +                              immVertex3fv(pos, vertices[next_i]);
 +                      }
 +                      immEnd();
  
 -                      glTranslatef(0.0f, 0.0f, x);
 +                      gpuTranslate3f(0.0f, 0.0f, x);
  
                        /* draw the square representing spotbl */
                        if (la->type == LA_SPOT) {
                                 * previously it adjusted to always to show it but that seems
                                 * confusing because it doesn't show the actual blend size */
                                if (blend != 0.0f && blend != z_abs) {
 -                                      fdrawbox(blend, -blend, -blend, blend);
 +                                      imm_draw_line_box_3d(pos, blend, -blend, -blend, blend);
                                }
                        }
                }
                else {
 -
                        /* draw the angled sides of the cone */
 -                      glBegin(GL_LINE_STRIP);
 -                      glVertex3fv(vvec);
 -                      glVertex3fv(vec);
 -                      glVertex3fv(lvec);
 -                      glEnd();
 +                      immBegin(GWN_PRIM_LINE_STRIP, 3);
 +                      immVertex3fv(pos, vvec);
 +                      immVertex3fv(pos, vec);
 +                      immVertex3fv(pos, lvec);
 +                      immEnd();
  
                        /* draw the circle at the end of the cone */
 -                      glTranslatef(0.0f, 0.0f, x);
 -                      circ(0.0f, 0.0f, z_abs);
 +                      gpuTranslate3f(0.0f, 0.0f, x);
 +                      imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, z_abs, 32);
  
                        /* draw the circle representing spotbl */
                        if (la->type == LA_SPOT) {
                                 * previously it adjusted to always to show it but that seems
                                 * confusing because it doesn't show the actual blend size */
                                if (blend != 0.0f && blend != z_abs) {
 -                                      circ(0.0f, 0.0f, blend);
 +                                      imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, blend, 32);
                                }
                        }
                }
  
                if (drawcone)
 -                      draw_transp_spot_volume(la, x, z);
 +                      draw_transp_spot_volume(la, x, z, pos);
  
                /* draw clip start, useful for wide cones where its not obvious where the start is */
 -              glTranslatef(0.0, 0.0, -x);  /* reverse translation above */
 -              glBegin(GL_LINES);
 +              gpuTranslate3f(0.0f, 0.0f, -x);  /* reverse translation above */
 +              immBegin(GWN_PRIM_LINES, 2);
                if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
                        float lvec_clip[3];
                        float vvec_clip[3];
                        interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
                        interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
  
 -                      glVertex3fv(lvec_clip);
 -                      glVertex3fv(vvec_clip);
 +                      immVertex3fv(pos, lvec_clip);
 +                      immVertex3fv(pos, vvec_clip);
                }
                /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
                else {
 -                      glVertex3f(0.0, 0.0, -circrad);
 -                      glVertex3f(0.0, 0.0, -la->dist);
 +                      immVertex3f(pos, 0.0f, 0.0f, -circrad);
 +                      immVertex3f(pos, 0.0f, 0.0f, -la->dist);
                }
 -              glEnd();
 +              immEnd();
        }
        else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
 -              
                /* draw the line from the circle along the dist */
 -              glBegin(GL_LINES);
 +              immBegin(GWN_PRIM_LINES, 2);
                vec[2] = -circrad;
 -              glVertex3fv(vec);
 +              immVertex3fv(pos, vec);
                vec[2] = -la->dist;
 -              glVertex3fv(vec);
 -              glEnd();
 -              
 +              immVertex3fv(pos, vec);
 +              immEnd();
 +
                if (la->type == LA_HEMI) {
                        /* draw the hemisphere curves */
                        short axis, steps, dir;
                        float outdist, zdist, mul;
                        zero_v3(vec);
 -                      outdist = 0.14; mul = 1.4; dir = 1;
 -                      
 +                      outdist = 0.14f; mul = 1.4f; dir = 1;
 +
                        setlinestyle(4);
                        /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
                        for (axis = 0; axis < 4; axis++) {
 -                              float v[3] = {0.0, 0.0, 0.0};
 -                              zdist = 0.02;
 -                              
 -                              glBegin(GL_LINE_STRIP);
 -                              
 +                              float v[3] = {0.0f, 0.0f, 0.0f};
 +                              zdist = 0.02f;
 +
 +                              immBegin(GWN_PRIM_LINE_STRIP, 6);
 +
                                for (steps = 0; steps < 6; steps++) {
                                        if (axis == 0 || axis == 1) {       /* x axis up, x axis down */
                                                /* make the arcs start at the edge of the energy circle */
                                        }
  
                                        v[2] = v[2] - steps * zdist;
 -                                      
 -                                      glVertex3fv(v);
 -                                      
 +
 +                                      immVertex3fv(pos, v);
 +
                                        zdist = zdist * mul;
                                }
 -                              
 -                              glEnd();
 +
 +                              immEnd();
                                /* flip the direction */
                                dir = -dir;
                        }
  
  #ifdef WITH_GAMEENGINE
                if (drawshadowbox) {
 -                      draw_transp_sun_volume(la);
 +                      draw_transp_sun_volume(la, pos);
                }
  #endif
 -
        }
        else if (la->type == LA_AREA) {
                setlinestyle(3);
                if (la->area_shape == LA_AREA_SQUARE)
 -                      fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
 +                      imm_draw_line_box_3d(pos, -la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
                else if (la->area_shape == LA_AREA_RECT)
 -                      fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
 +                      imm_draw_line_box_3d(pos, -la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
  
 -              glBegin(GL_LINES);
 -              glVertex3f(0.0, 0.0, -circrad);
 -              glVertex3f(0.0, 0.0, -la->dist);
 -              glEnd();
 +              immBegin(GWN_PRIM_LINES, 2);
 +              immVertex3f(pos, 0.0f, 0.0f, -circrad);
 +              immVertex3f(pos, 0.0f, 0.0f, -la->dist);
 +              immEnd();
        }
 -      
 +
        /* and back to viewspace */
 -      glPushMatrix();
 -      glLoadMatrixf(rv3d->viewmat);
 +      gpuPushMatrix();
 +      gpuLoadMatrix(rv3d->viewmat);
        copy_v3_v3(vec, ob->obmat[3]);
  
        setlinestyle(0);
 -      
 +
        if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
 -              drawshadbuflimits(la, ob->obmat);
 +              drawshadbuflimits(la, ob->obmat, pos);
        }
 -      
 +
        if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              UI_GetThemeColor4ubv(TH_LAMP, col);
 -              glColor4ubv(col);
 +              immUniformThemeColor(TH_LAMP);
        }
  
        glEnable(GL_BLEND);
 -      
 +
        if (vec[2] > 0) vec[2] -= circrad;
        else vec[2] += circrad;
 -      
 -      glBegin(GL_LINES);
 -      glVertex3fv(vec);
 +
 +      immBegin(GWN_PRIM_LINES, 2);
 +      immVertex3fv(pos, vec);
        vec[2] = 0;
 -      glVertex3fv(vec);
 -      glEnd();
 -      
 -      glPointSize(2.0);
 -      glBegin(GL_POINTS);
 -      glVertex3fv(vec);
 -      glEnd();
 -      
 +      immVertex3fv(pos, vec);
 +      immEnd();
 +
 +      glPointSize(2.0f);
 +      immBegin(GWN_PRIM_POINTS, 1);
 +      immVertex3fv(pos, vec);
 +      immEnd();
 +
        glDisable(GL_BLEND);
 -      
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              /* restore for drawing extra stuff */
 -              glColor3ubv(ob_wire_col);
 -      }
 -      /* and finally back to org object space! */
 -      glPopMatrix();
 +
 +      immUnbindProgram();
 +      gpuPopMatrix();
  }
  
 -static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3])
 +static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3], unsigned pos)
  {
 -      glBegin(GL_LINES);
 -      glVertex3f(0.0, 0.0, -sta);
 -      glVertex3f(0.0, 0.0, -end);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 2);
 +      immVertex3f(pos, 0.0f, 0.0f, -sta);
 +      immVertex3f(pos, 0.0f, 0.0f, -end);
 +      immEnd();
  
        if (!(dflag & DRAW_PICKING)) {
 -              glPointSize(3.0);
 -              glBegin(GL_POINTS);
 +              glPointSize(3.0f);
 +              /* would like smooth round points here, but that means binding another shader...
 +               * if it's really desired, pull these points into their own function to be called after */
 +              immBegin(GWN_PRIM_POINTS, 2);
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                      glColor3ubv(col);
 +                      immUniformColor3ubv(col);
                }
 -              glVertex3f(0.0, 0.0, -sta);
 -              glVertex3f(0.0, 0.0, -end);
 -              glEnd();
 +              immVertex3f(pos, 0.0f, 0.0f, -sta);
 +              immVertex3f(pos, 0.0f, 0.0f, -end);
 +              immEnd();
        }
  }
  
  
  /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
  /* qdn: now also enabled for Blender to set focus point for defocus composite node */
 -static void draw_focus_cross(float dist, float size)
 +static void draw_focus_cross(float dist, float size, unsigned pos)
  {
 -      glBegin(GL_LINES);
 -      glVertex3f(-size, 0.0f, -dist);
 -      glVertex3f(size, 0.0f, -dist);
 -      glVertex3f(0.0f, -size, -dist);
 -      glVertex3f(0.0f, size, -dist);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 4);
 +      immVertex3f(pos, -size, 0.0f, -dist);
 +      immVertex3f(pos, size, 0.0f, -dist);
 +      immVertex3f(pos, 0.0f, -size, -dist);
 +      immVertex3f(pos, 0.0f, size, -dist);
 +      immEnd();
  }
  
  #ifdef VIEW3D_CAMERA_BORDER_HACK
@@@ -1671,8 -1590,28 +1671,8 @@@ bool view3d_camera_border_hack_test = f
  
  /* ****************** draw clip data *************** */
  
 -static void draw_bundle_sphere(void)
 -{
 -      static GLuint displist = 0;
 -
 -      if (displist == 0) {
 -              GLUquadricObj *qobj;
 -
 -              displist = glGenLists(1);
 -              glNewList(displist, GL_COMPILE);
 -              qobj = gluNewQuadric();
 -              gluQuadricDrawStyle(qobj, GLU_FILL);
 -              gluSphere(qobj, 0.05, 8, 8);
 -              gluDeleteQuadric(qobj);
 -
 -              glEndList();
 -      }
 -
 -      glCallList(displist);
 -}
 -
  static void draw_viewport_object_reconstruction(
 -        Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d,
 +        Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d,
          MovieClip *clip, MovieTrackingObject *tracking_object,
          const short dflag, const unsigned char ob_wire_col[4],
          int *global_track_index, bool draw_selected)
        if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
                mul_v3_fl(camera_size, tracking_object->scale);
  
 -      glPushMatrix();
 +      gpuPushMatrix();
  
        if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
                /* current ogl matrix is translated in camera space, bundles should
                 * from current ogl matrix */
                invert_m4_m4(imat, base->object->obmat);
  
 -              glMultMatrixf(imat);
 -              glMultMatrixf(mat);
 +              gpuMultMatrix(imat);
 +              gpuMultMatrix(mat);
        }
        else {
                float obmat[4][4];
                BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
  
                invert_m4_m4(imat, obmat);
 -              glMultMatrixf(imat);
 +              gpuMultMatrix(imat);
        }
  
        for (track = tracksbase->first; track; track = track->next) {
                        continue;
  
                if (dflag & DRAW_PICKING)
 -                      GPU_select_load_id(base->selcol + (tracknr << 16));
 +                      GPU_select_load_id(base->object->select_color + (tracknr << 16));
  
 -              glPushMatrix();
 -              glTranslate3fv(track->bundle_pos);
 -              glScalef(v3d->bundle_size / 0.05f / camera_size[0],
 -                       v3d->bundle_size / 0.05f / camera_size[1],
 -                       v3d->bundle_size / 0.05f / camera_size[2]);
 +              gpuPushMatrix();
 +              gpuTranslate3fv(track->bundle_pos);
 +              gpuScale3f(v3d->bundle_size / 0.05f / camera_size[0],
 +                         v3d->bundle_size / 0.05f / camera_size[1],
 +                         v3d->bundle_size / 0.05f / camera_size[2]);
  
                const int v3d_drawtype = view3d_effective_drawtype(v3d);
                if (v3d_drawtype == OB_WIRE) {
 +                      unsigned char color[4];
 +                      const unsigned char *color_ptr = NULL;
                        if ((dflag & DRAW_CONSTCOLOR) == 0) {
                                if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
 -                                      glColor3ubv(ob_wire_col);
 +                                      color_ptr = ob_wire_col;
                                }
                                else {
 -                                      glColor3fv(track->color);
 +                                      rgba_float_to_uchar(color, track->color);
 +                                      color_ptr = color;
                                }
                        }
  
 -                      drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
 +                      drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
                }
                else if (v3d_drawtype > OB_WIRE) {
                        if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
 +                              Gwn_Batch *batch;
 +
 +                              gpuScaleUniform(0.05f);
 +
                                /* selection outline */
                                if (selected) {
 +                                      batch = Batch_get_sphere_wire(1);
 +
                                        if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                                              glColor3ubv(ob_wire_col);
 +                                              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +                                              GWN_batch_uniform_4f(batch, "color",
 +                                                              ob_wire_col[0] / 255.f,
 +                                                              ob_wire_col[1] / 255.f,
 +                                                              ob_wire_col[2] / 255.f, 1.0f);
 +                                      }
 +                                      else {
 +                                              Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
                                        }
 -
                                        glLineWidth(2.0f);
 -                                      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -
 -                                      draw_bundle_sphere();
  
 -                                      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +                                      GWN_batch_draw(batch);
                                }
  
 +                              batch = Batch_get_sphere(0);
 +
                                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                                      if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
 -                                      else UI_ThemeColor(TH_BUNDLE_SOLID);
 +                                      const float light[3] = {0.0f, 0.0f, 1.0f};
 +                                      float col[3];
 +                                      Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
 +                                      GWN_batch_uniform_3fv(batch, "light", light);
 +
 +                                      if (track->flag & TRACK_CUSTOMCOLOR) copy_v3_v3(col, track->color);
 +                                      else UI_GetThemeColor3fv(TH_BUNDLE_SOLID, col);
 +                                      GWN_batch_uniform_4f(batch, "color", col[0], col[1], col[2], 1.0f);
 +                              }
 +                              else {
 +                                      Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
                                }
  
 -                              draw_bundle_sphere();
 +                              GWN_batch_draw(batch);
                        }
                        else {
 +                              unsigned char color[4];
 +                              const unsigned char *color_ptr = NULL;
                                if ((dflag & DRAW_CONSTCOLOR) == 0) {
                                        if (selected) {
 -                                              glColor3ubv(ob_wire_col);
 +                                              color_ptr = ob_wire_col;
                                        }
                                        else {
 -                                              if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
 -                                              else UI_ThemeColor(TH_WIRE);
 +                                              if (track->flag & TRACK_CUSTOMCOLOR) rgba_float_to_uchar(color, track->color);
 +                                              else UI_GetThemeColor4ubv(TH_WIRE, color);
 +
 +                                              color_ptr = color;
                                        }
                                }
  
 -                              drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
 +                              drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
                        }
                }
  
 -              glPopMatrix();
 +              gpuPopMatrix();
  
                if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
                        float pos[3];
                        MovieTrackingReconstruction *reconstruction;
                        reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
  
 -                      if (reconstruction->camnr) {
 +                      if (reconstruction->camnr >= 2) {
                                MovieReconstructedCamera *camera = reconstruction->cameras;
 +                              unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +                              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +                              immUniformThemeColor(TH_CAMERA_PATH);
  
 -                              UI_ThemeColor(TH_CAMERA_PATH);
                                glLineWidth(2.0f);
  
 -                              glBegin(GL_LINE_STRIP);
 +                              immBegin(GWN_PRIM_LINE_STRIP, reconstruction->camnr);
                                for (int a = 0; a < reconstruction->camnr; a++, camera++) {
 -                                      glVertex3fv(camera->mat[3]);
 +                                      immVertex3fv(pos, camera->mat[3]);
                                }
 -                              glEnd();
 +                              immEnd();
 +
 +                              immUnbindProgram();
                        }
                }
        }
  
 -      glPopMatrix();
 +      gpuPopMatrix();
  
        *global_track_index = tracknr;
  }
  
  static void draw_viewport_reconstruction(
 -        Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
 +        Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
          const short dflag, const unsigned char ob_wire_col[4],
          const bool draw_selected)
  {
        /* restore */
        GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
  
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              glColor3ubv(ob_wire_col);
 -      }
 -
        if (dflag & DRAW_PICKING)
 -              GPU_select_load_id(base->selcol);
 +              GPU_select_load_id(base->object->select_color);
  }
  
 -static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
 +/* camera frame */
 +static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos)
  {
 -      glBegin(mode);
 -      glVertex3fv(near_plane[0]);
 -      glVertex3fv(far_plane[0]);
 -      glVertex3fv(far_plane[1]);
 -      glVertex3fv(near_plane[1]);
 -      glEnd();
 -
 -      glBegin(mode);
 -      glVertex3fv(near_plane[1]);
 -      glVertex3fv(far_plane[1]);
 -      glVertex3fv(far_plane[2]);
 -      glVertex3fv(near_plane[2]);
 -      glEnd();
 -
 -      glBegin(mode);
 -      glVertex3fv(near_plane[2]);
 -      glVertex3fv(far_plane[2]);
 -      glVertex3fv(far_plane[3]);
 -      glVertex3fv(near_plane[3]);
 -      glEnd();
 -
 -      glBegin(mode);
 -      glVertex3fv(far_plane[3]);
 -      glVertex3fv(near_plane[3]);
 -      glVertex3fv(near_plane[0]);
 -      glVertex3fv(far_plane[0]);
 -      glEnd();
 +      immBegin(filled ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_LOOP, 4);
 +      immVertex3fv(pos, vec[0]);
 +      immVertex3fv(pos, vec[1]);
 +      immVertex3fv(pos, vec[2]);
 +      immVertex3fv(pos, vec[3]);
 +      immEnd();
  }
  
 -/* camera frame */
 -static void drawcamera_frame(float vec[4][3], const GLenum mode)
 +/* center point to camera frame */
 +static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos)
  {
 -      glBegin(mode);
 -      glVertex3fv(vec[0]);
 -      glVertex3fv(vec[1]);
 -      glVertex3fv(vec[2]);
 -      glVertex3fv(vec[3]);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 8);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[0]);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[1]);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[2]);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[3]);
 +      immEnd();
  }
  
 -/* center point to camera frame */
 -static void drawcamera_framelines(float vec[4][3], float origin[3])
 +static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos)
  {
 -      glBegin(GL_LINE_STRIP);
 -      glVertex3fv(vec[1]);
 -      glVertex3fv(origin);
 -      glVertex3fv(vec[0]);
 -      glVertex3fv(vec[3]);
 -      glVertex3fv(origin);
 -      glVertex3fv(vec[2]);
 -      glEnd();
 +      drawcamera_frame(near_plane, filled, pos);
 +      drawcamera_frame(far_plane, filled, pos);
 +
 +      if (filled) {
 +              immBegin(GWN_PRIM_TRI_STRIP, 10);
 +
 +              immVertex3fv(pos, near_plane[0]);
 +              immVertex3fv(pos, far_plane[0]);
 +              immVertex3fv(pos, near_plane[1]);
 +              immVertex3fv(pos, far_plane[1]);
 +              immVertex3fv(pos, near_plane[2]);
 +              immVertex3fv(pos, far_plane[2]);
 +              immVertex3fv(pos, near_plane[3]);
 +              immVertex3fv(pos, far_plane[3]);
 +              immVertex3fv(pos, near_plane[0]);
 +              immVertex3fv(pos, far_plane[0]);
 +
 +              immEnd();
 +      }
 +      else {
 +              immBegin(GWN_PRIM_LINES, 8);
 +              for (int i = 0; i < 4; ++i) {
 +                      immVertex3fv(pos, near_plane[i]);
 +                      immVertex3fv(pos, far_plane[i]);
 +              }
 +              immEnd();
 +      }
  }
  
  static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
  
  static void drawcamera_stereo3d(
          Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
 -        float vec[4][3], float drawsize, const float scale[3])
 +        float vec[4][3], float drawsize, const float scale[3], unsigned pos)
  {
        float obmat[4][4];
        float vec_lr[2][4][3];
  
        zero_v3(tvec);
  
 -      glPushMatrix();
 +      /* caller bound GPU_SHADER_3D_UNIFORM_COLOR, passed in pos attribute ID */
  
        for (int i = 0; i < 2; i++) {
                ob = BKE_camera_multiview_render(scene, ob, names[i]);
                cam_lr[i] = ob->data;
  
 -              glLoadMatrixf(rv3d->viewmat);
 +              gpuLoadMatrix(rv3d->viewmat);
                BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
 -              glMultMatrixf(obmat);
 +              gpuMultMatrix(obmat);
  
                copy_m3_m3(vec_lr[i], vec);
                copy_v3_v3(vec_lr[i][3], vec[3]);
  
                if (is_stereo3d_cameras) {
                        /* camera frame */
 -                      drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
 +                      drawcamera_frame(vec_lr[i], false, pos);
  
                        /* center point to camera frame */
 -                      drawcamera_framelines(vec_lr[i], tvec);
 +                      drawcamera_framelines(vec_lr[i], tvec, pos);
                }
  
                /* connecting line */
                }
        }
  
 -
        /* the remaining drawing takes place in the view space */
 -      glLoadMatrixf(rv3d->viewmat);
 +      gpuLoadMatrix(rv3d->viewmat);
  
        if (is_stereo3d_cameras) {
                /* draw connecting lines */
 -              GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
 -              GPU_basic_shader_line_stipple(2, 0xAAAA);
 +              glLineStipple(2, 0xAAAA);
 +              glEnable(GL_LINE_STIPPLE);
  
 -              glBegin(GL_LINES);
 -              glVertex3fv(origin[0]);
 -              glVertex3fv(origin[1]);
 -              glEnd();
 +              immBegin(GWN_PRIM_LINES, 2);
 +              immVertex3fv(pos, origin[0]);
 +              immVertex3fv(pos, origin[1]);
 +              immEnd();
  
 -              GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
 +              glDisable(GL_LINE_STIPPLE);
        }
  
        /* draw convergence plane */
                        add_v3_v3(local_plane[i], axis_center);
                }
  
 -              glColor3f(0.0f, 0.0f, 0.0f);
 +              immUniformColor3f(0.0f, 0.0f, 0.0f);
  
                /* camera frame */
 -              drawcamera_frame(local_plane, GL_LINE_LOOP);
 +              drawcamera_frame(local_plane, false, pos);
  
                if (v3d->stereo3d_convergence_alpha > 0.0f) {
                        glEnable(GL_BLEND);
 -                      glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
 -                      glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
 +                      immUniformColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
  
 -                      drawcamera_frame(local_plane, GL_QUADS);
 +                      drawcamera_frame(local_plane, true, pos);
  
                        glDisable(GL_BLEND);
 -                      glDepthMask(1);  /* restore write in zbuffer */
 +                      glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                }
        }
  
                        }
  
                        /* camera frame */
 -                      glColor3f(0.0f, 0.0f, 0.0f);
 +                      immUniformColor3f(0.0f, 0.0f, 0.0f);
  
 -                      drawcamera_frame(near_plane, GL_LINE_LOOP);
 -                      drawcamera_frame(far_plane, GL_LINE_LOOP);
 -                      drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP);
 +                      drawcamera_volume(near_plane, far_plane, false, pos);
  
                        if (v3d->stereo3d_volume_alpha > 0.0f) {
                                glEnable(GL_BLEND);
 -                              glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                              glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
                                if (i == 0)
 -                                      glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
 +                                      immUniformColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
                                else
 -                                      glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
 +                                      immUniformColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
  
 -                              drawcamera_frame(near_plane, GL_QUADS);
 -                              drawcamera_frame(far_plane, GL_QUADS);
 -                              drawcamera_volume(near_plane, far_plane, GL_QUADS);
 +                              drawcamera_volume(near_plane, far_plane, true, pos);
  
                                glDisable(GL_BLEND);
 -                              glDepthMask(1);  /* restore write in zbuffer */
 +                              glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                        }
                }
        }
 -
 -      glPopMatrix();
  }
  
  /* flag similar to draw_object() */
 -static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 -                       const short dflag, const unsigned char ob_wire_col[4])
 +void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 +                const short dflag, const unsigned char ob_wire_col[4])
  {
        /* a standing up pyramid with (0,0,0) as top */
        Camera *cam;
        BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
                                 asp, shift, &drawsize, vec);
  
 -      glDisable(GL_CULL_FACE);
 -      glLineWidth(1);
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      if (ob_wire_col) {
 +              immUniformColor3ubv(ob_wire_col);
 +      }
 +      glLineWidth(1.0f);
  
        /* camera frame */
        if (!is_stereo3d_cameras) {
                        float obmat[4][4];
                        bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
  
 -                      glPushMatrix();
 -                      glLoadMatrixf(rv3d->viewmat);
 +                      gpuPushMatrix();
 +                      gpuLoadMatrix(rv3d->viewmat);
                        BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
 -                      glMultMatrixf(obmat);
 +                      gpuMultMatrix(obmat);
  
 -                      drawcamera_frame(vec, GL_LINE_LOOP);
 -                      glPopMatrix();
 +                      drawcamera_frame(vec, false, pos);
 +                      gpuPopMatrix();
                }
                else {
 -                      drawcamera_frame(vec, GL_LINE_LOOP);
 +                      drawcamera_frame(vec, false, pos);
                }
        }
  
 -      if (is_view)
 +      if (is_view) {
 +              immUnbindProgram();
                return;
 +      }
  
        zero_v3(tvec);
  
        /* center point to camera frame */
        if (!is_stereo3d_cameras)
 -              drawcamera_framelines(vec, tvec);
 +              drawcamera_framelines(vec, tvec, pos);
  
        /* arrow on top */
        tvec[2] = vec[1][2]; /* copy the depth */
         * for active cameras. We actually draw both outline+filled
         * for active cameras so the wire can be seen side-on */
        for (int i = 0; i < 2; i++) {
 -              if (i == 0) glBegin(GL_LINE_LOOP);
 -              else if (i == 1 && is_active) glBegin(GL_TRIANGLES);
 +              if (i == 0) immBegin(GWN_PRIM_LINE_LOOP, 3);
 +              else if (i == 1 && is_active) {
 +                      glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */
 +                      immBegin(GWN_PRIM_TRIS, 3);
 +              }
                else break;
  
                tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
                tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
 -              glVertex3fv(tvec); /* left */
 +              immVertex3fv(pos, tvec); /* left */
                
                tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
 -              glVertex3fv(tvec); /* right */
 +              immVertex3fv(pos, tvec); /* right */
                
                tvec[0] = shift[0];
                tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
 -              glVertex3fv(tvec); /* top */
 +              immVertex3fv(pos, tvec); /* top */
  
 -              glEnd();
 +              immEnd();
        }
  
        if ((dflag & DRAW_SCENESET) == 0) {
                        copy_m4_m4(nobmat, ob->obmat);
                        normalize_m4(nobmat);
  
 -                      glPushMatrix();
 -                      glLoadMatrixf(rv3d->viewmat);
 -                      glMultMatrixf(nobmat);
 +                      gpuLoadMatrix(rv3d->viewmat);
 +                      gpuMultMatrix(nobmat);
  
                        if (cam->flag & CAM_SHOWLIMITS) {
                                const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120};
  
 -                              draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col));
 +                              draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col), pos);
                                /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
 -                              draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
 +                              draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize, pos);
                        }
  
                        if (cam->flag & CAM_SHOWMIST) {
  
                                if (world) {
                                        draw_limit_line(world->miststa, world->miststa + world->mistdist,
 -                                                      dflag, (is_active ? col_hi : col));
 +                                                      dflag, (is_active ? col_hi : col), pos);
                                }
                        }
 -                      glPopMatrix();
                }
        }
  
        /* stereo cameras drawing */
        if (is_stereo3d) {
 -              drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
 +              drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale, pos);
        }
 +
 +      immUnbindProgram();
  }
  
  /* flag similar to draw_object() */
 -static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
 -                        Object *UNUSED(ob), int UNUSED(flag))
 +void drawspeaker(const unsigned char ob_wire_col[3])
  {
 -      float vec[3];
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
 -      glEnable(GL_BLEND);
 -      glLineWidth(1);
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +      if (ob_wire_col) {
 +              immUniformColor3ubv(ob_wire_col);
 +      }
 +
 +      glLineWidth(1.0f);
 +
 +      const int segments = 16;
  
        for (int j = 0; j < 3; j++) {
 -              vec[2] = 0.25f * j - 0.125f;
 +              float z = 0.25f * j - 0.125f;
  
 -              glBegin(GL_LINE_LOOP);
 -              for (int i = 0; i < 16; i++) {
 -                      vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 -                      vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 -                      glVertex3fv(vec);
 +              immBegin(GWN_PRIM_LINE_LOOP, segments);
 +              for (int i = 0; i < segments; i++) {
 +                      float x = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 +                      float y = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 +                      immVertex3f(pos, x, y, z);
                }
 -              glEnd();
 +              immEnd();
        }
  
        for (int j = 0; j < 4; j++) {
 -              vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
 -              vec[1] = ((j % 2) * (j - 2)) * 0.5f;
 -              glBegin(GL_LINE_STRIP);
 +              float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
 +              float y = ((j % 2) * (j - 2)) * 0.5f;
 +              immBegin(GWN_PRIM_LINE_STRIP, 3);
                for (int i = 0; i < 3; i++) {
                        if (i == 1) {
 -                              vec[0] *= 0.5f;
 -                              vec[1] *= 0.5f;
 +                              x *= 0.5f;
 +                              y *= 0.5f;
                        }
  
 -                      vec[2] = 0.25f * i - 0.125f;
 -                      glVertex3fv(vec);
 +                      float z = 0.25f * i - 0.125f;
 +                      immVertex3f(pos, x, y, z);
                }
 -              glEnd();
 +              immEnd();
        }
  
 -      glDisable(GL_BLEND);
 +      immUnbindProgram();
  }
  
 -static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
 +static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel,
 +                               unsigned int pos, unsigned int color)
  {
        BPoint *bp = lt->def;
        const float *co = dl ? dl->verts : NULL;
 +      float active_color[4], draw_color[4];
  
 -      const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
 -      UI_ThemeColor(color);
 +      UI_GetThemeColor4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, draw_color);
 +      UI_GetThemeColor4fv(TH_ACTIVE_VERT, active_color);
  
        glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 -      glBegin(GL_POINTS);
 +      immBeginAtMost(GWN_PRIM_POINTS, lt->pntsw * lt->pntsv * lt->pntsu);
  
        for (int w = 0; w < lt->pntsw; w++) {
                int wxt = (w == 0 || w == lt->pntsw - 1);
                                        if (bp->hide == 0) {
                                                /* check for active BPoint and ensure selected */
                                                if ((bp == actbp) && (bp->f1 & SELECT)) {
 -                                                      UI_ThemeColor(TH_ACTIVE_VERT);
 -                                                      glVertex3fv(dl ? co : bp->vec);
 -                                                      UI_ThemeColor(color);
 +                                                      immAttrib4fv(color, active_color);
 +                                                      immVertex3fv(pos, dl ? co : bp->vec);
                                                }
                                                else if ((bp->f1 & SELECT) == sel) {
 -                                                      glVertex3fv(dl ? co : bp->vec);
 +                                                      immAttrib4fv(color, draw_color);
 +                                                      immVertex3fv(pos, dl ? co : bp->vec);
                                                }
                                        }
                                }
                }
        }
        
 -      glEnd();
 +      immEnd();
  }
  
 -static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
 +static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol,
 +                               unsigned int pos, unsigned int color)
  {
        int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
  
        if (actdef_wcol) {
                float col[3];
                MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
 -              
                weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
 -              glColor3fv(col);
 -
 +              immAttrib3fv(color, col);
        }
        
        if (dl) {
 -              glVertex3fv(&dl->verts[index * 3]);
 +              immVertex3fv(pos, &dl->verts[index * 3]);
        }
        else {
 -              glVertex3fv(lt->def[index].vec);
 +              immVertex3fv(pos, lt->def[index].vec);
        }
  }
  
@@@ -2435,7 -2334,7 +2435,7 @@@ static void ensure_curve_cache(Scene *s
  #endif
  
  /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
 -static void drawlattice(View3D *v3d, Object *ob)
 +static void drawlattice(View3D *v3d, Object *ob, const short dflag, const unsigned char ob_wire_col[4])
  {
        Lattice *lt = ob->data;
        DispList *dl;
        if (is_edit) {
                lt = lt->editlatt->latt;
  
 -              UI_ThemeColor(TH_WIRE_EDIT);
 -              
                if (ob->defbase.first && lt->dvert) {
                        actdef_wcol = ob->actdef;
                }
        }
  
 -      glLineWidth(1);
 -      glBegin(GL_LINES);
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int color, pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      if (actdef_wcol) {
 +              color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
 +      }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +              if (is_edit) {
 +                      immUniformThemeColor(TH_WIRE_EDIT);
 +              }
 +              else {
 +                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                              immUniformColor3ubv(ob_wire_col);
 +                      }
 +                      else {
 +                              immUniformColor3f(0.0f, 0.0f, 0.0f);
 +                      }
 +              }
 +      }
 +
 +      glLineWidth(1.0f);
 +      immBeginAtMost(GWN_PRIM_LINES, lt->pntsw * lt->pntsv * lt->pntsu * 6);
 +
        for (w = 0; w < lt->pntsw; w++) {
                int wxt = (w == 0 || w == lt->pntsw - 1);
                for (v = 0; v < lt->pntsv; v++) {
                                int uxt = (u == 0 || u == lt->pntsu - 1);
  
                                if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
 -                                      drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol);
 -                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol);
 +                                      drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol, pos, color);
 +                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
                                }
                                if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
 -                                      drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol);
 -                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol);
 +                                      drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol, pos, color);
 +                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
                                }
                                if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
 -                                      drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol);
 -                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol);
 +                                      drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol, pos, color);
 +                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
                                }
                        }
                }
        }
 -      glEnd();
 +
 +      immEnd();
 +      immUnbindProgram();
  
        if (is_edit) {
                BPoint *actbp = BKE_lattice_active_point_get(lt);
  
                if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
 -              
 -              lattice_draw_verts(lt, dl, actbp, 0);
 -              lattice_draw_verts(lt, dl, actbp, 1);
 -              
 +
 +              Gwn_VertFormat *v_format = immVertexFormat();
 +              unsigned int v_pos = GWN_vertformat_attr_add(v_format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              unsigned int v_color = GWN_vertformat_attr_add(v_format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
 +
 +              immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
 +
 +              lattice_draw_verts(lt, dl, actbp, 0, v_pos, v_color);
 +              lattice_draw_verts(lt, dl, actbp, 1, v_pos, v_color);
 +
 +              immUnbindProgram();
 +
                if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
        }
  }
@@@ -2534,7 -2401,6 +2534,7 @@@ typedef struct drawDMVertSel_userData 
        int active;
        unsigned char *col[3];  /* (base, sel, act) */
        char sel_prev;
 +      unsigned int pos, color;
  } drawDMVertSel_userData;
  
  static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
        if (!(mv->flag & ME_HIDE)) {
                const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
                if (sel != data->sel_prev) {
 -                      glColor3ubv(data->col[sel]);
 +                      immAttrib3ubv(data->color, data->col[sel]);
                        data->sel_prev = sel;
                }
  
 -              glVertex3fv(co);
 +              immVertex3fv(data->pos, co);
        }
  }
  
  static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
  {
        drawDMVertSel_userData data;
 +      Gwn_VertFormat *format = immVertexFormat();
  
        /* TODO define selected color */
        unsigned char base_col[3] = {0x0, 0x0, 0x0};
        data.col[1] = sel_col;
        data.col[2] = act_col;
  
 -      glBegin(GL_POINTS);
 +      data.color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      if (dm->getNumVerts(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +
 +      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
        dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  /* ************** DRAW MESH ****************** */
@@@ -2630,34 -2486,25 +2630,34 @@@ static void draw_dm_face_normals__mapFu
                        copy_v3_v3(n, no);
                }
  
 -              glVertex3fv(cent);
 -              glVertex3f(cent[0] + n[0] * data->normalsize,
 -                         cent[1] + n[1] * data->normalsize,
 -                         cent[2] + n[2] * data->normalsize);
 +              immVertex3fv(data->pos, cent);
 +              immVertex3f(data->pos, cent[0] + n[0] * data->normalsize,
 +                                     cent[1] + n[1] * data->normalsize,
 +                                     cent[2] + n[2] * data->normalsize);
        }
  }
  
 -static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
 +static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
  {
 +      Gwn_VertFormat *format = immVertexFormat();
        drawDMNormal_userData data;
  
        data.bm = em->bm;
        data.normalsize = scene->toolsettings->normalsize;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
        calcDrawDMNormalScale(ob, &data);
  
 -      glBegin(GL_LINES);
 +      if (dm->getNumPolys(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformThemeColor(theme_id);
 +
 +      immBeginAtMost(GWN_PRIM_LINES, dm->getNumPolys(dm) * 2);
        dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
        if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
            (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
        {
 -              glVertex3fv(cent);
 +              immVertex3fv(data->pos, cent);
        }
  }
 -static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
 +static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select, const unsigned char fcol[3])
  {
 -      drawBMSelect_userData data = {em->bm, select};
 +      Gwn_VertFormat *format = immVertexFormat();
 +
 +      drawBMSelect_userData data;
 +      data.bm = em->bm;
 +      data.select = select;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
 -      glBegin(GL_POINTS);
 +      if (dm->getNumPolys(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformColor3ubv(fcol);
 +
 +      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumPolys(dm));
        dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
                        copy_v3_v3(n, no);
                }
  
 -              glVertex3fv(co);
 -              glVertex3f(co[0] + n[0] * data->normalsize,
 -                         co[1] + n[1] * data->normalsize,
 -                         co[2] + n[2] * data->normalsize);
 +              immVertex3fv(data->pos, co);
 +              immVertex3f(data->pos, co[0] + n[0] * data->normalsize,
 +                               co[1] + n[1] * data->normalsize,
 +                               co[2] + n[2] * data->normalsize);
        }
  }
  
 -static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
 +static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
  {
        drawDMNormal_userData data;
 +      Gwn_VertFormat *format = immVertexFormat();
  
        data.bm = em->bm;
        data.normalsize = scene->toolsettings->normalsize;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
        calcDrawDMNormalScale(ob, &data);
  
 -      glBegin(GL_LINES);
 +      if (dm->getNumVerts(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformThemeColor(theme_id);
 +
 +      immBeginAtMost(GWN_PRIM_LINES, dm->getNumVerts(dm) * 2);
        dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
 -/* Draw verts with color set based on selection */
 -static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
 -                                   const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
 +static void draw_dm_verts_skin_root__mapFunc(void *userData, int index, const float co[3],
 +                                             const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
  {
        drawDMVerts_userData *data = userData;
        BMVert *eve = BM_vert_at_index(data->bm, index);
  
        if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
                /* skin nodes: draw a red circle around the root node(s) */
 -              if (data->cd_vskin_offset != -1) {
 -                      const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
 -                      if (vs->flag & MVERT_SKIN_ROOT) {
 -                              float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
 -                              glEnd();
 -                      
 -                              glColor4ubv(data->th_skin_root);
 -                              drawcircball(GL_LINES, co, radius, data->imat);
 -
 -                              glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
 -                              glBegin(GL_POINTS);
 -                      }
 +              const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
 +              if (vs->flag & MVERT_SKIN_ROOT) {
 +                      float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
 +                      imm_drawcircball(co, radius, data->imat, data->pos);
                }
 +      }
 +}
 +
 +/* Draw verts with color set based on selection */
 +static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
 +                                   const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
 +{
 +      drawDMVerts_userData *data = userData;
 +      BMVert *eve = BM_vert_at_index(data->bm, index);
  
 +      if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
                /* draw active in a different color - no need to stop/start point drawing for this :D */
                if (eve == data->eve_act) {
 -                      glColor4ubv(data->th_editmesh_active);
 -                      glVertex3fv(co);
 -
 -                      /* back to regular vertex color */
 -                      glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
 +                      immAttrib4ubv(data->color, data->th_editmesh_active);
 +                      immVertex3fv(data->pos, co);
                }
                else {
 -                      glVertex3fv(co);
 +                      immAttrib4ubv(data->color, data->sel ? data->th_vertex_select : data->th_vertex);
 +                      immVertex3fv(data->pos, co);
                }
        }
  }
  
  static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
 -                          RegionView3D *rv3d)
 +                          RegionView3D *rv3d, const unsigned char col[4])
  {
 +      Gwn_VertFormat *format = immVertexFormat();
 +
        drawDMVerts_userData data;
        data.sel = sel;
        data.eve_act = eve_act;
        data.bm = em->bm;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      data.color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
  
        /* Cache theme values */
        UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
        UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
        UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
  
 -      /* For skin root drawing */
 -      data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
 +      /* Set correct alpha */
 +      data.th_editmesh_active[3] = data.th_vertex_select[3] = data.th_vertex[3] = data.th_skin_root[3] = col[3];
 +
        /* view-aligned matrix */
        mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
        invert_m4(data.imat);
  
 +      if (dm->getNumVerts(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +
        glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 -      glBegin(GL_POINTS);
 +
 +      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
        dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
 +
 +      /* For skin root drawing */
 +      data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
 +
 +      if (data.cd_vskin_offset != -1) {
 +              data.pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformColor4ubv(data.th_skin_root);
 +
 +              dm->foreachMappedVert(dm, draw_dm_verts_skin_root__mapFunc, &data, DM_FOREACH_NOP);
 +
 +              immUnbindProgram();
 +      }
  }
  
  /* Draw edges with color set based on selection */
@@@ -3136,32 -2938,24 +3136,32 @@@ static void draw_dm_loop_normals__mapFu
                        }
                        mul_v3_fl(vec, data->normalsize);
                        add_v3_v3(vec, co);
 -                      glVertex3fv(co);
 -                      glVertex3fv(vec);
 +                      immVertex3fv(data->pos, co);
 +                      immVertex3fv(data->pos, vec);
                }
        }
  }
  
 -static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
 +static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
  {
        drawDMNormal_userData data;
  
        data.bm = em->bm;
        data.normalsize = scene->toolsettings->normalsize;
 +      data.pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      if (dm->getNumLoops(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformThemeColor(theme_id);
  
        calcDrawDMNormalScale(ob, &data);
  
 -      glBegin(GL_LINES);
 +      immBeginAtMost(GWN_PRIM_LINES, dm->getNumLoops(dm) * 2);
        dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  /* Draw faces with color set based on selection
@@@ -3278,7 -3072,7 +3278,7 @@@ static void draw_dm_creases(BMEditMesh 
        data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
  
        if (data.cd_layer_offset != -1) {
 -              glLineWidth(3.0);
 +              glLineWidth(3.0f);
                dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
        }
  }
@@@ -3308,10 -3102,8 +3308,10 @@@ static void draw_dm_bweights__mapFunc(v
        if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
                const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
                if (bweight != 0.0f) {
 -                      UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_BEVEL, bweight);
 -                      glVertex3fv(co);
 +                      unsigned char col[3];
 +                      UI_GetThemeColorBlend3ubv(TH_VERTEX, TH_VERTEX_BEVEL, bweight, col);
 +                      immAttrib3ubv(data->col, col);
 +                      immVertex3fv(data->pos, co);
                }
        }
  }
@@@ -3325,21 -3117,11 +3325,21 @@@ static void draw_dm_bweights(BMEditMes
                data.bm = em->bm;
                data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
  
 +              /* is that ever true? */
                if (data.cd_layer_offset != -1) {
 -                      glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
 -                      glBegin(GL_POINTS);
 +                      Gwn_VertFormat *format = immVertexFormat();
 +                      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                      data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
 +
 +                      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +
 +                      glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2.0f);
 +
 +                      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
                        dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
 -                      glEnd();
 +                      immEnd();
 +
 +                      immUnbindProgram();
                }
        }
        else {
                data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
  
                if (data.cd_layer_offset != -1) {
 -                      glLineWidth(3.0);
 +                      glLineWidth(3.0f);
                        dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
                }
        }
@@@ -3370,7 -3152,7 +3370,7 @@@ static void draw_em_fancy_verts(Scene *
  {
        ToolSettings *ts = scene->toolsettings;
  
 -      if (v3d->zbuf) glDepthMask(0);  /* disable write in zbuffer, zbuf select */
 +      if (v3d->zbuf) glDepthMask(GL_FALSE);  /* disable write in zbuffer, zbuf select */
  
        for (int sel = 0; sel < 2; sel++) {
                unsigned char col[4], fcol[4];
                        }
  
                        if (ts->selectmode & SCE_SELECT_VERTEX) {
 -                              glPointSize(size);
 -                              glColor4ubv(col);
 -                              draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
 +                              draw_dm_verts(em, cageDM, sel, eve_act, rv3d, col);
                        }
                        
                        if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
                                glPointSize(fsize);
 -                              glColor4ubv(fcol);
 -                              draw_dm_face_centers(em, cageDM, sel);
 +                              draw_dm_face_centers(em, cageDM, sel, fcol);
                        }
                        
                        if (pass == 0) {
                }
        }
  
 -      if (v3d->zbuf) glDepthMask(1);
 +      if (v3d->zbuf) glDepthMask(GL_TRUE);
  }
  
  static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
@@@ -3522,9 -3307,11 +3522,9 @@@ static void draw_em_measure_stats(ARegi
  
        if (me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_EDGEANG)) {
                BoundBox bb;
 -              bglMats mats = {{0}};
                const rcti rect = {0, ar->winx, 0, ar->winy};
  
 -              view3d_get_transformation(ar, ar->regiondata, em->ob, &mats);
 -              ED_view3d_clipping_calc(&bb, clip_planes, &mats, &rect);
 +              ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
        }
  
        if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
@@@ -3888,7 -3675,7 +3888,7 @@@ static DMDrawOption draw_em_fancy__setG
        }
  }
  
 -static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 +static void draw_em_fancy(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d,
                            Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
  
  {
        const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE);
        bool use_depth_offset = false;
        
 -      glLineWidth(1);
 +      glLineWidth(1.0f);
        
        BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
  
                        draw_mesh_paint_weight_faces(finalDM, true, draw_em_fancy__setFaceOpts, me->edit_btmesh);
  
                        ED_view3d_polygon_offset(rv3d, 1.0);
 -                      glDepthMask(0);
 +                      glDepthMask(GL_FALSE);
                        use_depth_offset = true;
                }
                else {
                        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
                }
                else if (check_object_draw_texture(scene, v3d, dt)) {
 -                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 +                      if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
                                glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
                                finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind,
                                glFrontFace(GL_CCW);
                        }
                        else {
 -                              draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
 +                              draw_mesh_textured(scene, sl, v3d, rv3d, ob, finalDM, 0);
                        }
                }
                else {
                UI_ThemeColor(TH_WIRE_EDIT);
  
                ED_view3d_polygon_offset(rv3d, 1.0);
 -              glDepthMask(0);
 +              glDepthMask(GL_FALSE);
                use_depth_offset = true;
        }
        else {
  #endif
  
                        glEnable(GL_BLEND);
 -                      glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
                        /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
                        if (check_object_draw_texture(scene, v3d, dt))
  #endif
  
                        glDisable(GL_BLEND);
 -                      glDepthMask(1);  /* restore write in zbuffer */
 +                      glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                }
                else if (efa_act) {
                        /* even if draw faces is off it would be nice to draw the stipple face
                        UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
  
                        glEnable(GL_BLEND);
 -                      glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
  #ifdef WITH_FREESTYLE
                        draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
  #endif
  
                        glDisable(GL_BLEND);
 -                      glDepthMask(1);  /* restore write in zbuffer */
 +                      glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                }
  
                /* here starts all fancy draw-extra over */
                else {
                        if (me->drawflag & ME_DRAWSEAMS) {
                                UI_ThemeColor(TH_EDGE_SEAM);
 -                              glLineWidth(2);
 +                              glLineWidth(2.0f);
  
                                draw_dm_edges_seams(em, cageDM);
  
  
                        if (me->drawflag & ME_DRAWSHARP) {
                                UI_ThemeColor(TH_EDGE_SHARP);
 -                              glLineWidth(2);
 +                              glLineWidth(2.0f);
  
                                draw_dm_edges_sharp(em, cageDM);
  
  #ifdef WITH_FREESTYLE
                        if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
                                UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
 -                              glLineWidth(2);
 +                              glLineWidth(2.0f);
  
                                draw_dm_edges_freestyle(em, cageDM);
  
                                draw_dm_bweights(em, scene, cageDM);
                        }
  
 -                      glLineWidth(1);
 +                      glLineWidth(1.0f);
                        draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
                }
  
                        draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
  
                        if (me->drawflag & ME_DRAWNORMALS) {
 -                              UI_ThemeColor(TH_NORMAL);
 -                              draw_dm_face_normals(em, scene, ob, cageDM);
 +                              draw_dm_face_normals(em, scene, ob, cageDM, TH_NORMAL);
                        }
                        if (me->drawflag & ME_DRAW_VNORMALS) {
 -                              UI_ThemeColor(TH_VNORMAL);
 -                              draw_dm_vert_normals(em, scene, ob, cageDM);
 +                              draw_dm_vert_normals(em, scene, ob, cageDM, TH_VNORMAL);
                        }
                        if (me->drawflag & ME_DRAW_LNORMALS) {
 -                              UI_ThemeColor(TH_LNORMAL);
 -                              draw_dm_loop_normals(em, scene, ob, cageDM);
 +                              draw_dm_loop_normals(em, scene, ob, cageDM, TH_LNORMAL);
                        }
  
                        if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
        }
  
        if (use_depth_offset) {
 -              glDepthMask(1);
 +              glDepthMask(GL_TRUE);
                ED_view3d_polygon_offset(rv3d, 0.0);
                GPU_object_material_unbind();
        }
  #endif
  }
  
 +static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *UNUSED(ar), View3D *UNUSED(v3d),
 +                              Object *UNUSED(ob), Mesh *me, BMEditMesh *UNUSED(em), DerivedMesh *UNUSED(cageDM), DerivedMesh *UNUSED(finalDM), const char UNUSED(dt))
 +{
 +      /* for now... something simple! */
 +      Gwn_Batch *surface = DRW_mesh_batch_cache_get_all_triangles(me);
 +
 +      glEnable(GL_DEPTH_TEST);
 +      glDepthFunc(GL_LEQUAL);
 +
 +      glEnable(GL_BLEND);
 +
 +      /* disable depth writes for transparent surface, so it doesn't interfere with itself */
 +      glDepthMask(GL_FALSE);
 +
 +      Batch_set_builtin_program(surface, GPU_SHADER_3D_UNIFORM_COLOR);
 +      GWN_batch_uniform_4f(surface, "color", 1.0f, 0.5f, 0.0f, 0.5f);
 +      GWN_batch_draw(surface);
 +
 +#if 0 /* until I understand finalDM better */
 +      if (finalDM != cageDM) {
 +              puts("finalDM != cageDM");
 +              Gwn_Batch *finalSurface = MBC_get_all_triangles(finalDM);
 +              Batch_set_builtin_program(finalSurface, GPU_SHADER_3D_UNIFORM_COLOR);
 +              GWN_batch_uniform_4f(finalSurface, "color", 0.0f, 0.0f, 0.0f, 0.05f);
 +              GWN_batch_draw(finalSurface);
 +      }
 +#endif
 +
 +      glDepthMask(GL_TRUE);
 +
 +      /* now write surface depth so other objects won't poke through
 +       * NOTE: does not help as much as desired
 +       * TODO: draw edit object last to avoid this mess
 +       */
 +      Batch_set_builtin_program(surface, GPU_SHADER_3D_DEPTH_ONLY);
 +      GWN_batch_draw(surface);
 +
 +      if (GLEW_VERSION_3_2) {
 +#if 0
 +              Gwn_Batch *overlay = DRW_mesh_batch_cache_get_overlay_edges(me);
 +              Batch_set_builtin_program(overlay, GPU_SHADER_EDGES_OVERLAY);
 +              GWN_batch_uniform_2f(overlay, "viewportSize", ar->winx, ar->winy);
 +              GWN_batch_draw(overlay);
 +#endif
 +
 +#if 0 /* TODO: use this SIMPLE variant for pure triangle meshes */
 +              Batch_set_builtin_program(surface, GPU_SHADER_EDGES_OVERLAY_SIMPLE);
 +              /* use these defaults:
 +               * const float edgeColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
 +               * GWN_batch_uniform_4f(surface, "fillColor", edgeColor[0], edgeColor[1], edgeColor[2], 0.0f);
 +               * GWN_batch_uniform_4fv(surface, "outlineColor", edgeColor);
 +               * GWN_batch_uniform_1f(surface, "outlineWidth", 1.0f);
 +               */
 +              GWN_batch_uniform_2f(surface, "viewportSize", ar->winx, ar->winy);
 +              GWN_batch_draw(surface);
 +#endif
 +      }
 +      else {
 +              Gwn_Batch *edges = DRW_mesh_batch_cache_get_all_edges(me);
 +              Batch_set_builtin_program(edges, GPU_SHADER_3D_UNIFORM_COLOR);
 +              GWN_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
 +              glEnable(GL_LINE_SMOOTH);
 +              glLineWidth(1.5f);
 +              GWN_batch_draw(edges);
 +              glDisable(GL_LINE_SMOOTH);
 +      }
 +
 +#if 0 /* looks good even without points */
 +      Gwn_Batch *verts = MBC_get_all_verts(me);
 +      glEnable(GL_BLEND);
 +
 +      Batch_set_builtin_program(verts, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
 +      GWN_batch_uniform_4f(verts, "color", 0.0f, 0.0f, 0.0f, 1.0f);
 +      GWN_batch_uniform_1f(verts, "size", UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.5f);
 +      GWN_batch_draw(verts);
 +
 +      glDisable(GL_BLEND);
 +#endif
 +}
 +
  /* Mesh drawing routines */
  
 -static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
 +void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm, const unsigned char ob_wire_col[4]) /* LEGACY */
  {
        if ((v3d->transp == false) &&  /* not when we draw the transparent pass */
            (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */
        {
                glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
 -              glDepthMask(0);
 +              glDepthMask(GL_FALSE);
 +
 +              if (ob_wire_col) glColor4ubv(ob_wire_col);
  
                /* if transparent, we cannot draw the edges for solid select... edges
                 * have no material info. GPU_object_material_visible will skip the
                        dm->drawEdges(dm, 0, 1);
                }
  
 -              glDepthMask(1);
 +              glDepthMask(GL_TRUE);
 +      }
 +}
 +
 +static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, Mesh *me, const bool is_active)
 +{
 +      if ((v3d->transp == false) &&  /* not when we draw the transparent pass */
 +          (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */
 +      {
 +              glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
 +              glDepthMask(GL_FALSE);
 +
 +              float outline_color[4];
 +              UI_GetThemeColor4fv((is_active ? TH_ACTIVE : TH_SELECT), outline_color);
 +
 +#if 1 /* new version that draws only silhouette edges */
 +              Gwn_Batch *fancy_edges = DRW_mesh_batch_cache_get_fancy_edges(me);
 +
 +              if (rv3d->persp == RV3D_ORTHO) {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO);
 +                      /* set eye vector, transformed to object coords */
 +                      float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
 +                      mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye);
 +                      GWN_batch_uniform_3fv(fancy_edges, "eye", eye);
 +              }
 +              else {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
 +              }
 +
 +              GWN_batch_uniform_1b(fancy_edges, "drawFront", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawBack", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", true);
 +              GWN_batch_uniform_4fv(fancy_edges, "silhouetteColor", outline_color);
 +
 +              GWN_batch_draw(fancy_edges);
 +#else /* alternate version that matches look of old viewport (but more efficient) */
 +              Gwn_Batch *batch = MBC_get_all_edges(dm);
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +              GWN_batch_uniform_4fv(batch, "color", outline_color);
 +              GWN_batch_draw(batch);
 +#endif
 +
 +              glDepthMask(GL_TRUE);
        }
  }
  
@@@ -4293,11 -3959,11 +4293,11 @@@ static bool object_is_halo(Scene *scene
        return (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene));
  }
  
 -static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static void draw_mesh_fancy(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
                              const char dt, const unsigned char ob_wire_col[4], const short dflag)
  {
  #ifdef WITH_GAMEENGINE
 -      Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : base->object;
 +      Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, sl) : base->object;
  #else
        Object *ob = base->object;
  #endif
        eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
        bool /* no_verts,*/ no_edges, no_faces;
        DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
 -      const bool is_obact = (ob == OBACT);
 +      const bool is_obact = (ob == OBACT_NEW);
        int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
  
        if (!dm)
  
        if (dt == OB_BOUNDBOX) {
                if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
 -                      draw_bounding_volume(ob, ob->boundtype);
 +                      draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
        }
        else if ((no_faces && no_edges) ||
                 ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
        {
 -              glPointSize(1.5);
 +              glPointSize(1.5f);
                dm->drawVerts(dm);
        }
        else if ((dt == OB_WIRE) || no_faces) {
  
                if ((v3d->flag & V3D_SELECT_OUTLINE) &&
                    ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 -                  (base->flag & SELECT) &&
 +                  (base->flag & BASE_SELECTED) &&
                    !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
                    (draw_wire == OBDRAW_WIRE_OFF))
                {
 -                      draw_mesh_object_outline(v3d, ob, dm);
 +                      draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
                }
  
 -              if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
 +              if (draw_glsl_material(scene, sl, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
                        Paint *p;
  
                        glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
 -                      if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) {
 +                      if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
                                GPUVertexAttribs gattribs;
                                float planes[4][4];
                                float (*fpl)[4] = NULL;
  
                                if (ob->sculpt->partial_redraw) {
                                        if (ar->do_draw & RGN_DRAW_PARTIAL) {
 -                                              ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
                                                fpl = planes;
                                                ob->sculpt->partial_redraw = 0;
                                        }
                                draw_mesh_face_select(rv3d, me, dm, false);
                }
                else {
 -                      draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags);
 +                      draw_mesh_textured(scene, sl, v3d, rv3d, ob, dm, draw_flags);
                }
  
                if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) {
                                /* draw outline */
                                if ((v3d->flag & V3D_SELECT_OUTLINE) &&
                                    ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 -                                  (base->flag & SELECT) &&
 +                                  (base->flag & BASE_SELECTED) &&
                                    (draw_wire == OBDRAW_WIRE_OFF) &&
                                    (ob->sculpt == NULL))
                                {
 -                                      draw_mesh_object_outline(v3d, ob, dm);
 +                                      draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
                                }
  
                                /* materials arent compatible with vertex colors */
  
                        if ((v3d->flag & V3D_SELECT_OUTLINE) &&
                            ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 -                          (base->flag & SELECT) &&
 +                          (base->flag & BASE_SELECTED) &&
                            (draw_wire == OBDRAW_WIRE_OFF) &&
                            (ob->sculpt == NULL))
                        {
 -                              draw_mesh_object_outline(v3d, ob, dm);
 +                              draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
                        }
  
                        glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
 -                      if (ob->sculpt && (p = BKE_paint_get_active(scene))) {
 +                      if (ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
                                float planes[4][4];
                                float (*fpl)[4] = NULL;
                                const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
  
                                if (ob->sculpt->partial_redraw) {
                                        if (ar->do_draw & RGN_DRAW_PARTIAL) {
 -                                              ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
                                                fpl = planes;
                                                ob->sculpt->partial_redraw = 0;
                                        }
  
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
                        if (is_obact && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
 -                              ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f);
 +                              float color[3];
 +                              ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f, color);
 +                              glColor3fv(color);
                        }
                        else {
                                glColor3ubv(ob_wire_col);
                 */
                if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
                        ED_view3d_polygon_offset(rv3d, 1.0);
 -                      glDepthMask(0);  /* disable write in zbuffer, selected edge wires show better */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, selected edge wires show better */
                }
                
                glLineWidth(1.0f);
                dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
  
                if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
 -                      glDepthMask(1);
 +                      glDepthMask(GL_TRUE);
                        ED_view3d_polygon_offset(rv3d, 0.0);
                }
        }
  }
  
  /* returns true if nothing was drawn, for detecting to draw an object center */
 -static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static bool draw_mesh_object(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base,
                               const char dt, const unsigned char ob_wire_col[4], const short dflag)
  {
        Object *ob = base->object;
        /* If we are drawing shadows and any of the materials don't cast a shadow,
         * then don't draw the object */
        if (v3d->flag2 & V3D_RENDER_SHADOW) {
 -              for (int i = 1; i <= ob->totcol; ++i) {
 +              for (int i = 0; i < ob->totcol; ++i) {
                        Material *ma = give_current_material(ob, i);
                        if (ma && !(ma->mode2 & MA_CASTSHADOW)) {
                                return true;
  
                if (use_material) {
                        if (dt > OB_WIRE) {
 -                              const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
 +                              const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
  
 -                              GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
 +                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
                        }
                }
  
 -              draw_em_fancy(scene, ar, v3d, ob, em, cageDM, finalDM, dt);
 +              draw_em_fancy(scene, sl, ar, v3d, ob, em, cageDM, finalDM, dt);
  
                if (use_material) {
                        GPU_end_object_materials();
                /* ob->bb was set by derived mesh system, do NULL check just to be sure */
                if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) {
                        if (dt > OB_WIRE) {
 -                              const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
 +                              const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
  
                                if (dt == OB_SOLID || glsl) {
                                        const bool check_alpha = check_alpha_pass(base);
 -                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl,
                                                                   (check_alpha) ? &do_alpha_after : NULL);
                                }
                        }
  
 -                      draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
 +                      draw_mesh_fancy(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
  
                        GPU_end_object_materials();
                        
                }
        }
        
 -      if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
 +      if ((dflag & DRAW_PICKING) == 0 && (base->flag_legacy & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
                /* GPU_begin_object_materials checked if this is needed */
                if (do_alpha_after) {
                        if (ob->dtx & OB_DRAWXRAY) {
        return retval;
  }
  
 -/* ************** DRAW DISPLIST ****************** */
 -
 -
 -/**
 - * \param dl_type_mask Only draw types matching this mask.
 - * \return true when nothing was drawn
 - */
 -static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
 +static void make_color_variations(const unsigned char base_ubyte[4], float low[4], float med[4], float high[4], const bool other_obedit)
  {
 -      if (dlbase == NULL) return true;
 -      
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 +      /* original idea: nice variations (lighter & darker shades) of base color
 +       * current implementation uses input color as high; med & low get closer to background color
 +       */
  
 -      for (DispList *dl = dlbase->first; dl; dl = dl->next) {
 -              if (dl->parts == 0 || dl->nr == 0) {
 -                      continue;
 -              }
 +      float bg[3];
 +      UI_GetThemeColor3fv(TH_BACK, bg);
  
 -              if ((dl_type_mask & (1 << dl->type)) == 0) {
 -                      continue;
 -              }
 -              
 -              const float *data = dl->verts;
 -              int parts;
 +      float base[4];
 +      rgba_uchar_to_float(base, base_ubyte);
  
 -              switch (dl->type) {
 -                      case DL_SEGM:
 +      if (other_obedit) {
 +              /* this object should fade away so user can focus on the object being edited */
 +              interp_v3_v3v3(low, bg, base, 0.1f);
 +              interp_v3_v3v3(med, bg, base, 0.2f);
 +              interp_v3_v3v3(high, bg, base, 0.25f);
 +      }
 +      else {
 +              interp_v3_v3v3(low, bg, base, 0.333f);
 +              interp_v3_v3v3(med, bg, base, 0.667f);
 +              copy_v3_v3(high, base);
 +      }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +      /* use original alpha */
 +      low[3] = base[3];
 +      med[3] = base[3];
 +      high[3] = base[3];
 +}
  
 -                              for (parts = 0; parts < dl->parts; parts++)
 -                                      glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
 -                              
 -                              break;
 -                      case DL_POLY:
 +static void draw_mesh_fancy_new(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
 +                                const char dt, const unsigned char ob_wire_col[4], const short dflag, const bool other_obedit)
 +{
 +      if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) {
 +              /* too complicated! use existing methods */
 +              /* TODO: move this into a separate depth pre-pass */
 +              draw_mesh_fancy(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
 +              return;
 +      }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +#ifdef WITH_GAMEENGINE
 +      Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, sl) : base->object;
 +#else
 +      Object *ob = base->object;
 +#endif
 +      Mesh *me = ob->data;
 +      eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; /* could be bool draw_wire_overlay */
 +      bool no_edges, no_faces;
 +      DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
 +      const bool is_obact = (ob == OBACT_NEW);
 +      int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
  
 -                              for (parts = 0; parts < dl->parts; parts++)
 -                                      glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
 +      if (!dm)
 +              return;
  
 -                              break;
 -                      case DL_SURF:
 +      const bool solid = dt >= OB_SOLID;
 +      if (solid) {
 +              DM_update_materials(dm, ob);
 +      }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +      /* Check to draw dynamic paint colors (or weights from WeightVG modifiers).
 +       * Note: Last "preview-active" modifier in stack will win! */
 +      if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob))
 +              draw_flags |= DRAW_MODIFIERS_PREVIEW;
  
 -                              for (parts = 0; parts < dl->parts; parts++) {
 -                                      if (dl->flag & DL_CYCL_U)
 -                                              glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
 -                                      else
 -                                              glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
 -                              }
 +      /* Unwanted combination */
 +      if (draw_flags & DRAW_FACE_SELECT) {
 +              draw_wire = OBDRAW_WIRE_OFF;
 +      }
 +      else if (ob->dtx & OB_DRAWWIRE) {
 +              draw_wire = OBDRAW_WIRE_ON;
 +      }
  
 -                              for (int nr = 0; nr < dl->nr; nr++) {
 -                                      int ofs = 3 * dl->nr;
 +      /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */
 +      if (dm->type == DM_TYPE_CCGDM) {
 +              no_edges = !subsurf_has_edges(dm);
 +              no_faces = !subsurf_has_faces(dm);
 +      }
 +      else {
 +              no_edges = (dm->getNumEdges(dm) == 0);
 +              no_faces = (dm->getNumPolys(dm) == 0);
 +      }
  
 -                                      data = (dl->verts) + 3 * nr;
 -                                      parts = dl->parts;
 +      if (solid) {
 +              /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
 +              glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 +      }
  
 -                                      if (dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP);
 -                                      else glBegin(GL_LINE_STRIP);
 +      if (dt == OB_BOUNDBOX) {
 +              if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
 +                      draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
 +      }
 +      else if ((no_faces && no_edges) ||
 +               ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
 +      {
 +              glPointSize(1.5f);
 +              // dm->drawVerts(dm);
 +              // TODO: draw smooth round points as a batch
 +      }
 +      else if ((dt == OB_WIRE) || no_faces) {
 +              draw_wire = OBDRAW_WIRE_ON;
  
 -                                      while (parts--) {
 -                                              glVertex3fv(data);
 -                                              data += ofs;
 -                                      }
 -                                      glEnd();
 +              /* enable depth for wireframes */
 +              glEnable(GL_DEPTH_TEST);
 +              glDepthFunc(GL_LESS);
  
 -#if 0
 -                              /* (ton) this code crashes for me when resolv is 86 or higher... no clue */
 -                              glVertexPointer(3, GL_FLOAT, sizeof(float) * 3 * dl->nr, data + 3 * nr);
 -                              if (dl->flag & DL_CYCL_V)
 -                                      glDrawArrays(GL_LINE_LOOP, 0, dl->parts);
 -                              else
 -                                      glDrawArrays(GL_LINE_STRIP, 0, dl->parts);
 -#endif
 -                              }
 -                              break;
 +              glLineWidth(1.0f);
  
 -                      case DL_INDEX3:
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              break;
 +#if 1 /* fancy wireframes */
  
 -                      case DL_INDEX4:
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              break;
 +              Gwn_Batch *fancy_edges = DRW_mesh_batch_cache_get_fancy_edges(me);
 +
 +              if (rv3d->persp == RV3D_ORTHO) {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO);
 +                      /* set eye vector, transformed to object coords */
 +                      float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
 +                      mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye);
 +                      GWN_batch_uniform_3fv(fancy_edges, "eye", eye);
 +              }
 +              else {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
                }
 -      }
 -      
 -      glDisableClientState(GL_VERTEX_ARRAY);
 -      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -      
 -      return false;
 -}
  
 -static bool drawDispListwire(ListBase *dlbase, const short ob_type)
 -{
 -      unsigned int dl_mask = 0xffffffff;
 +              float frontColor[4];
 +              float backColor[4];
 +              float outlineColor[4];
 +              make_color_variations(ob_wire_col, backColor, frontColor, outlineColor, other_obedit);
  
 -      /* skip fill-faces for curves & fonts */
 -      if (ELEM(ob_type, OB_FONT, OB_CURVE)) {
 -              dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4));
 -      }
 +              GWN_batch_uniform_4fv(fancy_edges, "frontColor", frontColor);
 +              GWN_batch_uniform_4fv(fancy_edges, "backColor", backColor);
 +              GWN_batch_uniform_1b(fancy_edges, "drawFront", true);
 +              GWN_batch_uniform_1b(fancy_edges, "drawBack", true); /* false here = backface cull */
 +              GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", false);
  
 -      return drawDispListwire_ex(dlbase, dl_mask);
 -}
 +              GWN_batch_draw(fancy_edges);
  
 -static bool index3_nors_incr = true;
 +              /* extra oomph for the silhouette contours */
 +              glLineWidth(2.0f);
 +              GWN_batch_program_use_begin(fancy_edges); /* hack to make the following uniforms stick */
 +              GWN_batch_uniform_1b(fancy_edges, "drawFront", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawBack", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", true);
 +              GWN_batch_uniform_4fv(fancy_edges, "silhouetteColor", outlineColor);
  
 -static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
 -                              const unsigned char ob_wire_col[4], const bool use_glsl)
 -{
 -      GPUVertexAttribs gattribs;
 -      
 -      if (lb == NULL) return;
 +              GWN_batch_draw(fancy_edges);
  
 -      glEnableClientState(GL_VERTEX_ARRAY);
 +#else /* simple wireframes */
  
 -      /* track current material, -1 for none (needed for lines) */
 -      short col = -1;
 -      
 -      DispList *dl = lb->first;
 -      while (dl) {
 -              const float *data = dl->verts;
 -              const float *ndata = dl->nors;
 +              Gwn_Batch *batch = MBC_get_all_edges(dm);
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
  
 -              switch (dl->type) {
 -                      case DL_SEGM:
 -                              if (ob->type == OB_SURF) {
 -                                      if (col != -1) {
 -                                              GPU_object_material_unbind();
 -                                              col = -1;
 -                                      }
 +              float color[4];
 +              rgba_uchar_to_float(color, ob_wire_col);
  
 -                                      if ((dflag & DRAW_CONSTCOLOR) == 0)
 -                                              glColor3ubv(ob_wire_col);
 +              GWN_batch_uniform_4fv(batch, "color", color);
 +
 +              GWN_batch_draw(batch);
 +#endif
 +      }
 +      else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
 +               check_object_draw_texture(scene, v3d, dt))
 +      {
 +              bool draw_loose = true;
 +
 +              if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                  ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                  (base->flag & BASE_SELECTED) &&
 +                  !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
 +                  (draw_wire == OBDRAW_WIRE_OFF))
 +              {
 +                      draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
 +              }
 +
 +              if (draw_glsl_material(scene, sl, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
 +                      Paint *p;
 +
 +                      glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 +
 +                      if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
 +                              GPUVertexAttribs gattribs;
 +                              float planes[4][4];
 +                              float (*fpl)[4] = NULL;
 +                              const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
 +
 +                              if (ob->sculpt->partial_redraw) {
 +                                      if (ar->do_draw & RGN_DRAW_PARTIAL) {
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
 +                                              fpl = planes;
 +                                              ob->sculpt->partial_redraw = 0;
 +                                      }
 +                              }
 +
 +                              GPU_object_material_bind(1, &gattribs);
 +                              dm->drawFacesSolid(dm, fpl, fast, NULL);
 +                              draw_loose = false;
 +                      }
 +                      else
 +                              dm->drawFacesGLSL(dm, GPU_object_material_bind);
 +
 +                      GPU_object_material_unbind();
 +
 +                      glFrontFace(GL_CCW);
 +
 +                      if (draw_flags & DRAW_FACE_SELECT)
 +                              draw_mesh_face_select(rv3d, me, dm, false);
 +              }
 +              else {
 +                      draw_mesh_textured(scene, sl, v3d, rv3d, ob, dm, draw_flags);
 +              }
 +
 +              if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) {
 +                      if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
 +                              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                                      glColor3ubv(ob_wire_col);
 +                              }
 +                              glLineWidth(1.0f);
 +                              dm->drawLooseEdges(dm);
 +                      }
 +              }
 +      }
 +      else if (dt == OB_SOLID) {
 +              if (draw_flags & DRAW_MODIFIERS_PREVIEW) {
 +                      /* for object selection draws no shade */
 +                      if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) {
 +                              /* TODO: draw basic faces with GPU_SHADER_3D_DEPTH_ONLY */
 +                      }
 +                      else {
 +                              const float specular[3] = {0.47f, 0.47f, 0.47f};
 +
 +                              /* draw outline */
 +                              /* TODO: move this into a separate pass */
 +                              if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                                  ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                                  (base->flag & BASE_SELECTED) &&
 +                                  (draw_wire == OBDRAW_WIRE_OFF) &&
 +                                  (ob->sculpt == NULL))
 +                              {
 +                                      draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
 +                              }
 +
 +                              /* materials arent compatible with vertex colors */
 +                              GPU_end_object_materials();
 +
 +                              /* set default specular */
 +                              GPU_basic_shader_colors(NULL, specular, 35, 1.0f);
 +                              GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
 +
 +                              dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS);
 +
 +                              GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
 +                      }
 +              }
 +              else {
 +                      Paint *p;
 +
 +                      if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                          ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                          (base->flag & BASE_SELECTED) &&
 +                          (draw_wire == OBDRAW_WIRE_OFF) &&
 +                          (ob->sculpt == NULL))
 +                      {
 +                              /* TODO: move this into a separate pass */
 +                              draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
 +                      }
 +
 +                      glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 +
 +                      if (ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
 +                              float planes[4][4];
 +                              float (*fpl)[4] = NULL;
 +                              const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
 +
 +                              if (ob->sculpt->partial_redraw) {
 +                                      if (ar->do_draw & RGN_DRAW_PARTIAL) {
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
 +                                              fpl = planes;
 +                                              ob->sculpt->partial_redraw = 0;
 +                                      }
 +                              }
 +
 +                              dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind);
 +                      }
 +                      else
 +                              dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
 +
 +                      glFrontFace(GL_CCW);
 +
 +                      GPU_object_material_unbind();
 +
 +                      if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
 +                              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                                      glColor3ubv(ob_wire_col);
 +                              }
 +                              glLineWidth(1.0f);
 +                              dm->drawLooseEdges(dm);
 +                      }
 +              }
 +      }
 +      else if (dt == OB_PAINT) {
 +              draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags);
 +
 +              /* since we already draw wire as wp guide, don't draw over the top */
 +              draw_wire = OBDRAW_WIRE_OFF;
 +      }
 +
 +      if ((draw_wire != OBDRAW_WIRE_OFF) &&  /* draw extra wire */
 +          /* when overriding with render only, don't bother */
 +          (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)) // <-- is this "== 0" in the right spot???
 +      {
 +              /* When using wireframe object draw in particle edit mode
 +               * the mesh gets in the way of seeing the particles, fade the wire color
 +               * with the background. */
 +
 +              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                      /* TODO:
 +                       * Batch_UniformColor4ubv(ob_wire_col);
 +                       */
 +              }
 +
 +              /* If drawing wire and drawtype is not OB_WIRE then we are
 +               * overlaying the wires.
 +               *
 +               * No need for polygon offset because new technique is AWESOME.
 +               */
 +#if 0
 +              glLineWidth(1.0f);
 +              dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
 +#else
 +              /* something */
 +#endif
 +      }
 +      
 +#if 0 // (merwin) what is this for?
 +      if (is_obact && BKE_paint_select_vert_test(ob)) {
 +              const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
 +              glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 +
 +              if (!use_depth) glDisable(GL_DEPTH_TEST);
 +              else            ED_view3d_polygon_offset(rv3d, 1.0);
 +              drawSelectedVertices(dm, ob->data);
 +              if (!use_depth) glEnable(GL_DEPTH_TEST);
 +              else            ED_view3d_polygon_offset(rv3d, 0.0);
 +      }
 +#endif
 +
 +      dm->release(dm);
 +}
 +
 +static bool UNUSED_FUNCTION(draw_mesh_object_new)(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base,
 +                                 const char dt, const unsigned char ob_wire_col[4], const short dflag)
 +{
 +      Object *ob = base->object;
 +      Object *obedit = scene->obedit;
 +      Mesh *me = ob->data;
 +      BMEditMesh *em = me->edit_btmesh;
 +      bool do_alpha_after = false, drawlinked = false, retval = false;
 +
 +      if (v3d->flag2 & V3D_RENDER_SHADOW) {
 +              /* TODO: handle shadow pass separately */
 +              return true;
 +      }
 +      
 +      if (obedit && ob != obedit && ob->data == obedit->data) {
 +              if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {}
 +              else if (ob->modifiers.first || obedit->modifiers.first) {}
 +              else drawlinked = true;
 +      }
 +
 +      /* backface culling */
 +      const bool solid = dt > OB_WIRE;
 +      const bool cullBackface = solid && (v3d->flag2 & V3D_BACKFACE_CULLING);
 +      if (cullBackface) {
 +              glEnable(GL_CULL_FACE);
 +              glCullFace(GL_BACK);
 +      }
 +
 +      if (ob == obedit || drawlinked) {
 +              DerivedMesh *finalDM, *cageDM;
 +
 +              if (obedit != ob) {
 +                      /* linked to the edit object */
 +                      finalDM = cageDM = editbmesh_get_derived_base(
 +                              ob, em, scene->customdata_mask);
 +              }
 +              else {
 +                      cageDM = editbmesh_get_derived_cage_and_final(
 +                              scene, ob, em, scene->customdata_mask,
 +                              &finalDM);
 +              }
 +
 +              const bool use_material = solid && ((me->drawflag & ME_DRAWEIGHT) == 0);
 +
 +#if 0 // why update if not being used?
 +              DM_update_materials(finalDM, ob);
 +              if (cageDM != finalDM) {
 +                      DM_update_materials(cageDM, ob);
 +              }
 +#endif // moved to below
 +
 +              if (use_material) {
 +                      DM_update_materials(finalDM, ob);
 +                      if (cageDM != finalDM) {
 +                              DM_update_materials(cageDM, ob);
 +                      }
 +
 +                      const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
 +
 +                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
 +              }
 +
 +              draw_em_fancy_new(scene, ar, v3d, ob, me, em, cageDM, finalDM, dt);
 +
 +              if (use_material) {
 +                      GPU_end_object_materials();
 +              }
 +
 +              if (obedit != ob)
 +                      finalDM->release(finalDM);
 +      }
 +      else {
 +              /* ob->bb was set by derived mesh system, do NULL check just to be sure */
 +              if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) {
 +                      if (solid) {
 +                              const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
 +
 +                              if (dt == OB_SOLID || glsl) {
 +                                      const bool check_alpha = check_alpha_pass(base);
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl,
 +                                                                 (check_alpha) ? &do_alpha_after : NULL);
 +                              }
 +                      }
 +
 +                      const bool other_obedit = obedit && (obedit != ob);
 +
 +                      draw_mesh_fancy_new(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit);
 +
 +                      GPU_end_object_materials();
 +
 +                      if (me->totvert == 0) retval = true;
 +              }
 +      }
 +
 +      if (cullBackface)
 +              glDisable(GL_CULL_FACE);
 +
 +      return retval;
 +}
 +
 +/* ************** DRAW DISPLIST ****************** */
 +
 +static void drawDispListVerts(Gwn_PrimType prim_type, const void *data, unsigned int vert_ct, const unsigned char wire_col[3])
 +{
 +      Gwn_VertFormat format = {0};
 +      unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +      GWN_vertbuf_data_alloc(vbo, vert_ct);
 +
 +      GWN_vertbuf_attr_fill(vbo, pos_id, data);
 +
 +      Gwn_Batch *batch = GWN_batch_create(prim_type, vbo, NULL);
 +      Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +      if (wire_col) {
 +              GWN_batch_uniform_4f(batch, "color", wire_col[0] / 255.0f, wire_col[1] / 255.0f, wire_col[2] / 255.0f, 1.0f);
 +      }
 +      GWN_batch_draw(batch);
 +      GWN_batch_discard_all(batch);
 +}
 +
 +/* convert dispList with elem indices to batch, only support triangles and quads
 + * XXX : This is a huge perf issue. We should cache the resulting batches inside the object instead.
 + *       But new viewport will do it anyway
 + * TODO implement flat drawing */
 +static void drawDispListElem(
 +        bool quads, bool UNUSED(smooth), bool ndata_is_single,
 +        const float *data, const float *ndata, unsigned int data_len,
 +        const int *elem, unsigned int elem_len, const unsigned char wire_col[3])
 +{
 +      Gwn_VertFormat format = {0};
 +      int i;
 +      const int *idx = elem;
 +      unsigned int pos_id, nor_id;
 +
 +      pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (ndata) {
 +              if (ndata_is_single) {
 +                      /* pass */
 +              }
 +              else {
 +                      nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              }
 +      }
 +
 +      Gwn_IndexBufBuilder elb;
 +      GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, (quads) ? elem_len * 2 : elem_len, 0xffffffff);
 +
 +      if (quads) {
 +              for (i = elem_len; i; --i, idx += 4) {
 +                      GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
 +                      GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[2], idx[3]);
 +              }
 +      }
 +      else {
 +              for (i = elem_len; i; --i, idx += 3) {
 +                      GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
 +              }
 +      }
 +
 +      Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +      GWN_vertbuf_data_alloc(vbo, data_len);
 +
 +      GWN_vertbuf_attr_fill(vbo, pos_id, data);
 +
 +      if (ndata) {
 +              if (ndata_is_single) {
 +                      /* TODO: something like glNormal for a single value */
 +              }
 +              else {
 +                      GWN_vertbuf_attr_fill(vbo, nor_id, ndata);
 +              }
 +      }
 +
 +      Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_TRIS, vbo, GWN_indexbuf_build(&elb));
 +      Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
 +      if (wire_col) {
 +              GWN_batch_uniform_4f(batch, "color", wire_col[0] / 255.0f, wire_col[1] / 255.0f, wire_col[2] / 255.0f, 1.0f);
 +      }
 +      GWN_batch_uniform_4f(batch, "color", 0.8f, 0.8f, 0.8f, 1.0f);
 +      GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
 +      GWN_batch_draw(batch);
 +      GWN_batch_discard_all(batch);
 +}
 +
 +/**
 + * \param dl_type_mask Only draw types matching this mask.
 + * \return true when nothing was drawn
 + */
 +static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask, const unsigned char wire_col[3])
 +{
 +      if (dlbase == NULL) return true;
 +      
 +      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 +
 +      for (DispList *dl = dlbase->first; dl; dl = dl->next) {
 +              if (dl->parts == 0 || dl->nr == 0) {
 +                      continue;
 +              }
 +
 +              if ((dl_type_mask & (1 << dl->type)) == 0) {
 +                      continue;
 +              }
 +
 +              const float *data = dl->verts;
 +              int parts;
 +
 +              switch (dl->type) {
 +                      case DL_SEGM:
 +                              for (parts = 0; parts < dl->parts; parts++)
 +                                      drawDispListVerts(GWN_PRIM_LINE_STRIP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                              break;
  
 -                                      // glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                                      // glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
 -                                      glBegin(GL_LINE_STRIP);
 -                                      for (int nr = dl->nr; nr; nr--, data += 3)
 -                                              glVertex3fv(data);
 -                                      glEnd();
 -                              }
 -                              break;
                        case DL_POLY:
 +                              for (parts = 0; parts < dl->parts; parts++)
 +                                      drawDispListVerts(GWN_PRIM_LINE_LOOP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                              break;
 +
 +                      case DL_SURF:
 +                              for (parts = 0; parts < dl->parts; parts++) {
 +                                      if (dl->flag & DL_CYCL_U)
 +                                              drawDispListVerts(GWN_PRIM_LINE_LOOP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                                      else
 +                                              drawDispListVerts(GWN_PRIM_LINE_STRIP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                              }
 +
 +                              float *data_aligned = MEM_mallocN(sizeof(float) * 3 * dl->parts, "aligned data");
 +                              for (int nr = 0; nr < dl->nr; nr++) {
 +                                      int ofs = 3 * dl->nr;
 +                                      int idx = 0;
 +
 +                                      data = (dl->verts) + 3 * nr;
 +                                      parts = dl->parts;
 +
 +                                      while (parts--) {
 +                                              copy_v3_v3(data_aligned + idx, data);
 +                                              data += ofs;
 +                                              idx += 3;
 +                                      }
 +
 +                                      if (dl->flag & DL_CYCL_V)
 +                                              drawDispListVerts(GWN_PRIM_LINE_LOOP, data_aligned, dl->parts, wire_col);
 +                                      else
 +                                              drawDispListVerts(GWN_PRIM_LINE_STRIP, data_aligned, dl->parts, wire_col);
 +                              }
 +
 +                              if (data_aligned)
 +                                      MEM_freeN(data_aligned);
 +
 +                              break;
 +
 +                      case DL_INDEX3:
 +                              drawDispListElem(
 +                                      false, true, false,
 +                                      dl->verts, NULL, dl->nr,
 +                                      dl->index, dl->parts, wire_col);
 +                              break;
 +
 +                      case DL_INDEX4:
 +                              drawDispListElem(
 +                                      true, true, false,
 +                                      dl->verts, NULL, dl->nr,
 +                                      dl->index, dl->parts, wire_col);
 +                              break;
 +              }
 +      }
 +      
 +      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +      
 +      return false;
 +}
 +
 +static bool drawDispListwire(ListBase *dlbase, const short ob_type, const unsigned char wire_col[3])
 +{
 +      unsigned int dl_mask = 0xffffffff;
 +
 +      /* skip fill-faces for curves & fonts */
 +      if (ELEM(ob_type, OB_FONT, OB_CURVE)) {
 +              dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4));
 +      }
 +
 +      return drawDispListwire_ex(dlbase, dl_mask, wire_col);
 +}
 +
 +static bool index3_nors_incr = true;
 +
 +static void drawDispListsolid(ListBase *lb, Object *ob, const short UNUSED(dflag),
 +                              const unsigned char ob_wire_col[4], const bool use_glsl)
 +{
 +      GPUVertexAttribs gattribs;
 +      
 +      if (lb == NULL) return;
 +
 +      /* track current material, -1 for none (needed for lines) */
 +      short col = -1;
 +      
 +      DispList *dl = lb->first;
 +      while (dl) {
 +              const float *data = dl->verts;
 +              //const float *ndata = dl->nors;
 +
 +              switch (dl->type) {
 +                      case DL_SEGM:
                                if (ob->type == OB_SURF) {
                                        if (col != -1) {
                                                GPU_object_material_unbind();
                                                col = -1;
                                        }
  
 -                                      /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */
 -                                      //glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                                      //glDrawArrays(GL_LINE_LOOP, 0, dl->nr);
 +                                      drawDispListVerts(GWN_PRIM_LINE_STRIP, data, dl->nr, ob_wire_col);
 +                              }
 +                              break;
 +                      case DL_POLY:
 +                              if (ob->type == OB_SURF) {
 +                                      if (col != -1) {
 +                                              GPU_object_material_unbind();
 +                                              col = -1;
 +                                      }
  
 -                                      glBegin(GL_LINE_LOOP);
 -                                      for (int nr = dl->nr; nr; nr--, data += 3)
 -                                              glVertex3fv(data);
 -                                      glEnd();
 +                                      drawDispListVerts(GWN_PRIM_LINE_LOOP, data, dl->nr, ob_wire_col);
                                }
                                break;
                        case DL_SURF:
                                                GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
                                                col = dl->col;
                                        }
 -                                      /* FLAT/SMOOTH shading for surfaces */
 -                                      glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT);
 +                                      const unsigned int verts_len = dl->nr * dl->parts;
  
 -                                      glEnableClientState(GL_NORMAL_ARRAY);
 -                                      glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                                      glNormalPointer(GL_FLOAT, 0, dl->nors);
 -                                      glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index);
 -                                      glDisableClientState(GL_NORMAL_ARRAY);
 -                                      glShadeModel(GL_SMOOTH);
 +                                      drawDispListElem(
 +                                              true, (dl->rt & CU_SMOOTH) != 0, false,
 +                                              dl->verts, dl->nors, verts_len,
 +                                              dl->index, dl->totindex, ob_wire_col);
                                }
                                break;
  
                                        col = dl->col;
                                }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -
 +#if 0
                                /* for polys only one normal needed */
                                if (index3_nors_incr) {
                                        glEnableClientState(GL_NORMAL_ARRAY);
                                }
                                else
                                        glNormal3fv(ndata);
 +#endif
 +                              /* special case, 'nors' is a single value */
 +                              drawDispListElem(
 +                                      false, (dl->rt & CU_SMOOTH) != 0, true,
 +                                      dl->verts, dl->nors, dl->nr,
 +                                      dl->index, dl->parts, ob_wire_col);
  
 -                              glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -
 +#if 0
                                if (index3_nors_incr)
                                        glDisableClientState(GL_NORMAL_ARRAY);
 +#endif
  
                                break;
  
                                        col = dl->col;
                                }
  
 -                              glEnableClientState(GL_NORMAL_ARRAY);
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glNormalPointer(GL_FLOAT, 0, dl->nors);
 -                              glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              glDisableClientState(GL_NORMAL_ARRAY);
 +                              drawDispListElem(
 +                                      true, true, false,
 +                                      dl->verts, dl->nors, dl->nr,
 +                                      dl->index, dl->parts, ob_wire_col);
  
                                break;
                }
                dl = dl->next;
        }
  
 -      glDisableClientState(GL_VERTEX_ARRAY);
        glFrontFace(GL_CCW);
  
        if (col != -1) {
@@@ -5415,7 -4574,7 +5415,7 @@@ static void drawCurveDMWired(Object *ob
  }
  
  /* return true when nothing was drawn */
 -static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt)
 +static bool drawCurveDerivedMesh(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt)
  {
        Object *ob = base->object;
        DerivedMesh *dm = ob->derivedFinal;
        glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
        if (dt > OB_WIRE && dm->getNumPolys(dm)) {
 -              bool glsl = draw_glsl_material(scene, ob, v3d, dt);
 -              GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
 +              bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
 +              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
  
                if (!glsl)
                        dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
   * Only called by #drawDispList
   * \return true when nothing was drawn
   */
 -static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static bool drawDispList_nobackface(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base,
                                      const char dt, const short dflag, const unsigned char ob_wire_col[4])
  {
        Object *ob = base->object;
                                if (!render_only) {
                                        /* when we have faces, only draw loose-wire */
                                        if (has_faces) {
 -                                              drawDispListwire_ex(lb, (1 << DL_SEGM));
 +                                              drawDispListwire_ex(lb, (1 << DL_SEGM), ob_wire_col);
                                        }
                                        else {
 -                                              drawDispListwire(lb, ob->type);
 +                                              drawDispListwire(lb, ob->type, ob_wire_col);
                                        }
                                }
  
                                        /* pass */
                                }
                                else {
 -                                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
 +                                      if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 1, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
                                                GPU_end_object_materials();
                                        }
                                        else {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
                                                GPU_end_object_materials();
                                        }
                                        if (cu->editnurb && cu->bevobj == NULL && cu->taperobj == NULL && cu->ext1 == 0.0f && cu->ext2 == 0.0f) {
 -                                              cpack(0);
 -                                              drawDispListwire(lb, ob->type);
 +                                              unsigned char col[4] = {0, 0, 0, 0};
 +                                              drawDispListwire(lb, ob->type, col);
                                        }
                                }
                                index3_nors_incr = true;
                        }
                        else {
                                if (!render_only || BKE_displist_has_faces(lb)) {
 -                                      return drawDispListwire(lb, ob->type);
 +                                      return drawDispListwire(lb, ob->type, ob_wire_col);
                                }
                        }
                        break;
  
                                if (dl->nors == NULL) BKE_displist_normals_add(lb);
  
 -                              if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
 +                              if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 1, NULL);
                                        drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
                                        GPU_end_object_materials();
                                }
                                else {
 -                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
                                        drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
                                        GPU_end_object_materials();
                                }
                        }
                        else {
 -                              return drawDispListwire(lb, ob->type);
 +                              return drawDispListwire(lb, ob->type, ob_wire_col);
                        }
                        break;
                case OB_MBALL:
  
                                if (solid) {
  
 -                                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
 +                                      if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 1, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
                                                GPU_end_object_materials();
                                        }
                                        else {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
                                                GPU_end_object_materials();
                                        }
                                }
                                else {
 -                                      return drawDispListwire(lb, ob->type);
 +                                      return drawDispListwire(lb, ob->type, ob_wire_col);
                                }
                        }
                        break;
  
        return false;
  }
 -static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static bool drawDispList(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base,
                           const char dt, const short dflag, const unsigned char ob_wire_col[4])
  {
        bool retval;
        ensure_curve_cache(scene, base->object);
  #endif
  
 -      if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
 +      if (drawCurveDerivedMesh(scene, sl, v3d, rv3d, base, dt) == false) {
                retval = false;
        }
        else {
  
                glFrontFace(mode);
  
 -              retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
 +              retval = drawDispList_nobackface(scene, sl, v3d, rv3d, base, dt, dflag, ob_wire_col);
  
                if (mode != GL_CCW) {
                        glFrontFace(GL_CCW);
  }
  
  /* *********** drawing for particles ************* */
 -static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select)
 +/* stride :   offset size in bytes
 + * col[4] :   the color to use when *color is NULL, can be also NULL */
 +static void draw_vertex_array(Gwn_PrimType prim_type, const float *vert, const float *nor, const float *color, int stride, int vert_ct, float col[4])
 +{
 +      Gwn_VertFormat format = {0};
 +      unsigned int pos_id, nor_id, col_id;
 +      pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (nor) nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (color) col_id = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +      GWN_vertbuf_data_alloc(vbo, vert_ct);
 +
 +      if (stride == 0) {
 +              GWN_vertbuf_attr_fill(vbo, pos_id, vert);
 +              if (nor) GWN_vertbuf_attr_fill(vbo, nor_id, nor);
 +              if (color) GWN_vertbuf_attr_fill(vbo, col_id, color);
 +      }
 +      else {
 +              GWN_vertbuf_attr_fill_stride(vbo, pos_id, stride, vert);
 +              if (nor) GWN_vertbuf_attr_fill_stride(vbo, nor_id, stride, nor);
 +              if (color) GWN_vertbuf_attr_fill_stride(vbo, col_id, stride, color);
 +      }
 +
 +      Gwn_Batch *batch = GWN_batch_create(prim_type, vbo, NULL);
 +      if (nor && color) {
 +              Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR);
 +              GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
 +      }
 +      else if (nor) {
 +              Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
 +              GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
 +              if (col) GWN_batch_uniform_4fv(batch, "color", col);
 +      }
 +      else if (color) {
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_SMOOTH_COLOR);
 +      }
 +      else {
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +              if (col) GWN_batch_uniform_4fv(batch, "color", col);
 +      }
 +      GWN_batch_draw(batch);
 +      GWN_batch_discard_all(batch);
 +}
 +
 +static void draw_particle_arrays_new(int draw_as, int ob_dt, int select,
 +                                     const float *vert, const float *nor, const float *color,
 +                                     int totpoint, float col[4])
  {
        /* draw created data arrays */
        switch (draw_as) {
                case PART_DRAW_AXIS:
                case PART_DRAW_CROSS:
 -                      glDrawArrays(GL_LINES, 0, 6 * totpoint);
 +                      draw_vertex_array(GWN_PRIM_LINES, vert, nor, color, 0, 6 * totpoint, col);
                        break;
                case PART_DRAW_LINE:
 -                      glDrawArrays(GL_LINES, 0, 2 * totpoint);
 +                      draw_vertex_array(GWN_PRIM_LINES, vert, nor, color, 0, 2 * totpoint, col);
                        break;
                case PART_DRAW_BB:
                        if (ob_dt <= OB_WIRE || select)
                        else
                                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  
 -                      glDrawArrays(GL_QUADS, 0, 4 * totpoint);
 +                      draw_vertex_array(GWN_PRIM_TRIS, vert, nor, color, 0, 6 * totpoint, col);
                        break;
                default:
 -                      glDrawArrays(GL_POINTS, 0, totpoint);
 +                      draw_vertex_array(GWN_PRIM_POINTS, vert, nor, color, 0, totpoint, col);
                        break;
        }
  }
  static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize,
 -                          float imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd)
 +                          float imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd,
 +                          unsigned int pos)
  {
        float vec[3], vec2[3];
        float *vd = NULL;
                }
                case PART_DRAW_CIRC:
                {
 -                      drawcircball(GL_LINE_LOOP, state->co, pixsize, imat);
 +                      imm_drawcircball(state->co, pixsize, imat, pos);
                        break;
                }
                case PART_DRAW_BB:
                {
                        float xvec[3], yvec[3], zvec[3], bb_center[3];
 -                      if (cd) {
 -                              cd[0] = cd[3] = cd[6] = cd[9] = ma_col[0];
 -                              cd[1] = cd[4] = cd[7] = cd[10] = ma_col[1];
 -                              cd[2] = cd[5] = cd[8] = cd[11] = ma_col[2];
 -                              pdd->cd += 12;
 -                      }
  
                        copy_v3_v3(bb->vec, state->co);
                        copy_v3_v3(bb->vel, state->vel);
  
                        psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
 -                      
 +
 +                      /* First tri */
                        add_v3_v3v3(pdd->vd, bb_center, xvec);
                        add_v3_v3(pdd->vd, yvec); pdd->vd += 3;
  
                        sub_v3_v3v3(pdd->vd, bb_center, xvec);
                        sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
  
 +                      /* Second tri */
 +                      add_v3_v3v3(pdd->vd, bb_center, xvec);
 +                      add_v3_v3(pdd->vd, yvec); pdd->vd += 3;
 +
 +                      sub_v3_v3v3(pdd->vd, bb_center, xvec);
 +                      sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
 +
                        add_v3_v3v3(pdd->vd, bb_center, xvec);
                        sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
  
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 +                      if (cd) {
 +                              for (int i = 0; i < 6; i++, cd += 3, pdd->cd += 3) {
 +                                      copy_v3_v3(cd, ma_col);
 +                              }
 +                      }
 +                      for (int i = 0; i < 6; i++, pdd->nd += 3) {
 +                              copy_v3_v3(pdd->nd, zvec);
 +                      }
                        break;
                }
        }
  static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
                                 ParticleKey *state, int draw_as,
                                 float imat[4][4], ParticleBillboardData *bb, ParticleDrawData *pdd,
 -                               const float ct, const float pa_size, const float r_tilt, const float pixsize_scale)
 +                               const float ct, const float pa_size, const float r_tilt, const float pixsize_scale,
 +                               unsigned int pos)
  {
        ParticleSettings *part = psys->part;
        float pixsize;
  
        pixsize = ED_view3d_pixel_size(rv3d, state->co) * pixsize_scale;
  
 -      draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
 +      draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd, pos);
  }
  /* unified drawing of all new particle systems draw types except dupli ob & group
   * mostly tries to use vertex arrays for speed
@@@ -5914,11 -5018,10 +5914,11 @@@ static void draw_new_particle_system(Sc
        float cfra;
        float ma_col[3] = {0.0f, 0.0f, 0.0f};
        int a, totpart, totpoint = 0, totve = 0, drawn, draw_as, totchild = 0;
 -      bool select = (ob->flag & SELECT) != 0, create_cdata = false, need_v = false;
 +      bool select = (base->flag & BASE_SELECTED) != 0, create_cdata = false, need_v = false;
        GLint polygonmode[2];
        char numstr[32];
        unsigned char tcol[4] = {0, 0, 0, 255};
 +      unsigned int pos;
  
  /* 1. */
        if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
                copy_v3_v3(ma_col, &ma->r);
        }
  
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              glColor3ubv(tcol);
 -      }
 -
        timestep = psys_get_timestep(&sim);
  
 -      if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) {
 +      if ((ob->flag & OB_FROMGROUP) != 0) {
                float mat[4][4];
                mul_m4_m4m4(mat, ob->obmat, psys->imat);
 -              glMultMatrixf(mat);
 +              gpuMultMatrix(mat);
        }
  
        /* needed for text display */
                                tot_vec_size *= 2;
                                break;
                        case PART_DRAW_BB:
 -                              tot_vec_size *= 4;
 +                              tot_vec_size *= 6;  /* New OGL only understands tris, no choice here. */
                                create_ndata = 1;
                                break;
                }
                        totpoint = pdd->totpoint; /* draw data is up to date */
                }
                else {
 +                      if ((draw_as == PART_DRAW_CIRC) || (part->draw & PART_DRAW_SIZE)) {
 +                              pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +                              imm_cpack(0xFFFFFF);
 +                      }
                        for (a = 0, pa = pars; a < totpart + totchild; a++, pa++) {
                                /* setup per particle individual stuff */
                                if (a < totpart) {
  
                                                draw_particle_data(psys, rv3d,
                                                                   &state, draw_as, imat, &bb, psys->pdd,
 -                                                                 ct, pa_size, r_tilt, pixsize_scale);
 +                                                                 ct, pa_size, r_tilt, pixsize_scale, pos);
  
                                                totpoint++;
                                                drawn = 1;
  
                                                draw_particle_data(psys, rv3d,
                                                                   &state, draw_as, imat, &bb, psys->pdd,
 -                                                                 pa_time, pa_size, r_tilt, pixsize_scale);
 +                                                                 pa_time, pa_size, r_tilt, pixsize_scale, pos);
  
                                                totpoint++;
                                                drawn = 1;
  
                                        if (part->draw & PART_DRAW_SIZE) {
                                                setlinestyle(3);
 -                                              drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
 +                                              imm_drawcircball(state.co, pa_size, imat, pos);
                                                setlinestyle(0);
                                        }
  
                                        }
                                }
                        }
 +                      if ((draw_as == PART_DRAW_CIRC) || (part->draw & PART_DRAW_SIZE)) {
 +                              immUnbindProgram();
 +                      }
                }
        }
  /* 6. */
  
        glGetIntegerv(GL_POLYGON_MODE, polygonmode);
 -      glEnableClientState(GL_VERTEX_ARRAY);
  
        if (draw_as == PART_DRAW_PATH) {
                ParticleCacheKey **cache, *path;
                float *cdata2 = NULL;
  
 -              /* setup gl flags */
 -              if (1) { //ob_dt > OB_WIRE) {
 -                      glEnableClientState(GL_NORMAL_ARRAY);
 -
 -                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                              if (part->draw_col == PART_DRAW_COL_MAT)
 -                                      glEnableClientState(GL_COLOR_ARRAY);
 -                      }
 -
 -                      // XXX test
 -                      GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
 -                      GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
 -              }
 -
                if (totchild && (part->draw & PART_DRAW_PARENT) == 0)
                        totpart = 0;
                else if (psys->pathcache == NULL)
                for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
                        path = cache[a];
                        if (path->segments > 0) {
 -                              glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 -
 -                              if (1) { //ob_dt > OB_WIRE) {
 -                                      glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
 -                                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                                              if (part->draw_col == PART_DRAW_COL_MAT) {
 -                                                      glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
 -                                              }
 -                                      }
 +                              if (((dflag & DRAW_CONSTCOLOR) == 0) && (part->draw_col == PART_DRAW_COL_MAT)) {
 +                                      draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, path->col, sizeof(ParticleCacheKey), path->segments + 1, NULL);
 +                              }
 +                              else {
 +                                      float color[4];
 +                                      rgba_uchar_to_float(color, tcol);
 +                                      draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, NULL, sizeof(ParticleCacheKey), path->segments + 1, color);
                                }
 -
 -                              glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
                        }
                }
  
                if (part->type ==  PART_HAIR) {
                        if (part->draw & PART_DRAW_GUIDE_HAIRS) {
                                DerivedMesh *hair_dm = psys->hair_out_dm;
 -                              
 -                              glDisableClientState(GL_NORMAL_ARRAY);
 -                              glDisableClientState(GL_COLOR_ARRAY);
 -                              
 +
                                for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
                                        if (pa->totkey > 1) {
                                                HairKey *hkey = pa->hair;
                                                
 -                                              glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co);
 -
 -#if 0 /* XXX use proper theme color here */
 -                                              UI_ThemeColor(TH_NORMAL);
 -#else
 -                                              glColor3f(0.58f, 0.67f, 1.0f);
 -#endif
 -
 -                                              glDrawArrays(GL_LINE_STRIP, 0, pa->totkey);
 +                                              /* XXX use proper theme color here */
 +                                              float color[4] = {0.58f, 0.67f, 1.0f, 1.0f};
 +                                              draw_vertex_array(GWN_PRIM_LINE_STRIP, hkey->world_co, NULL, NULL, sizeof(HairKey), pa->totkey, color);
                                        }
                                }
                                
                                        MVert *mvert = hair_dm->getVertArray(hair_dm);
                                        int i;
                                        
 -                                      glColor3f(0.9f, 0.4f, 0.4f);
 -                                      
 -                                      glBegin(GL_LINES);
 +                                      unsigned int pos_id = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                                      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +                                      immUniformColor3f(0.9f, 0.4f, 0.4f);
 +
 +                                      unsigned int count = 0;
                                        for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
 -                                              for (i = 1; i < pa->totkey; ++i) {
 -                                                      float v1[3], v2[3];
 -                                                      
 -                                                      copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co);
 -                                                      copy_v3_v3(v2, mvert[pa->hair_index + i].co);
 -                                                      
 -                                                      mul_m4_v3(ob->obmat, v1);
 -                                                      mul_m4_v3(ob->obmat, v2);
 -                                                      
 -                                                      glVertex3fv(v1);
 -                                                      glVertex3fv(v2);
 +                                              count += MAX2(pa->totkey - 1, 0);
 +                                      }
 +
 +                                      if (count > 0) {
 +                                              immBegin(GWN_PRIM_LINES, count * 2);
 +                                              for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
 +                                                      for (i = 1; i < pa->totkey; ++i) {
 +                                                              float v1[3], v2[3];
 +
 +                                                              copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co);
 +                                                              copy_v3_v3(v2, mvert[pa->hair_index + i].co);
 +
 +                                                              mul_m4_v3(ob->obmat, v1);
 +                                                              mul_m4_v3(ob->obmat, v2);
 +
 +                                                              immVertex3fv(pos_id, v1);
 +                                                              immVertex3fv(pos_id, v2);
 +                                                      }
                                                }
 +                                              immEnd();
                                        }
 -                                      glEnd();
 +
 +                                      immUnbindProgram();
                                }
 -                              
 -                              glEnableClientState(GL_NORMAL_ARRAY);
 -                              if ((dflag & DRAW_CONSTCOLOR) == 0)
 -                                      if (part->draw_col == PART_DRAW_COL_MAT)
 -                                              glEnableClientState(GL_COLOR_ARRAY);
                        }
                        
                        if (part->draw & PART_DRAW_HAIR_GRID) {
                                        int *res = clmd->hair_grid_res;
                                        int i;
                                        
 -                                      glDisableClientState(GL_NORMAL_ARRAY);
 -                                      glDisableClientState(GL_COLOR_ARRAY);
 -                                      
 +                                      unsigned int pos_id = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                                      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
                                        if (select)
 -                                              UI_ThemeColor(TH_ACTIVE);
 +                                              immUniformThemeColor(TH_ACTIVE);
                                        else
 -                                              UI_ThemeColor(TH_WIRE);
 -                                      glBegin(GL_LINES);
 -                                      glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmin[2]);
 -                                      glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmin[2]);
 -                                      glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmin[2]);
 -                                      glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmin[2]);
 +                                              immUniformThemeColor(TH_WIRE);
 +
 +                                      immBegin(GWN_PRIM_LINES, 24);
 +                                      immVertex3f(pos_id, gmin[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmin[1], gmin[2]);
 +                                      immVertex3f(pos_id, gmax[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmax[1], gmin[2]);
 +                                      immVertex3f(pos_id, gmax[0], gmax[1], gmin[2]); immVertex3f(pos_id, gmin[0], gmax[1], gmin[2]);
 +                                      immVertex3f(pos_id, gmin[0], gmax[1], gmin[2]); immVertex3f(pos_id, gmin[0], gmin[1], gmin[2]);
                                        
 -                                      glVertex3f(gmin[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmin[1], gmax[2]);
 -                                      glVertex3f(gmax[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmax[1], gmax[2]);
 -                                      glVertex3f(gmax[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmax[1], gmax[2]);
 -                                      glVertex3f(gmin[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmin[1], gmax[2]);
 +                                      immVertex3f(pos_id, gmin[0], gmin[1], gmax[2]); immVertex3f(pos_id, gmax[0], gmin[1], gmax[2]);
 +                                      immVertex3f(pos_id, gmax[0], gmin[1], gmax[2]); immVertex3f(pos_id, gmax[0], gmax[1], gmax[2]);
 +                                      immVertex3f(pos_id, gmax[0], gmax[1], gmax[2]); immVertex3f(pos_id, gmin[0], gmax[1], gmax[2]);
 +                                      immVertex3f(pos_id, gmin[0], gmax[1], gmax[2]); immVertex3f(pos_id, gmin[0], gmin[1], gmax[2]);
                                        
 -                                      glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmax[2]);
 -                                      glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmax[2]);
 -                                      glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmax[2]);
 -                                      glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmax[2]);
 -                                      glEnd();
 +                                      immVertex3f(pos_id, gmin[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmin[0], gmin[1], gmax[2]);
 +                                      immVertex3f(pos_id, gmax[0], gmin[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmin[1], gmax[2]);
 +                                      immVertex3f(pos_id, gmin[0], gmax[1], gmin[2]); immVertex3f(pos_id, gmin[0], gmax[1], gmax[2]);
 +                                      immVertex3f(pos_id, gmax[0], gmax[1], gmin[2]); immVertex3f(pos_id, gmax[0], gmax[1], gmax[2]);
 +                                      immEnd();
                                        
                                        if (select)
 -                                              UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100);
 +                                              immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -100);
                                        else
 -                                              UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100);
 -                                      glEnable(GL_BLEND);
 -                                      glBegin(GL_LINES);
 -                                      for (i = 1; i < res[0] - 1; ++i) {
 -                                              float f = interpf(gmax[0], gmin[0], (float)i / (float)(res[0] - 1));
 -                                              glVertex3f(f, gmin[1], gmin[2]); glVertex3f(f, gmax[1], gmin[2]);
 -                                              glVertex3f(f, gmax[1], gmin[2]); glVertex3f(f, gmax[1], gmax[2]);
 -                                              glVertex3f(f, gmax[1], gmax[2]); glVertex3f(f, gmin[1], gmax[2]);
 -                                              glVertex3f(f, gmin[1], gmax[2]); glVertex3f(f, gmin[1], gmin[2]);
 -                                      }
 -                                      for (i = 1; i < res[1] - 1; ++i) {
 -                                              float f = interpf(gmax[1], gmin[1], (float)i / (float)(res[1] - 1));
 -                                              glVertex3f(gmin[0], f, gmin[2]); glVertex3f(gmax[0], f, gmin[2]);
 -                                              glVertex3f(gmax[0], f, gmin[2]); glVertex3f(gmax[0], f, gmax[2]);
 -                                              glVertex3f(gmax[0], f, gmax[2]); glVertex3f(gmin[0], f, gmax[2]);
 -                                              glVertex3f(gmin[0], f, gmax[2]); glVertex3f(gmin[0], f, gmin[2]);
 -                                      }
 -                                      for (i = 1; i < res[2] - 1; ++i) {
 -                                              float f = interpf(gmax[2], gmin[2], (float)i / (float)(res[2] - 1));
 -                                              glVertex3f(gmin[0], gmin[1], f); glVertex3f(gmax[0], gmin[1], f);
 -                                              glVertex3f(gmax[0], gmin[1], f); glVertex3f(gmax[0], gmax[1], f);
 -                                              glVertex3f(gmax[0], gmax[1], f); glVertex3f(gmin[0], gmax[1], f);
 -                                              glVertex3f(gmin[0], gmax[1], f); glVertex3f(gmin[0], gmin[1], f);
 +                                              immUniformThemeColorShadeAlpha(TH_WIRE, 0, -100);
 +
 +                                      int count = 0;
 +                                      count += MAX2(0, res[0] - 2) * 8;
 +                                      count += MAX2(0, res[1] - 2) * 8;
 +                                      count += MAX2(0, res[2] - 2) * 8;
 +
 +                                      if (count >= 2) {
 +                                              glEnable(GL_BLEND);
 +                                              immBegin(GWN_PRIM_LINES, count);
 +                                              for (i = 1; i < res[0] - 1; ++i) {
 +                                                      float f = interpf(gmax[0], gmin[0], (float)i / (float)(res[0] - 1));
 +                                                      immVertex3f(pos_id, f, gmin[1], gmin[2]); immVertex3f(pos_id, f, gmax[1], gmin[2]);
 +                                                      immVertex3f(pos_id, f, gmax[1], gmin[2]); immVertex3f(pos_id, f, gmax[1], gmax[2]);
 +                                                      immVertex3f(pos_id, f, gmax[1], gmax[2]); immVertex3f(pos_id, f, gmin[1], gmax[2]);
 +                                                      immVertex3f(pos_id, f, gmin[1], gmax[2]); immVertex3f(pos_id, f, gmin[1], gmin[2]);
 +                                              }
 +                                              for (i = 1; i < res[1] - 1; ++i) {
 +                                                      float f = interpf(gmax[1], gmin[1], (float)i / (float)(res[1] - 1));
 +                                                      immVertex3f(pos_id, gmin[0], f, gmin[2]); immVertex3f(pos_id, gmax[0], f, gmin[2]);
 +                                                      immVertex3f(pos_id, gmax[0], f, gmin[2]); immVertex3f(pos_id, gmax[0], f, gmax[2]);
 +                                                      immVertex3f(pos_id, gmax[0], f, gmax[2]); immVertex3f(pos_id, gmin[0], f, gmax[2]);
 +                                                      immVertex3f(pos_id, gmin[0], f, gmax[2]); immVertex3f(pos_id, gmin[0], f, gmin[2]);
 +                                              }
 +                                              for (i = 1; i < res[2] - 1; ++i) {
 +                                                      float f = interpf(gmax[2], gmin[2], (float)i / (float)(res[2] - 1));
 +                                                      immVertex3f(pos_id, gmin[0], gmin[1], f); immVertex3f(pos_id, gmax[0], gmin[1], f);
 +                                                      immVertex3f(pos_id, gmax[0], gmin[1], f); immVertex3f(pos_id, gmax[0], gmax[1], f);
 +                                                      immVertex3f(pos_id, gmax[0], gmax[1], f); immVertex3f(pos_id, gmin[0], gmax[1], f);
 +                                                      immVertex3f(pos_id, gmin[0], gmax[1], f); immVertex3f(pos_id, gmin[0], gmin[1], f);
 +                                              }
 +                                              immEnd();
 +                                              glDisable(GL_BLEND);
                                        }
 -                                      glEnd();
 -                                      glDisable(GL_BLEND);
 -                                      
 -                                      glEnableClientState(GL_NORMAL_ARRAY);
 -                                      if ((dflag & DRAW_CONSTCOLOR) == 0)
 -                                              if (part->draw_col == PART_DRAW_COL_MAT)
 -                                                      glEnableClientState(GL_COLOR_ARRAY);
 +
 +                                      immUnbindProgram();
                                }
                        }
                }
                cache = psys->childcache;
                for (a = 0; a < totchild; a++) {
                        path = cache[a];
 -                      glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
  
 -                      if (1) { //ob_dt > OB_WIRE) {
 -                              glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
 -                              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                                      if (part->draw_col == PART_DRAW_COL_MAT) {
 -                                              glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
 -                                      }
 -                              }
 +                      if (((dflag & DRAW_CONSTCOLOR) == 0) && (part->draw_col == PART_DRAW_COL_MAT)) {
 +                              draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, path->col, sizeof(ParticleCacheKey), path->segments + 1, NULL);
 +                      }
 +                      else {
 +                              float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
 +                              draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, NULL, sizeof(ParticleCacheKey), path->segments + 1, color);
                        }
 -
 -                      glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
                }
  
                /* restore & clean up */
 -              if (1) { //ob_dt > OB_WIRE) {
 -                      if (part->draw_col == PART_DRAW_COL_MAT)
 -                              glDisableClientState(GL_COLOR_ARRAY);
 -                      GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
 -              }
 -
                if (cdata2) {
                        MEM_freeN(cdata2);
                        cdata2 = NULL;
                }
        }
        else if (pdd && ELEM(draw_as, 0, PART_DRAW_CIRC) == 0) {
 -              glDisableClientState(GL_COLOR_ARRAY);
  
 -              /* enable point data array */
                if (pdd->vdata) {
 -                      glEnableClientState(GL_VERTEX_ARRAY);
 -                      glVertexPointer(3, GL_FLOAT, 0, pdd->vdata);
 -              }
 -              else
 -                      glDisableClientState(GL_VERTEX_ARRAY);
 -
 -              if ((dflag & DRAW_CONSTCOLOR) == 0) {
                        if (select) {
 -                              UI_ThemeColor(TH_ACTIVE);
 +                              float color[4];
 +                              UI_GetThemeColor4fv(TH_ACTIVE, color);
  
                                if (part->draw_size)
                                        glPointSize(part->draw_size + 2);
  
                                glLineWidth(3.0);
  
 -                              draw_particle_arrays(draw_as, totpoint, ob_dt, 1);
 +                              draw_particle_arrays_new(draw_as, ob_dt, 1, pdd->vdata, NULL, NULL, totpoint, color);
                        }
  
 -                      /* restore from select */
 -                      glColor3fv(ma_col);
 -              }
 -
 -              glPointSize(part->draw_size ? part->draw_size : 2.0);
 -              glLineWidth(1.0);
 +                      glPointSize(part->draw_size ? part->draw_size : 2.0);
 +                      glLineWidth(1.0);
  
 -              /* enable other data arrays */
  
 -              /* billboards are drawn this way */
 -              if (pdd->ndata && ob_dt > OB_WIRE) {
 -                      glEnableClientState(GL_NORMAL_ARRAY);
 -                      glNormalPointer(GL_FLOAT, 0, pdd->ndata);
 -                      GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
 -                      GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
 -              }
 -
 -              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                      if (pdd->cdata) {
 -                              glEnableClientState(GL_COLOR_ARRAY);
 -                              glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
 +#if 0
 +                      /* enable other data arrays */
 +                      /* billboards are drawn this way */
 +                      if (pdd->ndata && ob_dt > OB_WIRE) {
 +                              GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
 +                              GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
 +                      }
 +                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                              if (pdd->cdata) {
 +                                      glEnableClientState(GL_COLOR_ARRAY);
 +                                      glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
 +                              }
                        }
 +#endif
 +
 +                      draw_particle_arrays_new(draw_as, ob_dt, 0, pdd->vdata, pdd->ndata, pdd->cdata, totpoint, NULL);
                }
  
 -              draw_particle_arrays(draw_as, totpoint, ob_dt, 0);
  
                pdd->flag |= PARTICLE_DRAW_DATA_UPDATED;
                pdd->totpoint = totpoint;
        }
  
        if (pdd && pdd->vedata) {
 -              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                      glDisableClientState(GL_COLOR_ARRAY);
 -                      cpack(0xC0C0C0);
 -              }
 -              
 -              glVertexPointer(3, GL_FLOAT, 0, pdd->vedata);
 -              
 -              glDrawArrays(GL_LINES, 0, 2 * totve);
 +              float color[4] = {0.75f, 0.75f, 0.75f, 1.0f};
 +              draw_vertex_array(GWN_PRIM_LINES, pdd->vedata, NULL, NULL, 0, 2 * totve, color);
        }
  
        glPolygonMode(GL_FRONT, polygonmode[0]);
  /* 7. */
        
        GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
 -      glDisableClientState(GL_COLOR_ARRAY);
 -      glDisableClientState(GL_VERTEX_ARRAY);
 -      glDisableClientState(GL_NORMAL_ARRAY);
  
        if (states)
                MEM_freeN(states);
                pdd->ma_col = NULL;
        }
  
 -      if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) {
 -              glLoadMatrixf(rv3d->viewmat);
 +      if ((ob->flag & OB_FROMGROUP) != 0) {
 +              gpuLoadMatrix(rv3d->viewmat);
        }
  }
  
 -static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit)
 +static void draw_update_ptcache_edit(Scene *scene, SceneLayer *sl, Object *ob, PTCacheEdit *edit)
  {
        if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED)
 -              PE_update_object(scene, ob, 0);
 +              PE_update_object(scene, sl, ob, 0);
  
        /* create path and child path cache if it doesn't exist already */
        if (edit->pathcache == NULL)
  
  static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
  {
 -      ParticleCacheKey **cache, *path, *pkey;
 -      PTCacheEditPoint *point;
 -      PTCacheEditKey *key;
        ParticleEditSettings *pset = PE_settings(scene);
 -      int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0;
 -      int totkeys = 1;
 -      float sel_col[3];
 -      float nosel_col[3];
 -      float *pathcol = NULL, *pcol;
 +      const int totpoint = edit->totpoint;
 +      const bool timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : false;
  
        if (edit->pathcache == NULL)
                return;
                glDisable(GL_DEPTH_TEST);
  
        /* get selection theme colors */
 +      float sel_col[3], nosel_col[3];
        UI_GetThemeColor3fv(TH_VERTEX_SELECT, sel_col);
        UI_GetThemeColor3fv(TH_VERTEX, nosel_col);
  
        /* draw paths */
 -      totkeys = (*edit->pathcache)->segments + 1;
 +      const int totkeys = (*edit->pathcache)->segments + 1;
  
        glEnable(GL_BLEND);
 -      pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data");
 -
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glEnableClientState(GL_COLOR_ARRAY);
 +      float *pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data");
  
        if (pset->brushtype == PE_BRUSH_WEIGHT)
                glLineWidth(2.0f);
  
 -      cache = edit->pathcache;
 +      ParticleCacheKey **cache = edit->pathcache;
 +      PTCacheEditPoint *point;
 +      int i;
 +
        for (i = 0, point = edit->points; i < totpoint; i++, point++) {
 -              path = cache[i];
 -              glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 +              ParticleCacheKey *path = cache[i];
 +
 +              Gwn_VertFormat format = {0};
 +              unsigned int pos_id, col_id, col_comp;
 +
 +              col_comp = ((point->flag & PEP_HIDE) || timed) ? 4 : 3;
 +
 +              pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              col_id = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, col_comp, GWN_FETCH_FLOAT);
 +
 +              Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +              GWN_vertbuf_data_alloc(vbo, path->segments + 1);
 +
 +              GWN_vertbuf_attr_fill_stride(vbo, pos_id, sizeof(ParticleCacheKey), path->co);
 +
 +              float *pcol = pathcol;
  
                if (point->flag & PEP_HIDE) {
 -                      for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) {
 +                      for (int k = 0; k < totkeys; k++, pcol += 4) {
                                copy_v3_v3(pcol, path->col);
                                pcol[3] = 0.25f;
                        }
  
 -                      glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol);
 +                      GWN_vertbuf_attr_fill(vbo, col_id, pathcol);
                }
                else if (timed) {
 -                      for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) {
 +                      ParticleCacheKey *pkey = path;
 +                      for (int k = 0; k < totkeys; k++, pkey++, pcol += 4) {
                                copy_v3_v3(pcol, pkey->col);
                                pcol[3] = 1.0f - fabsf((float)(CFRA) -pkey->time) / (float)pset->fade_frames;
                        }
  
 -                      glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol);
 +                      GWN_vertbuf_attr_fill(vbo, col_id, pathcol);
 +              }
 +              else {
 +                      /* FIXME: shader wants 4 color components but the cache only contains ParticleCacheKey
 +                       * So alpha is random */
 +                      GWN_vertbuf_attr_fill_stride(vbo, col_id, sizeof(ParticleCacheKey), path->col);
                }
 -              else
 -                      glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
  
 -              glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
 +              Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_LINE_STRIP, vbo, NULL);
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_SMOOTH_COLOR);
 +              GWN_batch_draw(batch);
 +              GWN_batch_discard_all(batch);
        }
  
 -      if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; }
 -
 +      if (pathcol) { MEM_freeN(pathcol); pathcol = NULL; }
  
        /* draw edit vertices */
        if (pset->selectmode != SCE_SELECT_PATH) {
                        float *cd = NULL, *cdata = NULL;
                        int totkeys_visible = 0;
  
 +                      Gwn_VertFormat format = {0};
 +                      unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                      unsigned int col_id = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, (timed ? 4 : 3), GWN_FETCH_FLOAT);
 +
                        for (i = 0, point = edit->points; i < totpoint; i++, point++)
                                if (!(point->flag & PEP_HIDE))
                                        totkeys_visible += point->totkey;
                                if (point->flag & PEP_HIDE)
                                        continue;
  
 -                              for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
 +                              PTCacheEditKey *key = point->keys;
 +                              for (int k = 0; k < point->totkey; k++, key++) {
                                        if (pd) {
                                                copy_v3_v3(pd, key->co);
                                                pd += 3;
                                if (point->flag & PEP_HIDE || point->totkey == 0)
                                        continue;
  
 +                              Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +                              GWN_vertbuf_data_alloc(vbo, point->totkey);
 +
                                if (point->keys->flag & PEK_USE_WCO)
 -                                      glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co);
 +                                      GWN_vertbuf_attr_fill_stride(vbo, pos_id, sizeof(PTCacheEditKey), point->keys->world_co);
                                else
 -                                      glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), pd);
 +                                      GWN_vertbuf_attr_fill(vbo, pos_id, pd);
  
 -                              glColorPointer((timed ? 4 : 3), GL_FLOAT, (timed ? 4 : 3) * sizeof(float), cd);
 +                              GWN_vertbuf_attr_fill(vbo, col_id, cd);
  
 -                              glDrawArrays(GL_POINTS, 0, point->totkey);
 +                              Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_POINTS, vbo, NULL);
 +                              Batch_set_builtin_program(batch, GPU_SHADER_3D_SMOOTH_COLOR);
 +                              GWN_batch_draw(batch);
 +                              GWN_batch_discard_all(batch);
  
                                pd += pd ? 3 * point->totkey : 0;
                                cd += (timed ? 4 : 3) * point->totkey;
                        if (cdata) { MEM_freeN(cdata); cd = cdata = NULL; }
                }
                else if (pset->selectmode == SCE_SELECT_END) {
 -                      glBegin(GL_POINTS);
 +                      Gwn_VertFormat *format = immVertexFormat();
 +                      unsigned int pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                      unsigned int col_id = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +                      immBeginAtMost(GWN_PRIM_POINTS, totpoint);
                        for (i = 0, point = edit->points; i < totpoint; i++, point++) {
                                if ((point->flag & PEP_HIDE) == 0 && point->totkey) {
 -                                      key = point->keys + point->totkey - 1;
 -                                      glColor3fv((key->flag & PEK_SELECT) ? sel_col : nosel_col);
 +                                      PTCacheEditKey *key = point->keys + point->totkey - 1;
 +                                      if ((key->flag & PEK_SELECT) != 0) {
 +                                              immAttrib3fv(col_id, sel_col);
 +                                      }
 +                                      else {
 +                                              immAttrib3fv(col_id, nosel_col);
 +                                      }
                                        /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
 -                                      glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co);
 +                                      immVertex3fv(pos_id, (key->flag & PEK_USE_WCO) ? key->world_co : key->co);
                                }
                        }
 -                      glEnd();
 +                      immEnd();
 +                      immUnbindProgram();
                }
        }
  
        glDisable(GL_BLEND);
 -      glDisableClientState(GL_COLOR_ARRAY);
 -      glDisableClientState(GL_NORMAL_ARRAY);
 -      glDisableClientState(GL_VERTEX_ARRAY);
        if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
  }
  
@@@ -6782,137 -5895,130 +6782,137 @@@ static void ob_draw_RE_motion(float com
        float tw = itw * drw_size;
        float th = ith * drw_size;
  
 -      glBegin(GL_LINES);
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
  
 -      glColor4ub(0x7F, 0x00, 0x00, 155);
 +      immBegin(GWN_PRIM_LINES, 30);
 +
 +      immAttrib4ub(col, 0x7F, 0x00, 0x00, 155);
        root[1] = root[2] = 0.0f;
        root[0] = -drw_size;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 +      immVertex3fv(pos, root);
        tip[1] = tip[2] = 0.0f;
        tip[0] = drw_size;
        mul_m3_v3(tr, tip);
        add_v3_v3(tip, com);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, tip);
  
        root[1] = 0.0f; root[2] = tw;
        root[0] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[1] = 0.0f; root[2] = -tw;
        root[0] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[1] = tw; root[2] = 0.0f;
        root[0] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[1] = -tw; root[2] = 0.0f;
        root[0] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
 -      glColor4ub(0x00, 0x7F, 0x00, 155);
 +      immAttrib4ub(col, 0x00, 0x7F, 0x00, 155);
  
        root[0] = root[2] = 0.0f;
        root[1] = -drw_size;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 +      immVertex3fv(pos, root);
        tip[0] = tip[2] = 0.0f;
        tip[1] = drw_size;
        mul_m3_v3(tr, tip);
        add_v3_v3(tip, com);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, tip);
  
        root[0] = 0.0f; root[2] = tw;
        root[1] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[0] = 0.0f; root[2] = -tw;
        root[1] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[0] = tw; root[2] = 0.0f;
        root[1] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[0] = -tw; root[2] = 0.0f;
        root[1] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
 -      glColor4ub(0x00, 0x00, 0x7F, 155);
 +      immAttrib4ub(col, 0x00, 0x00, 0x7F, 155);
        root[0] = root[1] = 0.0f;
        root[2] = -drw_size;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 +      immVertex3fv(pos, root);
        tip[0] = tip[1] = 0.0f;
        tip[2] = drw_size;
        mul_m3_v3(tr, tip);
        add_v3_v3(tip, com);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, tip);
  
        root[0] = 0.0f; root[1] = tw;
        root[2] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[0] = 0.0f; root[1] = -tw;
        root[2] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[0] = tw; root[1] = 0.0f;
        root[2] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
  
        root[0] = -tw; root[1] = 0.0f;
        root[2] = th;
        mul_m3_v3(tr, root);
        add_v3_v3(root, com);
 -      glVertex3fv(root);
 -      glVertex3fv(tip);
 +      immVertex3fv(pos, root);
 +      immVertex3fv(pos, tip);
 +
 +      immEnd();
  
 -      glEnd();
 +      immUnbindProgram();
  }
  
  /* place to add drawers */
@@@ -6921,7 -6027,7 +6921,7 @@@ static void drawhandlesN(Nurb *nu, cons
  {
        if (nu->hide || hide_handles) return;
  
 -      if (nu->type == CU_BEZIER) {
 +      if (nu->type == CU_BEZIER && nu->pntsu > 0) {
  
                const float *fp;
  
                        UI_GetThemeColor3ubv(basecol + a, handle_cols[a]);
                }
  
 +              Gwn_VertFormat *format = immVertexFormat();
 +              unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +
                glLineWidth(1.0f);
  
 -              glBegin(GL_LINES);
 +              immBeginAtMost(GWN_PRIM_LINES, nu->pntsu * 4);
  
                BezTriple *bezt = nu->bezt;
                int a = nu->pntsu;
                                if ((bezt->f2 & SELECT) == sel) {
                                        fp = bezt->vec[0];
  
 -                                      glColor3ubv(handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
 -                                      glVertex3fv(fp);
 -                                      glVertex3fv(fp + 3);
 +                                      immAttrib3ubv(col, handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
 +                                      immVertex3fv(pos, fp);
 +                                      immVertex3fv(pos, fp + 3);
  
 -                                      glColor3ubv(handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
 -                                      glVertex3fv(fp + 3);
 -                                      glVertex3fv(fp + 6);
 +                                      immAttrib3ubv(col, handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
 +                                      immVertex3fv(pos, fp + 3);
 +                                      immVertex3fv(pos, fp + 6);
                                }
                                else if ((bezt->f1 & SELECT) == sel) {
                                        fp = bezt->vec[0];
  
 -                                      glColor3ubv(handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
 -                                      glVertex3fv(fp);
 -                                      glVertex3fv(fp + 3);
 +                                      immAttrib3ubv(col, handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]);
 +                                      immVertex3fv(pos, fp);
 +                                      immVertex3fv(pos, fp + 3);
                                }
                                else if ((bezt->f3 & SELECT) == sel) {
                                        fp = bezt->vec[1];
  
 -                                      glColor3ubv(handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
 -                                      glVertex3fv(fp);
 -                                      glVertex3fv(fp + 3);
 +                                      immAttrib3ubv(col, handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]);
 +                                      immVertex3fv(pos, fp);
 +                                      immVertex3fv(pos, fp + 3);
                                }
                        }
                        bezt++;
                }
  
 -              glEnd();
 +              immEnd();
 +
 +              immUnbindProgram();
  
  #undef TH_HANDLE_COL_TOT
  
@@@ -6989,196 -6088,153 +6989,196 @@@ static void drawhandlesN_active(Nurb *n
  {
        if (nu->hide) return;
  
 -      UI_ThemeColor(TH_ACTIVE_SPLINE);
 -      glLineWidth(2);
 -
 -      glBegin(GL_LINES);
 +      if (nu->type == CU_BEZIER && nu->pntsu > 0) {
 +              unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformThemeColor(TH_ACTIVE_SPLINE);
 +              glLineWidth(2.0f);
  
 -      if (nu->type == CU_BEZIER) {
 +              immBeginAtMost(GWN_PRIM_LINES, nu->pntsu * 4);
                BezTriple *bezt = nu->bezt;
                int a = nu->pntsu;
                while (a--) {
                        if (bezt->hide == 0) {
                                const float *fp = bezt->vec[0];
  
 -                              glVertex3fv(fp);
 -                              glVertex3fv(fp + 3);
 +                              immVertex3fv(pos, fp);
 +                              immVertex3fv(pos, fp + 3);
  
 -                              glVertex3fv(fp + 3);
 -                              glVertex3fv(fp + 6);
 +                              immVertex3fv(pos, fp + 3);
 +                              immVertex3fv(pos, fp + 6);
                        }
                        bezt++;
                }
 +              immEnd();
 +              immUnbindProgram();
        }
 -      glEnd();
 -
 -      glColor3ub(0, 0, 0);
  }
  
 -static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const void *vert)
 +static void drawvertsN(const Nurb *nurb, const bool hide_handles, const void *vert)
  {
 -      if (nu->hide) return;
 +      const Nurb *nu;
 +
 +      // just quick guesstimate of how many verts to draw
 +      int count = 0;
 +      for (nu = nurb; nu; nu = nu->next) {
 +              if (!nu->hide) {
 +                      if (nu->type == CU_BEZIER) {
 +                              count += nu->pntsu * 3;
 +                      }
 +                      else {
 +                              count += nu->pntsu * nu->pntsv;
 +                      }
 +              }
 +      }
 +      if (count == 0) return;
  
 -      const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
  
 -      UI_ThemeColor(color);
 +      unsigned char vert_color[3];
 +      unsigned char vert_color_select[3];
 +      unsigned char vert_color_active[3];
 +      UI_GetThemeColor3ubv(TH_VERTEX, vert_color);
 +      UI_GetThemeColor3ubv(TH_VERTEX_SELECT, vert_color_select);
 +      UI_GetThemeColor3ubv(TH_ACTIVE_VERT, vert_color_active);
  
        glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 +
 +      immBeginAtMost(GWN_PRIM_POINTS, count);
        
 -      glBegin(GL_POINTS);
 -      
 -      if (nu->type == CU_BEZIER) {
 +      for (nu = nurb; nu; nu = nu->next) {
  
 -              BezTriple *bezt = nu->bezt;
 -              int a = nu->pntsu;
 -              while (a--) {
 -                      if (bezt->hide == 0) {
 -                              if (sel == 1 && bezt == vert) {
 -                                      UI_ThemeColor(TH_ACTIVE_VERT);
 +              if (nu->hide) continue;
  
 -                                      if (bezt->f2 & SELECT) glVertex3fv(bezt->vec[1]);
 -                                      if (!hide_handles) {
 -                                              if (bezt->f1 & SELECT) glVertex3fv(bezt->vec[0]);
 -                                              if (bezt->f3 & SELECT) glVertex3fv(bezt->vec[2]);
 -                                      }
 +              if (nu->type == CU_BEZIER) {
  
 -                                      UI_ThemeColor(color);
 -                              }
 -                              else if (hide_handles) {
 -                                      if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]);
 -                              }
 -                              else {
 -                                      if ((bezt->f1 & SELECT) == sel) glVertex3fv(bezt->vec[0]);
 -                                      if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]);
 -                                      if ((bezt->f3 & SELECT) == sel) glVertex3fv(bezt->vec[2]);
 +                      const BezTriple *bezt = nu->bezt;
 +                      int a = nu->pntsu;
 +                      while (a--) {
 +                              if (bezt->hide == 0) {
 +                                      if (bezt == vert) {
 +                                              immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_active : vert_color);
 +                                              immVertex3fv(pos, bezt->vec[1]);
 +                                              if (!hide_handles) {
 +                                                      immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_active : vert_color);
 +                                                      immVertex3fv(pos, bezt->vec[0]);
 +                                                      immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_active : vert_color);
 +                                                      immVertex3fv(pos, bezt->vec[2]);
 +                                              }
 +                                      }
 +                                      else {
 +                                              immAttrib3ubv(color, bezt->f2 & SELECT ? vert_color_select : vert_color);
 +                                              immVertex3fv(pos, bezt->vec[1]);
 +                                              if (!hide_handles) {
 +                                                      immAttrib3ubv(color, bezt->f1 & SELECT ? vert_color_select : vert_color);
 +                                                      immVertex3fv(pos, bezt->vec[0]);
 +                                                      immAttrib3ubv(color, bezt->f3 & SELECT ? vert_color_select : vert_color);
 +                                                      immVertex3fv(pos, bezt->vec[2]);
 +                                              }
 +                                      }
                                }
 +                              bezt++;
                        }
 -                      bezt++;
                }
 -      }
 -      else {
 -              BPoint *bp = nu->bp;
 -              int a = nu->pntsu * nu->pntsv;
 -              while (a--) {
 -                      if (bp->hide == 0) {
 -                              if (bp == vert) {
 -                                      UI_ThemeColor(TH_ACTIVE_VERT);
 -                                      glVertex3fv(bp->vec);
 -                                      UI_ThemeColor(color);
 -                              }
 -                              else {
 -                                      if ((bp->f1 & SELECT) == sel) glVertex3fv(bp->vec);
 +              else {
 +                      const BPoint *bp = nu->bp;
 +                      int a = nu->pntsu * nu->pntsv;
 +                      while (a--) {
 +                              if (bp->hide == 0) {
 +                                      if (bp == vert) {
 +                                              immAttrib3ubv(color, vert_color_active);
 +                                      }
 +                                      else {
 +                                              immAttrib3ubv(color, bp->f1 & SELECT ? vert_color_select : vert_color);
 +                                      }
 +                                      immVertex3fv(pos, bp->vec);
                                }
 +                              bp++;
                        }
 -                      bp++;
                }
        }
 -      
 -      glEnd();
 +
 +      immEnd();
 +      immUnbindProgram();
  }
  
  static void editnurb_draw_active_poly(Nurb *nu)
  {
 -      UI_ThemeColor(TH_ACTIVE_SPLINE);
 -      glLineWidth(2);
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformThemeColor(TH_ACTIVE_SPLINE);
 +
 +      glLineWidth(2.0f);
  
        BPoint *bp = nu->bp;
        for (int b = 0; b < nu->pntsv; b++) {
 -              if (nu->flagu & 1) glBegin(GL_LINE_LOOP);
 -              else glBegin(GL_LINE_STRIP);
 +              if (nu->pntsu >= 2) {
 +                      if (nu->flagu & 1) immBegin(GWN_PRIM_LINE_LOOP, nu->pntsu);
 +                      else immBegin(GWN_PRIM_LINE_STRIP, nu->pntsu);
  
 -              for (int a = 0; a < nu->pntsu; a++, bp++) {
 -                      glVertex3fv(bp->vec);
 -              }
 +                      for (int a = 0; a < nu->pntsu; a++, bp++) {
 +                              immVertex3fv(pos, bp->vec);
 +                      }
  
 -              glEnd();
 +                      immEnd();
 +              }
        }
  
 -      glColor3ub(0, 0, 0);
 +      immUnbindProgram();
  }
  
  static void editnurb_draw_active_nurbs(Nurb *nu)
  {
 -      UI_ThemeColor(TH_ACTIVE_SPLINE);
 -      glLineWidth(2);
 +      if (nu->pntsv > 0) {
 +              Gwn_VertFormat *format = immVertexFormat();
 +              unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformThemeColor(TH_ACTIVE_SPLINE);
  
 -      glBegin(GL_LINES);
 -      BPoint *bp = nu->bp;
 -      for (int b = 0; b < nu->pntsv; b++) {
 -              BPoint *bp1 = bp;
 -              bp++;
 -
 -              for (int a = nu->pntsu - 1; a > 0; a--, bp++) {
 -                      if (bp->hide == 0 && bp1->hide == 0) {
 -                              glVertex3fv(bp->vec);
 -                              glVertex3fv(bp1->vec);
 -                      }
 -                      bp1 = bp;
 -              }
 -      }
 +              glLineWidth(2.0f);
 +              // just quick guesstimate of how many verts to draw
 +              int count = (nu->pntsu - 1) * nu->pntsv * 2;
 +              if (nu->pntsv > 1) count += (nu->pntsv - 1) * nu->pntsu * 2;
 +              if (count < 2) return;
  
 -      if (nu->pntsv > 1) {    /* surface */
 +              immBeginAtMost(GWN_PRIM_LINES, count);
 +              BPoint *bp = nu->bp;
 +              for (int b = 0; b < nu->pntsv; b++) {
 +                      BPoint *bp1 = bp;
 +                      bp++;
  
 -              int ofs = nu->pntsu;
 -              for (int b = 0; b < nu->pntsu; b++) {
 -                      BPoint *bp1 = nu->bp + b;
 -                      bp = bp1 + ofs;
 -                      for (int a = nu->pntsv - 1; a > 0; a--, bp += ofs) {
 +                      for (int a = nu->pntsu - 1; a > 0; a--, bp++) {
                                if (bp->hide == 0 && bp1->hide == 0) {
 -                                      glVertex3fv(bp->vec);
 -                                      glVertex3fv(bp1->vec);
 +                                      immVertex3fv(pos, bp->vec);
 +                                      immVertex3fv(pos, bp1->vec);
                                }
                                bp1 = bp;
                        }
                }
 -      }
  
 -      glEnd();
 +              if (nu->pntsv > 1) {    /* surface */
 +                      int ofs = nu->pntsu;
 +                      for (int b = 0; b < nu->pntsu; b++) {
 +                              BPoint *bp1 = nu->bp + b;
 +                              bp = bp1 + ofs;
 +                              for (int a = nu->pntsv - 1; a > 0; a--, bp += ofs) {
 +                                      if (bp->hide == 0 && bp1->hide == 0) {
 +                                              immVertex3fv(pos, bp->vec);
 +                                              immVertex3fv(pos, bp1->vec);
 +                                      }
 +                                      bp1 = bp;
 +                              }
 +                      }
 +              }
 +
 +              immEnd();
  
 -      glColor3ub(0, 0, 0);
 +              immUnbindProgram();
 +      }
  }
  
  static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
        BPoint *bp, *bp1;
        int a, b;
        Curve *cu = ob->data;
 +      Gwn_VertFormat *format;
 +      unsigned int pos, col;
 +      unsigned char color[3];
  
        int index = 0;
        Nurb *nu = nurb;
                if (nu->hide == 0) {
                        switch (nu->type) {
                                case CU_POLY:
 +                              {
                                        if (!sel && index == cu->actnu) {
                                                /* we should draw active spline highlight below everything */
                                                editnurb_draw_active_poly(nu);
                                        }
  
 -                                      glLineWidth(1);
 +                                      format = immVertexFormat();
 +                                      pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                                      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);