Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_view3d / drawobject.c
index c3823627009cc98c06911d27c887e0f5c0b74bdc..75c217c4f0cb022ff1887e2f8535f09ad1c97cb2 100644 (file)
@@ -54,6 +54,7 @@
 #include "BKE_camera.h"
 #include "BKE_colortools.h"
 #include "BKE_constraint.h"  /* for the get_constraint_target function */
+#include "BKE_context.h"
 #include "BKE_curve.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_deform.h"
@@ -62,6 +63,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"
@@ -80,6 +82,8 @@
 
 #include "BKE_editmesh.h"
 
+#include "DEG_depsgraph.h"
+
 #include "IMB_imbuf.h"
 #include "IMB_imbuf_types.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);
+
+// #define USE_MESH_DM_SELECT
+
 /* Workaround for sequencer scene render mode.
  *
  * Strips doesn't use DAG to update objects or so, which
@@ -129,6 +144,7 @@ typedef struct drawDMVerts_userData {
 
        BMVert *eve_act;
        char sel;
+       unsigned int pos, color;
 
        /* cached theme values */
        unsigned char th_editmesh_active[4];
@@ -181,6 +197,7 @@ typedef struct drawDMFacesSel_userData {
 } drawDMFacesSel_userData;
 
 typedef struct drawDMNormal_userData {
+       unsigned int pos;
        BMesh *bm;
        int uniform_scale;
        float normalsize;
@@ -189,6 +206,7 @@ typedef struct drawDMNormal_userData {
 } drawDMNormal_userData;
 
 typedef struct drawMVertOffset_userData {
+       unsigned int pos, col;
        MVert *mvert;
        int offset;
 } drawMVertOffset_userData;
@@ -196,9 +214,11 @@ typedef struct 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;
@@ -206,25 +226,23 @@ typedef struct 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)
@@ -296,13 +314,15 @@ static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
 
 /* check for glsl drawing */
 
-bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
+bool draw_glsl_material(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer,
+        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(view_layer) && (ob && eval_ctx->object_mode & OB_MODE_WEIGHT_PAINT))
                return false;
        
        if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
@@ -316,16 +336,17 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
                return false;
 }
 
-static bool check_alpha_pass(Base *base)
+static bool check_alpha_pass(const EvaluationContext *eval_ctx, Base *base)
 {
-       if (base->flag & OB_FROMDUPLI)
+       if (base->flag_legacy & OB_FROMDUPLI)
                return false;
 
        if (G.f & G_PICKSEL)
                return false;
 
-       if (base->object->mode & OB_MODE_ALL_PAINT)
+       if (eval_ctx->object_mode & OB_MODE_ALL_PAINT) {
                return false;
+       }
 
        return (base->object->dtx & OB_DRAWTRANSP);
 }
@@ -414,9 +435,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;
 
@@ -429,8 +450,6 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
 
        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);
@@ -450,8 +469,6 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
 
                        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);
@@ -472,7 +489,7 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
                        
                        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);
@@ -501,54 +518,60 @@ static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3]
                        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);
 
-       switch (drawtype) {
+       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;
@@ -564,28 +587,27 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
                                        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:
@@ -599,34 +621,34 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
                        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();
 }
 
 
@@ -634,38 +656,39 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
 static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], eStereoViews 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;
+
+               /* Support multi-view */
+               if (ima && (sview == STEREO_RIGHT_ID)) {
+                       iuser.multiview_eye = sview;
+                       iuser.flag |= IMA_SHOW_STEREO;
+                       BKE_image_multiview_index(ima, &iuser);
+               }
 
-       int ima_x, ima_y;
+               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;
@@ -675,61 +698,98 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
                }
        }
 
-       /* 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);
+                       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 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_box_wire_2d(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
        }
+       else {
+               immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+               immUniformColor3ubv(ob_wire_col);
+               glEnable(GL_LINE_SMOOTH);
+
+               if (!use_blend) {
+                       glEnable(GL_BLEND);
+                       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+               }
 
-       /* 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();
+               imm_draw_box_wire_2d(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 
-       /* Reset GL settings */
-       glPopMatrix();
+               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])
@@ -747,62 +807,65 @@ static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3
        }
 }
 
-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);
+       /* set up outline */
+       float outlineColor[4];
+       UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor);
+       immUniform4fv("outlineColor", outlineColor);
+       immUniform1f("outlineWidth", outlineWidth);
 
-       /* 1. draw filled, blended polygon */
-       glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
+       immBegin(GWN_PRIM_POINTS, 1);
+       immVertex3fv(pos, co);
+       immEnd();
 
-       /* 2. draw outline */
-       glLineWidth(1);
-       UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
-       glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
-
-       /* 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 ************* */
@@ -893,36 +956,30 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
        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;
                                }
 
@@ -939,13 +996,11 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
                        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();
@@ -969,9 +1024,9 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write)
 /* 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},
@@ -984,13 +1039,21 @@ static void drawcube_size(float 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];
 
@@ -1000,16 +1063,16 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4])
        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)
@@ -1075,62 +1138,63 @@ 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);
+       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 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];
 
@@ -1143,50 +1207,46 @@ static void draw_transp_sun_volume(Lamp *la)
        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);
+       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 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);
@@ -1194,7 +1254,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
                               !(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
@@ -1206,7 +1266,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
                ((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;
@@ -1214,118 +1274,159 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
 
        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);
+                       glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, 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 */
        }
@@ -1357,24 +1458,18 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
                            {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) {
@@ -1384,22 +1479,21 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
                                 * 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_box_wire_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) {
@@ -1409,17 +1503,17 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
                                 * 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];
@@ -1428,41 +1522,40 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
                        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 */
@@ -1475,13 +1568,13 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
                                        }
 
                                        v[2] = v[2] - steps * zdist;
-                                       
-                                       glVertex3fv(v);
-                                       
+
+                                       immVertex3fv(pos, v);
+
                                        zdist = zdist * mul;
                                }
-                               
-                               glEnd();
+
+                               immEnd();
                                /* flip the direction */
                                dir = -dir;
                        }
@@ -1489,96 +1582,92 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
 
 #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_box_wire_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_box_wire_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
@@ -1588,26 +1677,6 @@ bool view3d_camera_border_hack_test = false;
 
 /* ****************** 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,
         MovieClip *clip, MovieTrackingObject *tracking_object,
@@ -1633,7 +1702,7 @@ static void draw_viewport_object_reconstruction(
        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
@@ -1641,8 +1710,8 @@ static void draw_viewport_object_reconstruction(
                 * from current ogl matrix */
                invert_m4_m4(imat, base->object->obmat);
 
-               glMultMatrixf(imat);
-               glMultMatrixf(mat);
+               gpuMultMatrix(imat);
+               gpuMultMatrix(mat);
        }
        else {
                float obmat[4][4];
@@ -1651,7 +1720,7 @@ static void draw_viewport_object_reconstruction(
                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) {
@@ -1664,66 +1733,93 @@ static void draw_viewport_object_reconstruction(
                        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 = GPU_batch_preset_sphere_wire(1);
+
                                        if ((dflag & DRAW_CONSTCOLOR) == 0) {
-                                               glColor3ubv(ob_wire_col);
+                                               GWN_batch_program_set_builtin(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 {
+                                               GWN_batch_program_set_builtin(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 = GPU_batch_preset_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];
+                                       GWN_batch_program_set_builtin(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 {
+                                       GWN_batch_program_set_builtin(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];
@@ -1743,22 +1839,27 @@ static void draw_viewport_object_reconstruction(
                        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;
 }
@@ -1793,67 +1894,65 @@ static void draw_viewport_reconstruction(
        /* 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)
@@ -1865,7 +1964,7 @@ 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];
@@ -1881,15 +1980,15 @@ static void drawcamera_stereo3d(
 
        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]);
@@ -1906,10 +2005,10 @@ static void drawcamera_stereo3d(
 
                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 */
@@ -1923,21 +2022,20 @@ static void drawcamera_stereo3d(
                }
        }
 
-
        /* 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 */
@@ -1962,21 +2060,21 @@ static void drawcamera_stereo3d(
                        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 */
                }
        }
 
@@ -2001,37 +2099,31 @@ static void drawcamera_stereo3d(
                        }
 
                        /* 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;
@@ -2094,8 +2186,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
        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) {
@@ -2104,27 +2200,29 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
                        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 */
@@ -2133,22 +2231,25 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
         * 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) {
@@ -2159,16 +2260,15 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
                        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) {
@@ -2177,69 +2277,79 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
 
                                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);
@@ -2251,12 +2361,12 @@ static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short s
                                        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);
                                                }
                                        }
                                }
@@ -2264,32 +2374,32 @@ static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short s
                }
        }
        
-       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);
        }
 }
 
 #ifdef SEQUENCER_DAG_WORKAROUND
-static void ensure_curve_cache(Scene *scene, Object *object)
+static void ensure_curve_cache(
+        const EvaluationContext *eval_ctx, Scene *scene, Object *object)
 {
        bool need_recalc = object->curve_cache == NULL;
        /* Render thread might have freed the curve cache if the
@@ -2318,13 +2428,13 @@ static void ensure_curve_cache(Scene *scene, Object *object)
                        case OB_CURVE:
                        case OB_SURF:
                        case OB_FONT:
-                               BKE_displist_make_curveTypes(scene, object, false);
+                               BKE_displist_make_curveTypes(eval_ctx, scene, object, false);
                                break;
                        case OB_MBALL:
-                               BKE_displist_make_mball(G.main->eval_ctx, scene, object);
+                               BKE_displist_make_mball(eval_ctx, scene, object);
                                break;
                        case OB_LATTICE:
-                               BKE_lattice_modifiers_calc(scene, object);
+                               BKE_lattice_modifiers_calc(eval_ctx, scene, object);
                                break;
                }
        }
@@ -2332,7 +2442,7 @@ static void ensure_curve_cache(Scene *scene, Object *object)
 #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;
@@ -2345,47 +2455,79 @@ static void drawlattice(View3D *v3d, Object *ob)
        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);
-       for (w = 0; w < lt->pntsw; w++) {
-               int wxt = (w == 0 || w == lt->pntsw - 1);
-               for (v = 0; v < lt->pntsv; v++) {
-                       int vxt = (v == 0 || v == lt->pntsv - 1);
-                       for (u = 0; u < lt->pntsu; u++) {
-                               int uxt = (u == 0 || u == lt->pntsu - 1);
+       Gwn_VertFormat *format = immVertexFormat();
+       unsigned int color, pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 
-                               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);
-                               }
-                               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);
-                               }
-                               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);
-                               }
-                       }
-               }
+       if (actdef_wcol) {
+               color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+               immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
        }
-       glEnd();
+       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 vxt = (v == 0 || v == lt->pntsv - 1);
+                       for (u = 0; u < lt->pntsu; u++) {
+                               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, 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, 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, pos, color);
+                                       drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
+                               }
+                       }
+               }
+       }
+
+       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);
        }
 }
@@ -2399,6 +2541,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],
@@ -2410,17 +2553,18 @@ static void drawSelectedVertices__mapFunc(void *userData, int index, const float
        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};
@@ -2435,9 +2579,18 @@ static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
        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 ****************** */
@@ -2484,25 +2637,34 @@ static void draw_dm_face_normals__mapFunc(void *userData, int index, const float
                        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]))
@@ -2513,16 +2675,28 @@ static void draw_dm_face_centers__mapFunc(void *userData, int index, const float
        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);
+
+       if (dm->getNumPolys(dm) == 0) return;
+
+       immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+       immUniformColor3ubv(fcol);
 
-       glBegin(GL_POINTS);
+       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])
@@ -2549,71 +2723,83 @@ static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float
                        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);
@@ -2621,16 +2807,37 @@ static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVer
        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 */
@@ -2936,24 +3143,32 @@ static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int
                        }
                        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
@@ -3070,7 +3285,7 @@ static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
        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);
        }
 }
@@ -3100,8 +3315,10 @@ static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[
        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);
                }
        }
 }
@@ -3115,11 +3332,21 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
                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 {
@@ -3129,7 +3356,7 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
                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);
                }
        }
@@ -3150,7 +3377,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
 {
        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];
@@ -3180,15 +3407,12 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
                        }
 
                        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) {
@@ -3198,7 +3422,7 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
                }
        }
 
-       if (v3d->zbuf) glDepthMask(1);
+       if (v3d->zbuf) glDepthMask(GL_TRUE);
 }
 
 static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
@@ -3305,11 +3529,9 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
 
        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) {
@@ -3673,8 +3895,9 @@ static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
        }
 }
 
-static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
-                          Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
+static void draw_em_fancy(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d,
+        Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
 
 {
        RegionView3D *rv3d = ar->regiondata;
@@ -3682,7 +3905,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
        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);
 
@@ -3691,7 +3914,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                        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 {
@@ -3711,7 +3934,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                        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(eval_ctx, scene, view_layer, ob, v3d, dt)) {
                                glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 
                                finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind,
@@ -3721,7 +3944,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                                glFrontFace(GL_CCW);
                        }
                        else {
-                               draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
+                               draw_mesh_textured(scene, view_layer, v3d, rv3d, ob, finalDM, 0);
                        }
                }
                else {
@@ -3738,7 +3961,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                UI_ThemeColor(TH_WIRE_EDIT);
 
                ED_view3d_polygon_offset(rv3d, 1.0);
-               glDepthMask(0);
+               glDepthMask(GL_FALSE);
                use_depth_offset = true;
        }
        else {
@@ -3788,7 +4011,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 #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))
@@ -3804,7 +4027,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 #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
@@ -3819,7 +4042,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                        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);
@@ -3828,7 +4051,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 #endif
 
                        glDisable(GL_BLEND);
-                       glDepthMask(1);  /* restore write in zbuffer */
+                       glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                }
 
                /* here starts all fancy draw-extra over */
@@ -3842,7 +4065,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                else {
                        if (me->drawflag & ME_DRAWSEAMS) {
                                UI_ThemeColor(TH_EDGE_SEAM);
-                               glLineWidth(2);
+                               glLineWidth(2.0f);
 
                                draw_dm_edges_seams(em, cageDM);
 
@@ -3851,7 +4074,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 
                        if (me->drawflag & ME_DRAWSHARP) {
                                UI_ThemeColor(TH_EDGE_SHARP);
-                               glLineWidth(2);
+                               glLineWidth(2.0f);
 
                                draw_dm_edges_sharp(em, cageDM);
 
@@ -3861,7 +4084,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 #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);
 
@@ -3876,7 +4099,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                                draw_dm_bweights(em, scene, cageDM);
                        }
 
-                       glLineWidth(1);
+                       glLineWidth(1.0f);
                        draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
                }
 
@@ -3884,16 +4107,13 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
                        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 |
@@ -3914,7 +4134,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
        }
 
        if (use_depth_offset) {
-               glDepthMask(1);
+               glDepthMask(GL_TRUE);
                ED_view3d_polygon_offset(rv3d, 0.0);
                GPU_object_material_unbind();
        }
@@ -3925,15 +4145,99 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 #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);
+
+       GWN_batch_program_set_builtin(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);
+               GWN_batch_program_set_builtin(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
+        */
+       GWN_batch_program_set_builtin(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);
+               GWN_batch_program_set_builtin(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 */
+               GWN_batch_program_set_builtin(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);
+               GWN_batch_program_set_builtin(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);
+
+       GWN_batch_program_set_builtin(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(
+        const EvaluationContext *eval_ctx, 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 */
+           (eval_ctx->object_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
@@ -3947,7 +4251,51 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
                        dm->drawEdges(dm, 0, 1);
                }
 
-               glDepthMask(1);
+               glDepthMask(GL_TRUE);
+       }
+}
+
+static void draw_mesh_object_outline_new(
+        const EvaluationContext *eval_ctx, View3D *v3d, RegionView3D *rv3d,
+        Mesh *me, const bool is_active)
+{
+       if ((v3d->transp == false) &&  /* not when we draw the transparent pass */
+           (eval_ctx->object_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) {
+                       GWN_batch_program_set_builtin(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 {
+                       GWN_batch_program_set_builtin(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);
+               GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+               GWN_batch_uniform_4fv(batch, "color", outline_color);
+               GWN_batch_draw(batch);
+#endif
+
+               glDepthMask(GL_TRUE);
        }
 }
 
@@ -3957,20 +4305,23 @@ static bool object_is_halo(Scene *scene, Object *ob)
        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,
-                            const char dt, const unsigned char ob_wire_col[4], const short dflag)
+static void draw_mesh_fancy(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, 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, view_layer, eval_ctx->object_mode) : base->object);
 #else
        Object *ob = base->object;
 #endif
        Mesh *me = ob->data;
        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);
-       int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
+       DerivedMesh *dm = mesh_get_derived_final(eval_ctx, scene, ob, scene->customdata_mask);
+       const bool is_obact = (ob == OBACT(view_layer));
+       int draw_flags = (is_obact && BKE_paint_select_face_test(ob, eval_ctx->object_mode)) ? DRAW_FACE_SELECT : 0;
 
        if (!dm)
                return;
@@ -4005,37 +4356,39 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
 
        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)))
+                ((!is_obact || (eval_ctx->object_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) {
                draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
        }
-       else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
+       else if (((is_obact && eval_ctx->object_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 & 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(eval_ctx, v3d, ob, dm, ob_wire_col);
                }
 
-               if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
+               if (draw_glsl_material(eval_ctx, scene, view_layer, 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, view_layer, eval_ctx->object_mode)))
+                       {
                                GPUVertexAttribs gattribs;
                                float planes[4][4];
                                float (*fpl)[4] = NULL;
@@ -4043,7 +4396,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
 
                                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;
                                        }
@@ -4068,7 +4421,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
                                draw_mesh_face_select(rv3d, me, dm, false);
                }
                else {
-                       draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags);
+                       draw_mesh_textured(scene, view_layer, v3d, rv3d, ob, dm, draw_flags);
                }
 
                if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) {
@@ -4094,11 +4447,11 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
                                /* 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(eval_ctx, v3d, ob, dm, ob_wire_col);
                                }
 
                                /* materials arent compatible with vertex colors */
@@ -4118,23 +4471,23 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
 
                        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(eval_ctx, 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, view_layer, eval_ctx->object_mode))) {
                                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;
                                        }
@@ -4159,7 +4512,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
                }
        }
        else if (dt == OB_PAINT) {
-               draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags);
+               draw_mesh_paint(eval_ctx, 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;
@@ -4174,8 +4527,10 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
                 * with the background. */
 
                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);
+                       if (is_obact && (eval_ctx->object_mode & OB_MODE_PARTICLE_EDIT)) {
+                               float color[3];
+                               ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f, color);
+                               glColor3fv(color);
                        }
                        else {
                                glColor3ubv(ob_wire_col);
@@ -4193,19 +4548,19 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
                 */
                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);
                }
        }
        
-       if (is_obact && BKE_paint_select_vert_test(ob)) {
+       if (is_obact && BKE_paint_select_vert_test(ob, eval_ctx->object_mode)) {
                const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
                glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 
@@ -4219,11 +4574,12 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
 }
 
 /* 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,
-                             const char dt, const unsigned char ob_wire_col[4], const short dflag)
+static bool draw_mesh_object(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
+        const char dt, const unsigned char ob_wire_col[4], const short dflag)
 {
        Object *ob = base->object;
-       Object *obedit = scene->obedit;
+       Object *obedit = OBEDIT_FROM_EVAL_CTX(eval_ctx);
        Mesh *me = ob->data;
        BMEditMesh *em = me->edit_btmesh;
        bool do_alpha_after = false, drawlinked = false, retval = false;
@@ -4231,7 +4587,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
        /* 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;
@@ -4260,7 +4616,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
                }
                else {
                        cageDM = editbmesh_get_derived_cage_and_final(
-                               scene, ob, em, scene->customdata_mask,
+                               eval_ctx, scene, ob, em, scene->customdata_mask,
                                &finalDM);
                }
 
@@ -4273,13 +4629,13 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
 
                if (use_material) {
                        if (dt > OB_WIRE) {
-                               const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
+                               const bool glsl = draw_glsl_material(eval_ctx, scene, view_layer, ob, v3d, dt);
 
-                               GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
+                               GPU_begin_object_materials(v3d, rv3d, scene, view_layer, ob, glsl, eval_ctx->object_mode, NULL);
                        }
                }
 
-               draw_em_fancy(scene, ar, v3d, ob, em, cageDM, finalDM, dt);
+               draw_em_fancy(eval_ctx, scene, view_layer, ar, v3d, ob, em, cageDM, finalDM, dt);
 
                if (use_material) {
                        GPU_end_object_materials();
@@ -4292,16 +4648,17 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
                /* 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(eval_ctx, scene, view_layer, 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,
-                                                                  (check_alpha) ? &do_alpha_after : NULL);
+                                       const bool check_alpha = check_alpha_pass(eval_ctx, base);
+                                       GPU_begin_object_materials(
+                                               v3d, rv3d, scene, view_layer, ob,
+                                               glsl, eval_ctx->object_mode, (check_alpha) ? &do_alpha_after : NULL);
                                }
                        }
 
-                       draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
+                       draw_mesh_fancy(eval_ctx, scene, view_layer, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
 
                        GPU_end_object_materials();
                        
@@ -4309,7 +4666,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
                }
        }
        
-       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) {
@@ -4333,134 +4690,663 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
        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(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer,
+        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(eval_ctx, scene, view_layer, 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, view_layer, eval_ctx->object_mode) : 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(eval_ctx, scene, ob, scene->customdata_mask);
+       const bool is_obact = (ob == OBACT(view_layer));
+       int draw_flags = (is_obact && BKE_paint_select_face_test(ob, eval_ctx->object_mode)) ? 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 || (eval_ctx->object_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) {
+                       GWN_batch_program_set_builtin(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 {
+                       GWN_batch_program_set_builtin(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);
+
+               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);
+
+               GWN_batch_draw(fancy_edges);
+
+               /* 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);
+
+               GWN_batch_draw(fancy_edges);
+
+#else /* simple wireframes */
+
+               Gwn_Batch *batch = MBC_get_all_edges(dm);
+               GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+
+               float color[4];
+               rgba_uchar_to_float(color, ob_wire_col);
+
+               GWN_batch_uniform_4fv(batch, "color", color);
+
+               GWN_batch_draw(batch);
+#endif
+       }
+       else if (((is_obact && eval_ctx->object_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(eval_ctx, v3d, rv3d, me, (ob == OBACT(view_layer)));
+               }
+
+               if (draw_glsl_material(eval_ctx, scene, view_layer, 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, view_layer, eval_ctx->object_mode)))
+                       {
+                               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, view_layer, 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(eval_ctx, v3d, rv3d, me, (ob == OBACT(view_layer)));
+                               }
+
+                               /* 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(eval_ctx, v3d, rv3d, me, (ob == OBACT(view_layer)));
+                       }
+
+                       glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
+
+                       if (ob->sculpt && (p = BKE_paint_get_active(scene, view_layer, eval_ctx->object_mode))) {
+                               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(eval_ctx, 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)(
+        const EvaluationContext *eval_ctx, Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
+        const char dt, const unsigned char ob_wire_col[4], const short dflag)
+{
+       Object *ob = base->object;
+       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;
+       }
+       Object *obedit = OBEDIT_FROM_EVAL_CTX(eval_ctx);
+       
+       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(
+                               eval_ctx, 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(eval_ctx, scene, eval_ctx->view_layer, ob, v3d, dt);
+
+                       GPU_begin_object_materials(v3d, rv3d, scene, eval_ctx->view_layer, ob, glsl, eval_ctx->object_mode, 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(eval_ctx, scene, eval_ctx->view_layer, ob, v3d, dt);
+
+                               if (dt == OB_SOLID || glsl) {
+                                       const bool check_alpha = check_alpha_pass(eval_ctx, base);
+                                       GPU_begin_object_materials(
+                                               v3d, rv3d, scene, eval_ctx->view_layer, ob,
+                                               eval_ctx->object_mode, glsl, (check_alpha) ? &do_alpha_after : NULL);
+                               }
+                       }
+
+                       const bool other_obedit = obedit && (obedit != ob);
+
+                       draw_mesh_fancy_new(eval_ctx, scene, eval_ctx->view_layer, 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_ex(prim_type, vbo, NULL, GWN_BATCH_OWNS_VBO);
+       GWN_batch_program_set_builtin(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(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_ex(
+               GWN_PRIM_TRIS, vbo, GWN_indexbuf_build(&elb), GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX);
+       GWN_batch_program_set_builtin(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(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;
+
+                       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);
+       return drawDispListwire_ex(dlbase, dl_mask, wire_col);
 }
 
 static bool index3_nors_incr = true;
 
-static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
+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;
 
-       glEnableClientState(GL_VERTEX_ARRAY);
-
        /* 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;
+               //const float *ndata = dl->nors;
 
                switch (dl->type) {
                        case DL_SEGM:
@@ -4470,15 +5356,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
                                                col = -1;
                                        }
 
-                                       if ((dflag & DRAW_CONSTCOLOR) == 0)
-                                               glColor3ubv(ob_wire_col);
-
-                                       // 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();
+                                       drawDispListVerts(GWN_PRIM_LINE_STRIP, data, dl->nr, ob_wire_col);
                                }
                                break;
                        case DL_POLY:
@@ -4488,14 +5366,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
                                                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);
-
-                                       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:
@@ -4505,15 +5376,12 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
                                                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;
 
@@ -4523,8 +5391,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
                                        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);
@@ -4532,11 +5399,17 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
                                }
                                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;
 
@@ -4546,18 +5419,16 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
                                        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) {
@@ -4572,7 +5443,9 @@ 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(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, View3D *v3d, RegionView3D *rv3d,
+        Base *base, const char dt)
 {
        Object *ob = base->object;
        DerivedMesh *dm = ob->derivedFinal;
@@ -4586,8 +5459,10 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
        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(eval_ctx, scene, view_layer, ob, v3d, dt);
+               GPU_begin_object_materials(
+                       v3d, rv3d, scene, view_layer, ob,
+                       eval_ctx->object_mode, glsl, NULL);
 
                if (!glsl)
                        dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
@@ -4608,8 +5483,9 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
  * Only called by #drawDispList
  * \return true when nothing was drawn
  */
-static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
-                                    const char dt, const short dflag, const unsigned char ob_wire_col[4])
+static bool drawDispList_nobackface(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, View3D *v3d, RegionView3D *rv3d,
+        Base *base, const char dt, const short dflag, const unsigned char ob_wire_col[4])
 {
        Object *ob = base->object;
        ListBase *lb = NULL;
@@ -4638,10 +5514,10 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
                                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);
                                        }
                                }
 
@@ -4649,26 +5525,26 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
                                        /* pass */
                                }
                                else {
-                                       if (draw_glsl_material(scene, ob, v3d, dt)) {
-                                               GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
+                                       if (draw_glsl_material(eval_ctx, scene, view_layer, ob, v3d, dt)) {
+                                               GPU_begin_object_materials(v3d, rv3d, scene, view_layer, ob, 1, eval_ctx->object_mode, 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, view_layer, ob, 0, eval_ctx->object_mode, 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;
@@ -4684,19 +5560,19 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
 
                                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(eval_ctx, scene, view_layer, ob, v3d, dt)) {
+                                       GPU_begin_object_materials(v3d, rv3d, scene, view_layer, ob, 1, eval_ctx->object_mode, 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, view_layer, ob, 0, eval_ctx->object_mode, 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:
@@ -4709,19 +5585,19 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
 
                                if (solid) {
 
-                                       if (draw_glsl_material(scene, ob, v3d, dt)) {
-                                               GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
+                                       if (draw_glsl_material(eval_ctx, scene, view_layer, ob, v3d, dt)) {
+                                               GPU_begin_object_materials(v3d, rv3d, scene, view_layer, ob, 1, eval_ctx->object_mode, 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, view_layer, ob, 0, eval_ctx->object_mode, 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;
@@ -4729,8 +5605,9 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
 
        return false;
 }
-static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
-                         const char dt, const short dflag, const unsigned char ob_wire_col[4])
+static bool drawDispList(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, View3D *v3d, RegionView3D *rv3d, Base *base,
+        const char dt, const short dflag, const unsigned char ob_wire_col[4])
 {
        bool retval;
 
@@ -4742,10 +5619,10 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba
        }
 
 #ifdef SEQUENCER_DAG_WORKAROUND
-       ensure_curve_cache(scene, base->object);
+       ensure_curve_cache(eval_ctx, scene, base->object);
 #endif
 
-       if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
+       if (drawCurveDerivedMesh(eval_ctx, scene, view_layer, v3d, rv3d, base, dt) == false) {
                retval = false;
        }
        else {
@@ -4761,7 +5638,7 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba
 
                glFrontFace(mode);
 
-               retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+               retval = drawDispList_nobackface(eval_ctx, scene, view_layer, v3d, rv3d, base, dt, dflag, ob_wire_col);
 
                if (mode != GL_CCW) {
                        glFrontFace(GL_CCW);
@@ -4776,16 +5653,63 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba
 }
 
 /* *********** 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_ex(prim_type, vbo, NULL, GWN_BATCH_OWNS_VBO);
+       if (nor && color) {
+               GWN_batch_program_set_builtin(batch, GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR);
+               GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
+       }
+       else if (nor) {
+               GWN_batch_program_set_builtin(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) {
+               GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_SMOOTH_COLOR);
+       }
+       else {
+               GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+               if (col) GWN_batch_uniform_4fv(batch, "color", col);
+       }
+       GWN_batch_draw(batch);
+       GWN_batch_discard(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)
@@ -4793,15 +5717,16 @@ static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int selec
                        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;
@@ -4911,28 +5836,30 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
                }
                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, 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);
@@ -4941,10 +5868,14 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
                        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;
                }
        }
@@ -4952,7 +5883,8 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
 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;
@@ -4983,7 +5915,7 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
 
        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
@@ -4996,9 +5928,10 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
  * 6. draw the arrays
  * 7. clean up
  */
-static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d,
-                                     Base *base, ParticleSystem *psys,
-                                     const char ob_dt, const short dflag)
+static void draw_new_particle_system(
+        const EvaluationContext *eval_ctx, Scene *scene, View3D *v3d, RegionView3D *rv3d,
+        Base *base, ParticleSystem *psys,
+        const char ob_dt, const short dflag)
 {
        Object *ob = base->object;
        ParticleEditSettings *pset = PE_settings(scene);
@@ -5016,10 +5949,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
        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))
@@ -5028,7 +5962,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
        if (pars == NULL) return;
 
        /* don't draw normal paths in edit mode */
-       if (psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART) == 0)
+       if (psys_in_edit_mode(eval_ctx, eval_ctx->view_layer, psys) && (pset->flag & PE_DRAW_PART) == 0)
                return;
 
        if (part->draw_as == PART_DRAW_REND)
@@ -5048,6 +5982,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                curvemapping_changed_all(psys->part->twistcurve);
 
 /* 2. */
+       sim.eval_ctx = eval_ctx;
        sim.scene = scene;
        sim.ob = ob;
        sim.psys = psys;
@@ -5083,16 +6018,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                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 */
@@ -5212,7 +6143,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                partsize *= 2;
                                break;
                        case PART_DRAW_BB:
-                               partsize *= 4;
+                               partsize *= 6;  /* New OGL only understands tris, no choice here. */
                                create_ndata = 1;
                                break;
                }
@@ -5267,6 +6198,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                        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) {
@@ -5337,7 +6273,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
                                                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;
@@ -5349,7 +6285,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
                                                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;
@@ -5371,7 +6307,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
                                        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);
                                        }
 
@@ -5408,31 +6344,19 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                        }
                                }
                        }
+                       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)
@@ -5443,41 +6367,28 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                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);
                                        }
                                }
                                
@@ -5485,30 +6396,36 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                        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) {
@@ -5519,64 +6436,69 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                        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();
                                }
                        }
                }
@@ -5585,27 +6507,17 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                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;
@@ -5625,19 +6537,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                }
        }
        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);
@@ -5646,48 +6550,39 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
                                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);
-
-               /* enable other data arrays */
+                       glPointSize(part->draw_size ? part->draw_size : 2.0);
+                       glLineWidth(1.0);
 
-               /* 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]);
@@ -5696,9 +6591,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 /* 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);
@@ -5721,32 +6613,28 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                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(
+        const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, PTCacheEdit *edit)
 {
        if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED)
-               PE_update_object(scene, ob, 0);
+               PE_update_object(eval_ctx, scene, view_layer, ob, 0);
 
        /* create path and child path cache if it doesn't exist already */
-       if (edit->pathcache == NULL)
-               psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
+       if (edit->pathcache == NULL) {
+               psys_cache_edit_paths(eval_ctx, scene, ob, edit, CFRA, G.is_rendering);
+       }
 }
 
 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;
@@ -5758,50 +6646,71 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
                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_calloc_arrayN(totkeys, 4 * sizeof(float), "particle path color data");
-
-       glEnableClientState(GL_VERTEX_ARRAY);
-       glEnableClientState(GL_COLOR_ARRAY);
+       float *pathcol = MEM_calloc_arrayN(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_ex(GWN_PRIM_LINE_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
+               GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_SMOOTH_COLOR);
+               GWN_batch_draw(batch);
+               GWN_batch_discard(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) {
@@ -5812,6 +6721,10 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
                        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;
@@ -5826,7 +6739,8 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
                                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;
@@ -5851,14 +6765,20 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
                                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_ex(GWN_PRIM_POINTS, vbo, NULL, GWN_BATCH_OWNS_VBO);
+                               GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_SMOOTH_COLOR);
+                               GWN_batch_draw(batch);
+                               GWN_batch_discard(batch);
 
                                pd += pd ? 3 * point->totkey : 0;
                                cd += (timed ? 4 : 3) * point->totkey;
@@ -5867,23 +6787,30 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
                        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);
 }
 
@@ -5896,130 +6823,137 @@ static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, flo
        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);
+
+       immBegin(GWN_PRIM_LINES, 30);
 
-       glColor4ub(0x7F, 0x00, 0x00, 155);
+       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);
 
-       glEnd();
+       immEnd();
+
+       immUnbindProgram();
 }
 
 /* place to add drawers */
@@ -6028,7 +6962,7 @@ static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
 {
        if (nu->hide || hide_handles) return;
 
-       if (nu->type == CU_BEZIER) {
+       if (nu->type == CU_BEZIER && nu->pntsu > 0) {
 
                const float *fp;
 
@@ -6041,9 +6975,14 @@ static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
                        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;
@@ -6052,33 +6991,35 @@ static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
                                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
 
@@ -6089,153 +7030,196 @@ static void drawhandlesN_active(Nurb *nu)
 {
        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);
-
-       glBegin(GL_LINES);
-       BPoint *bp = nu->bp;
-       for (int b = 0; b < nu->pntsv; b++) {
-               BPoint *bp1 = bp;
-               bp++;
+       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);
 
-               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)
@@ -6243,6 +7227,9 @@ 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;
@@ -6250,35 +7237,55 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
                if (nu->hide == 0) {
          &