Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Tue, 11 Jul 2017 04:21:05 +0000 (14:21 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 11 Jul 2017 04:21:05 +0000 (14:21 +1000)
1  2 
source/blender/blenkernel/intern/scene.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_view3d/drawobject.c
source/blender/render/intern/source/pipeline.c

index 85c28b8bf54ce761e468be0a591e0eed0aacda40,a15f270a3eef934a06f2889841a7df52c7990d15..3b2287a7921212bd2b07b1e0ec18213bae21c86a
@@@ -67,8 -67,8 +67,8 @@@
  #include "BKE_action.h"
  #include "BKE_armature.h"
  #include "BKE_cachefile.h"
 +#include "BKE_collection.h"
  #include "BKE_colortools.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_editmesh.h"
  #include "BKE_fcurve.h"
  #include "BKE_freestyle.h"
@@@ -78,7 -78,6 +78,7 @@@
  #include "BKE_icons.h"
  #include "BKE_idprop.h"
  #include "BKE_image.h"
 +#include "BKE_layer.h"
  #include "BKE_library.h"
  #include "BKE_library_remap.h"
  #include "BKE_linestyle.h"
  #include "BKE_sequencer.h"
  #include "BKE_sound.h"
  #include "BKE_unit.h"
 +#include "BKE_workspace.h"
  #include "BKE_world.h"
  
  #include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +#include "DEG_depsgraph_query.h"
  
  #include "RE_engine.h"
  
  
  const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
  const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
 +const char *RE_engine_id_BLENDER_CLAY = "BLENDER_CLAY";
 +const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
  const char *RE_engine_id_CYCLES = "CYCLES";
  
  void free_avicodecdata(AviCodecData *acd)
@@@ -160,66 -154,13 +160,66 @@@ static void remove_sequencer_fcurves(Sc
        }
  }
  
 +/* copy SceneCollection tree but keep pointing to the same objects */
 +static void scene_collection_copy(SceneCollection *scn, SceneCollection *sc)
 +{
 +      BLI_duplicatelist(&scn->objects, &sc->objects);
 +      for (LinkData *link = scn->objects.first; link; link = link->next) {
 +              id_us_plus(link->data);
 +      }
 +
 +      BLI_duplicatelist(&scn->filter_objects, &sc->filter_objects);
 +      for (LinkData *link = scn->filter_objects.first; link; link = link->next) {
 +              id_us_plus(link->data);
 +      }
 +
 +      BLI_duplicatelist(&scn->scene_collections, &sc->scene_collections);
 +      SceneCollection *nscn = scn->scene_collections.first; /* nested SceneCollection new */
 +      for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
 +              scene_collection_copy(nscn, nsc);
 +              nscn = nscn->next;
 +      }
 +}
 +
 +/* Find the equivalent SceneCollection in the new tree */
 +static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_reference, SceneCollection *scn, SceneCollection *sc)
 +{
 +      if (sc == sc_reference) {
 +              return scn;
 +      }
 +
 +      SceneCollection *nscn = scn->scene_collections.first; /* nested master collection new */
 +      for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
 +
 +              SceneCollection *found = scene_collection_from_new_tree(sc_reference, nscn, nsc);
 +              if (found) {
 +                      return found;
 +              }
 +              nscn = nscn->next;
 +      }
 +      return NULL;
 +}
 +
 +/* recreate the LayerCollection tree */
 +static void layer_collections_recreate(SceneLayer *sl, ListBase *lb, SceneCollection *mcn, SceneCollection *mc)
 +{
 +      for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
 +
 +              SceneCollection *sc = scene_collection_from_new_tree(lc->scene_collection, mcn, mc);
 +              BLI_assert(sc);
 +
 +              /* instead of syncronizing both trees we simply re-create it */
 +              BKE_collection_link(sl, sc);
 +      }
 +}
 +
  Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
  {
        Scene *scen;
        SceneRenderLayer *srl, *new_srl;
        FreestyleLineSet *lineset;
        ToolSettings *ts;
 -      Base *base, *obase;
 +      BaseLegacy *legacy_base, *olegacy_base;
        
        if (type == SCE_COPY_EMPTY) {
                ListBase rl, rv;
                scen = BKE_libblock_copy(bmain, &sce->id);
                BLI_duplicatelist(&(scen->base), &(sce->base));
                
-               id_us_plus((ID *)scen->world);
+               if (type != SCE_COPY_FULL) {
+                       id_us_plus((ID *)scen->world);
+               }
                id_us_plus((ID *)scen->set);
                /* id_us_plus((ID *)scen->gm.dome.warptext); */  /* XXX Not refcounted? see readfile.c */
  
                scen->theDag = NULL;
                scen->depsgraph = NULL;
                scen->obedit = NULL;
 -              scen->stats = NULL;
                scen->fps_info = NULL;
  
                if (sce->rigidbody_world)
                        scen->rigidbody_world = BKE_rigidbody_world_copy(sce->rigidbody_world);
  
                BLI_duplicatelist(&(scen->markers), &(sce->markers));
 -              BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces));
                BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers));
                BLI_duplicatelist(&(scen->r.views), &(sce->r.views));
                BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets));
                        BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false);
                }
  
 -              obase = sce->base.first;
 -              base = scen->base.first;
 -              while (base) {
 -                      id_us_plus(&base->object->id);
 -                      if (obase == sce->basact) scen->basact = base;
 +              olegacy_base = sce->base.first;
 +              legacy_base = scen->base.first;
 +              while (legacy_base) {
 +                      id_us_plus(&legacy_base->object->id);
 +                      if (olegacy_base == sce->basact) scen->basact = legacy_base;
        
 -                      obase = obase->next;
 -                      base = base->next;
 +                      olegacy_base = olegacy_base->next;
 +                      legacy_base = legacy_base->next;
                }
  
                /* copy action and remove animation used by sequencer */
                        if (type == SCE_COPY_FULL) {
                                for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
                                        if (lineset->linestyle) {
-                                               id_us_plus((ID *)lineset->linestyle);
+                                               /* Has been incremented by BKE_freestyle_config_copy(). */
+                                               id_us_min(&lineset->linestyle->id);
                                                lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
                                        }
                                }
                        }
                        new_srl = new_srl->next;
                }
 +
 +              /* layers and collections */
 +              scen->collection = MEM_dupallocN(sce->collection);
 +              SceneCollection *mcn = BKE_collection_master(scen);
 +              SceneCollection *mc = BKE_collection_master(sce);
 +
 +              /* recursively creates a new SceneCollection tree */
 +              scene_collection_copy(mcn, mc);
 +
 +              IDPropertyTemplate val = {0};
 +              BLI_duplicatelist(&scen->render_layers, &sce->render_layers);
 +              SceneLayer *new_sl = scen->render_layers.first;
 +              for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) {
 +                      new_sl->stats = NULL;
 +                      new_sl->properties_evaluated = NULL;
 +                      new_sl->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
 +                      IDP_MergeGroup(new_sl->properties, sl->properties, true);
 +
 +                      /* we start fresh with no overrides and no visibility flags set
 +                       * instead of syncing both trees we simply unlink and relink the scene collection */
 +                      BLI_listbase_clear(&new_sl->layer_collections);
 +                      BLI_listbase_clear(&new_sl->object_bases);
 +                      BLI_listbase_clear(&new_sl->drawdata);
 +                      layer_collections_recreate(new_sl, &sl->layer_collections, mcn, mc);
 +
 +                      Object *active_ob = OBACT_NEW;
 +                      Base *new_base = new_sl->object_bases.first;
 +                      for (Base *base = sl->object_bases.first; base; base = base->next) {
 +                              new_base->flag = base->flag;
 +                              new_base->flag_legacy = base->flag_legacy;
 +
 +                              if (new_base->object == active_ob) {
 +                                      new_sl->basact = new_base;
 +                              }
 +
 +                              new_base = new_base->next;
 +                      }
 +                      new_sl = new_sl->next;
 +              }
 +
 +              scen->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
 +              scen->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
        }
  
        /* copy color management settings */
                        ts->sculpt = MEM_dupallocN(ts->sculpt);
                        BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint);
                }
+               if (ts->uvsculpt) {
+                       ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
+                       BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint);
+               }
  
                BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint);
                ts->imapaint.paintcursor = NULL;
                id_us_plus((ID *)ts->imapaint.stencil);
+               id_us_plus((ID *)ts->imapaint.clone);
+               id_us_plus((ID *)ts->imapaint.canvas);
                ts->particle.paintcursor = NULL;
+               ts->particle.scene = NULL;
+               ts->particle.object = NULL;
                
                /* duplicate Grease Pencil Drawing Brushes */
                BLI_listbase_clear(&ts->gp_brushes);
        /* world */
        if (type == SCE_COPY_FULL) {
                if (scen->world) {
-                       id_us_plus((ID *)scen->world);
                        scen->world = BKE_world_copy(bmain, scen->world);
                        BKE_animdata_copy_id_action((ID *)scen->world, false);
                }
  
        BKE_previewimg_id_copy(&scen->id, &sce->id);
  
 +      if (type != SCE_COPY_NEW) {
 +              if (sce->collection_properties) {
 +                      IDP_MergeGroup(scen->collection_properties, sce->collection_properties, true);
 +              }
 +              if (sce->layer_properties) {
 +                      IDP_MergeGroup(scen->layer_properties, sce->layer_properties, true);
 +              }
 +      }
 +
        return scen;
  }
  
@@@ -485,7 -387,7 +495,7 @@@ void BKE_scene_make_local(Main *bmain, 
  }
  
  /** Free (or release) any data used by this scene (does not free the scene itself). */
 -void BKE_scene_free(Scene *sce)
 +void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
  {
        SceneRenderLayer *srl;
  
        }
  
        BLI_freelistN(&sce->markers);
 -      BLI_freelistN(&sce->transform_spaces);
        BLI_freelistN(&sce->r.layers);
        BLI_freelistN(&sce->r.views);
 -      
 +
        if (sce->toolsettings) {
                if (sce->toolsettings->vpaint) {
                        BKE_paint_free(&sce->toolsettings->vpaint->paint);
                sce->toolsettings = NULL;
        }
        
 -      DAG_scene_free(sce);
 +      DEG_scene_graph_free(sce);
        if (sce->depsgraph)
                DEG_graph_free(sce->depsgraph);
 -      
 -      MEM_SAFE_FREE(sce->stats);
 +
        MEM_SAFE_FREE(sce->fps_info);
  
        BKE_sound_destroy_scene(sce);
  
        BKE_previewimg_free(&sce->preview);
        curvemapping_free_data(&sce->r.mblur_shutter_curve);
 +
 +      for (SceneLayer *sl = sce->render_layers.first, *sl_next; sl; sl = sl_next) {
 +              sl_next = sl->next;
 +
 +              BLI_remlink(&sce->render_layers, sl);
 +              BKE_scene_layer_free(sl);
 +      }
 +
 +      /* Master Collection */
 +      BKE_collection_master_free(sce, do_id_user);
 +      MEM_freeN(sce->collection);
 +      sce->collection = NULL;
 +
 +      /* LayerCollection engine settings. */
 +      if (sce->collection_properties) {
 +              IDP_FreeProperty(sce->collection_properties);
 +              MEM_freeN(sce->collection_properties);
 +              sce->collection_properties = NULL;
 +      }
 +
 +      /* Render engine setting. */
 +      if (sce->layer_properties) {
 +              IDP_FreeProperty(sce->layer_properties);
 +              MEM_freeN(sce->layer_properties);
 +              sce->layer_properties = NULL;
 +      }
 +}
 +
 +void BKE_scene_free(Scene *sce)
 +{
 +      return BKE_scene_free_ex(sce, true);
  }
  
  void BKE_scene_init(Scene *sce)
        sce->r.ffcodecdata.audio_bitrate = 192;
        sce->r.ffcodecdata.audio_channels = 2;
  
 -      BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine));
 +      BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
  
        sce->audio.distance_model = 2.0f;
        sce->audio.doppler_factor = 1.0f;
        sce->gm.angulardeactthreshold = 1.0f;
        sce->gm.deactivationtime = 0.0f;
  
 -      sce->gm.flag = GAME_DISPLAY_LISTS;
 +      sce->gm.flag = 0;
        sce->gm.matmode = GAME_MAT_MULTITEX;
  
        sce->gm.obstacleSimulation = OBSTSIMULATION_NONE;
        sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
        sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
        sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
 +
 +      /* Master Collection */
 +      sce->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection");
 +      BLI_strncpy(sce->collection->name, "Master Collection", sizeof(sce->collection->name));
 +
 +      /* Engine settings */
 +      IDPropertyTemplate val = {0};
 +      sce->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
 +      BKE_layer_collection_engine_settings_create(sce->collection_properties);
 +
 +      sce->layer_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
 +      BKE_scene_layer_engine_settings_create(sce->layer_properties);
 +
 +      BKE_scene_layer_add(sce, "Render Layer");
  }
  
  Scene *BKE_scene_add(Main *bmain, const char *name)
        return sce;
  }
  
 -Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
 +BaseLegacy *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
  {
 -      Base *base;
 +      BaseLegacy *base;
  
        for (base = scene->base.first; base; base = base->next) {
                if (STREQ(base->object->id.name + 2, name)) {
        return base;
  }
  
 -Base *BKE_scene_base_find(Scene *scene, Object *ob)
 +BaseLegacy *BKE_scene_base_find(Scene *scene, Object *ob)
  {
 -      return BLI_findptr(&scene->base, ob, offsetof(Base, object));
 +      return BLI_findptr(&scene->base, ob, offsetof(BaseLegacy, object));
  }
  
  /**
   * Sets the active scene, mainly used when running in background mode (``--scene`` command line argument).
   * This is also called to set the scene directly, bypassing windowing code.
 - * Otherwise #ED_screen_set_scene is used when changing scenes by the user.
 + * Otherwise #WM_window_change_active_scene is used when changing scenes by the user.
   */
  void BKE_scene_set_background(Main *bmain, Scene *scene)
  {
        Scene *sce;
 -      Base *base;
 +      BaseLegacy *base;
        Object *ob;
        Group *group;
        GroupObject *go;
 -      int flag;
        
        /* check for cyclic sets, for reading old files but also for definite security (py?) */
        BKE_scene_validate_setscene(bmain, scene);
  
        /* sort baselist for scene and sets */
        for (sce = scene; sce; sce = sce->set)
 -              DAG_scene_relations_rebuild(bmain, sce);
 +              DEG_scene_relations_rebuild(bmain, sce);
  
        /* copy layers and flags from bases to objects */
        for (base = scene->base.first; base; base = base->next) {
                ob->lay = base->lay;
                
                /* group patch... */
 -              base->flag &= ~(OB_FROMGROUP);
 -              flag = ob->flag & (OB_FROMGROUP);
 -              base->flag |= flag;
 -              
 -              /* not too nice... for recovering objects with lost data */
 -              //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE;
 -              ob->flag = base->flag;
 +              BKE_scene_base_flag_sync_from_base(base);
        }
        /* no full animation update, this to enable render code to work (render code calls own animation updates) */
  }
@@@ -1075,7 -941,7 +1085,7 @@@ Scene *BKE_scene_set_name(Main *bmain, 
  
  /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
  int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
 -                             Scene **scene, int val, Base **base, Object **ob)
 +                             Scene **scene, int val, BaseLegacy **base, Object **ob)
  {
        bool run_again = true;
        
                                }
                                /* handle dupli's */
                                if (iter->dupob) {
 -                                      (*base)->flag |= OB_FROMDUPLI;
 +                                      (*base)->flag_legacy |= OB_FROMDUPLI;
                                        *ob = iter->dupob->ob;
                                        iter->phase = F_DUPLI;
  
                                }
                                else if (iter->phase == F_DUPLI) {
                                        iter->phase = F_SCENE;
 -                                      (*base)->flag &= ~OB_FROMDUPLI;
 +                                      (*base)->flag_legacy &= ~OB_FROMDUPLI;
                                        
                                        if (iter->dupli_refob) {
                                                /* Restore last object's real matrix. */
        return iter->phase;
  }
  
 +Scene *BKE_scene_find_from_collection(const Main *bmain, const SceneCollection *scene_collection)
 +{
 +      for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
 +              for (SceneLayer *layer = scene->render_layers.first; layer; layer = layer->next) {
 +                      if (BKE_scene_layer_has_collection(layer, scene_collection)) {
 +                              return scene;
 +                      }
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
  Object *BKE_scene_camera_find(Scene *sc)
  {
 -      Base *base;
 +      BaseLegacy *base;
        
        for (base = sc->base.first; base; base = base->next)
                if (base->object->type == OB_CAMERA)
@@@ -1318,54 -1171,47 +1328,54 @@@ char *BKE_scene_find_last_marker_name(S
        return best_marker ? best_marker->name : NULL;
  }
  
 +void BKE_scene_remove_rigidbody_object(Scene *scene, Object *ob)
 +{
 +      /* remove rigid body constraint from world before removing object */
 +      if (ob->rigidbody_constraint)
 +              BKE_rigidbody_remove_constraint(scene, ob);
 +      /* remove rigid body object from world before removing object */
 +      if (ob->rigidbody_object)
 +              BKE_rigidbody_remove_object(scene, ob);
 +}
  
 -Base *BKE_scene_base_add(Scene *sce, Object *ob)
 +BaseLegacy *BKE_scene_base_add(Scene *sce, Object *ob)
  {
 -      Base *b = MEM_callocN(sizeof(*b), __func__);
 +      BaseLegacy *b = MEM_callocN(sizeof(*b), __func__);
        BLI_addhead(&sce->base, b);
  
        b->object = ob;
 -      b->flag = ob->flag;
 +      b->flag_legacy = ob->flag;
        b->lay = ob->lay;
  
        return b;
  }
  
 -void BKE_scene_base_unlink(Scene *sce, Base *base)
 +void BKE_scene_base_unlink(Scene *sce, BaseLegacy *base)
  {
 -      /* remove rigid body constraint from world before removing object */
 -      if (base->object->rigidbody_constraint)
 -              BKE_rigidbody_remove_constraint(sce, base->object);
 -      /* remove rigid body object from world before removing object */
 -      if (base->object->rigidbody_object)
 -              BKE_rigidbody_remove_object(sce, base->object);
 -      
 +      BKE_scene_remove_rigidbody_object(sce, base->object);
 +
        BLI_remlink(&sce->base, base);
        if (sce->basact == base)
                sce->basact = NULL;
  }
  
 +/* deprecated, use BKE_scene_layer_base_deselect_all */
  void BKE_scene_base_deselect_all(Scene *sce)
  {
 -      Base *b;
 +      BaseLegacy *b;
  
        for (b = sce->base.first; b; b = b->next) {
 -              b->flag &= ~SELECT;
 -              b->object->flag = b->flag;
 +              b->flag_legacy &= ~SELECT;
 +              int flag = b->object->flag & (OB_FROMGROUP);
 +              b->object->flag = b->flag_legacy;
 +              b->object->flag |= flag;
        }
  }
  
 -void BKE_scene_base_select(Scene *sce, Base *selbase)
 +void BKE_scene_base_select(Scene *sce, BaseLegacy *selbase)
  {
 -      selbase->flag |= SELECT;
 -      selbase->object->flag = selbase->flag;
 +      selbase->flag_legacy |= SELECT;
 +      selbase->object->flag = selbase->flag_legacy;
  
        sce->basact = selbase;
  }
@@@ -1419,6 -1265,109 +1429,6 @@@ void BKE_scene_frame_set(struct Scene *
        scene->r.cfra = (int)intpart;
  }
  
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -/* drivers support/hacks 
 - *  - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
 - *    - these are always run since the depsgraph can't handle non-object data
 - *    - these happen after objects are all done so that we can read in their final transform values,
 - *      though this means that objects can't refer to scene info for guidance...
 - */
 -static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene)
 -{
 -      SceneRenderLayer *srl;
 -      float ctime = BKE_scene_frame_get(scene);
 -      
 -      /* scene itself */
 -      if (scene->adt && scene->adt->drivers.first) {
 -              BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS);
 -      }
 -
 -      /* world */
 -      /* TODO: what about world textures? but then those have nodes too... */
 -      if (scene->world) {
 -              ID *wid = (ID *)scene->world;
 -              AnimData *adt = BKE_animdata_from_id(wid);
 -              
 -              if (adt && adt->drivers.first)
 -                      BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS);
 -      }
 -      
 -      /* nodes */
 -      if (scene->nodetree) {
 -              ID *nid = (ID *)scene->nodetree;
 -              AnimData *adt = BKE_animdata_from_id(nid);
 -              
 -              if (adt && adt->drivers.first)
 -                      BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
 -      }
 -
 -      /* world nodes */
 -      if (scene->world && scene->world->nodetree) {
 -              ID *nid = (ID *)scene->world->nodetree;
 -              AnimData *adt = BKE_animdata_from_id(nid);
 -              
 -              if (adt && adt->drivers.first)
 -                      BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
 -      }
 -
 -      /* freestyle */
 -      for (srl = scene->r.layers.first; srl; srl = srl->next) {
 -              FreestyleConfig *config = &srl->freestyleConfig;
 -              FreestyleLineSet *lineset;
 -
 -              for (lineset = config->linesets.first; lineset; lineset = lineset->next) {
 -                      if (lineset->linestyle) {
 -                              ID *lid = &lineset->linestyle->id;
 -                              AnimData *adt = BKE_animdata_from_id(lid);
 -
 -                              if (adt && adt->drivers.first)
 -                                      BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS);
 -                      }
 -              }
 -      }
 -}
 -
 -/* deps hack - do extra recalcs at end */
 -static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
 -{
 -      Base *base;
 -              
 -      scene->customdata_mask = scene_parent->customdata_mask;
 -      
 -      /* sets first, we allow per definition current scene to have
 -       * dependencies on sets, but not the other way around. */
 -      if (scene->set)
 -              scene_depsgraph_hack(eval_ctx, scene->set, scene_parent);
 -      
 -      for (base = scene->base.first; base; base = base->next) {
 -              Object *ob = base->object;
 -              
 -              if (ob->depsflag) {
 -                      int recalc = 0;
 -                      // printf("depshack %s\n", ob->id.name + 2);
 -                      
 -                      if (ob->depsflag & OB_DEPS_EXTRA_OB_RECALC)
 -                              recalc |= OB_RECALC_OB;
 -                      if (ob->depsflag & OB_DEPS_EXTRA_DATA_RECALC)
 -                              recalc |= OB_RECALC_DATA;
 -                      
 -                      ob->recalc |= recalc;
 -                      BKE_object_handle_update(eval_ctx, scene_parent, ob);
 -                      
 -                      if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) {
 -                              GroupObject *go;
 -                              
 -                              for (go = ob->dup_group->gobject.first; go; go = go->next) {
 -                                      if (go->ob)
 -                                              go->ob->recalc |= recalc;
 -                              }
 -                              BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, ob, ob->dup_group);
 -                      }
 -              }
 -      }
 -}
 -#endif  /* WITH_LEGACY_DEPSGRAPH */
 -
  /* That's like really a bummer, because currently animation data for armatures
   * might want to use pose, and pose might be missing on the object.
   * This happens when changing visible layers, which leads to situations when
  static void scene_armature_depsgraph_workaround(Main *bmain)
  {
        Object *ob;
 -      if (BLI_listbase_is_empty(&bmain->armature) || !DAG_id_type_tagged(bmain, ID_OB)) {
 +      if (BLI_listbase_is_empty(&bmain->armature) || !DEG_id_type_tagged(bmain, ID_OB)) {
                return;
        }
        for (ob = bmain->object.first; ob; ob = ob->id.next) {
  }
  #endif
  
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
 -{
 -      if (scene->set)
 -              scene_rebuild_rbw_recursive(scene->set, ctime);
 -
 -      if (BKE_scene_check_rigidbody_active(scene))
 -              BKE_rigidbody_rebuild_world(scene, ctime);
 -}
 -
 -static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
 -{
 -      if (scene->set)
 -              scene_do_rb_simulation_recursive(scene->set, ctime);
 -
 -      if (BKE_scene_check_rigidbody_active(scene))
 -              BKE_rigidbody_do_simulation(scene, ctime);
 -}
 -#endif
 -
 -/* Used to visualize CPU threads activity during threaded object update,
 - * would pollute STDERR with whole bunch of timing information which then
 - * could be parsed and nicely visualized.
 - */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -#  undef DETAILED_ANALYSIS_OUTPUT
 -#else
 -/* ALWAYS KEEY DISABLED! */
 -#  undef DETAILED_ANALYSIS_OUTPUT
 -#endif
 -
 -/* Mballs evaluation uses BKE_scene_base_iter_next which calls
 - * duplilist for all objects in the scene. This leads to conflict
 - * accessing and writing same data from multiple threads.
 - *
 - * Ideally Mballs shouldn't do such an iteration and use DAG
 - * queries instead. For the time being we've got new DAG
 - * let's keep it simple and update mballs in a single thread.
 - */
 -#define MBALL_SINGLETHREAD_HACK
 -
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -typedef struct StatisicsEntry {
 -      struct StatisicsEntry *next, *prev;
 -      Object *object;
 -      double start_time;
 -      double duration;
 -} StatisicsEntry;
 -
 -typedef struct ThreadedObjectUpdateState {
 -      /* TODO(sergey): We might want this to be per-thread object. */
 -      EvaluationContext *eval_ctx;
 -      Scene *scene;
 -      Scene *scene_parent;
 -      double base_time;
 -
 -#ifdef MBALL_SINGLETHREAD_HACK
 -      bool has_mballs;
 -#endif
 -
 -      /* Execution statistics */
 -      bool has_updated_objects;
 -      ListBase *statistics;
 -} ThreadedObjectUpdateState;
 -
 -static void scene_update_object_add_task(void *node, void *user_data);
 -
 -static void scene_update_all_bases(EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
 -{
 -      Base *base;
 -
 -      for (base = scene->base.first; base; base = base->next) {
 -              Object *object = base->object;
 -
 -              BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, true);
 -
 -              if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
 -                      BKE_group_handle_recalc_and_update(eval_ctx, scene_parent, object, object->dup_group);
 -
 -              /* always update layer, so that animating layers works (joshua july 2010) */
 -              /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes
 -               * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */
 -              // base->lay = ob->lay;
 -      }
 -}
 -
 -static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid)
 -{
 -/* Disable print for now in favor of summary statistics at the end of update. */
 -#define PRINT if (false) printf
 -
 -      ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool);
 -      void *node = taskdata;
 -      Object *object = DAG_get_node_object(node);
 -      EvaluationContext *eval_ctx = state->eval_ctx;
 -      Scene *scene = state->scene;
 -      Scene *scene_parent = state->scene_parent;
 -
 -#ifdef MBALL_SINGLETHREAD_HACK
 -      if (object && object->type == OB_MBALL) {
 -              state->has_mballs = true;
 -      }
 -      else
 -#endif
 -      if (object) {
 -              double start_time = 0.0;
 -              bool add_to_stats = false;
 -
 -              if (G.debug & G_DEBUG_DEPSGRAPH) {
 -                      if (object->recalc & OB_RECALC_ALL) {
 -                              printf("Thread %d: update object %s\n", threadid, object->id.name);
 -                      }
 -
 -                      start_time = PIL_check_seconds_timer();
 -
 -                      if (object->recalc & OB_RECALC_ALL) {
 -                              state->has_updated_objects = true;
 -                              add_to_stats = true;
 -                      }
 -              }
 -
 -              /* We only update object itself here, dupli-group will be updated
 -               * separately from main thread because of we've got no idea about
 -               * dependencies inside the group.
 -               */
 -              BKE_object_handle_update_ex(eval_ctx, scene_parent, object, scene->rigidbody_world, false);
 -
 -              /* Calculate statistics. */
 -              if (add_to_stats) {
 -                      StatisicsEntry *entry;
 -
 -                      entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics");
 -                      entry->object = object;
 -                      entry->start_time = start_time;
 -                      entry->duration = PIL_check_seconds_timer() - start_time;
 -
 -                      BLI_addtail(&state->statistics[threadid], entry);
 -              }
 -      }
 -      else {
 -              PRINT("Threda %d: update node %s\n", threadid,
 -                    DAG_get_node_name(scene, node));
 -      }
 -
 -      /* Update will decrease child's valency and schedule child with zero valency. */
 -      DAG_threaded_update_handle_node_updated(node, scene_update_object_add_task, pool);
 -
 -#undef PRINT
 -}
 -
 -static void scene_update_object_add_task(void *node, void *user_data)
 -{
 -      TaskPool *task_pool = user_data;
 -
 -      BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW);
 -}
 -
 -static void print_threads_statistics(ThreadedObjectUpdateState *state)
 -{
 -      int i, tot_thread;
 -      double finish_time;
 -
 -      if ((G.debug & G_DEBUG_DEPSGRAPH) == 0) {
 -              return;
 -      }
 -
 -#ifdef DETAILED_ANALYSIS_OUTPUT
 -      if (state->has_updated_objects) {
 -              tot_thread = BLI_system_thread_count();
 -
 -              fprintf(stderr, "objects update base time %f\n", state->base_time);
 -
 -              for (i = 0; i < tot_thread; i++) {
 -                      StatisicsEntry *entry;
 -                      for (entry = state->statistics[i].first;
 -                           entry;
 -                           entry = entry->next)
 -                      {
 -                              fprintf(stderr, "thread %d object %s start_time %f duration %f\n",
 -                                      i, entry->object->id.name + 2,
 -                                      entry->start_time, entry->duration);
 -                      }
 -                      BLI_freelistN(&state->statistics[i]);
 -              }
 -      }
 -#else
 -      finish_time = PIL_check_seconds_timer();
 -      tot_thread = BLI_system_thread_count();
 -      int total_objects = 0;
 -
 -      for (i = 0; i < tot_thread; i++) {
 -              int thread_total_objects = 0;
 -              double thread_total_time = 0.0;
 -              StatisicsEntry *entry;
 -
 -              if (state->has_updated_objects) {
 -                      /* Don't pollute output if no objects were updated. */
 -                      for (entry = state->statistics[i].first;
 -                           entry;
 -                           entry = entry->next)
 -                      {
 -                              thread_total_objects++;
 -                              thread_total_time += entry->duration;
 -                      }
 -
 -                      printf("Thread %d: total %d objects in %f sec.\n",
 -                             i,
 -                             thread_total_objects,
 -                             thread_total_time);
 -
 -                      for (entry = state->statistics[i].first;
 -                           entry;
 -                           entry = entry->next)
 -                      {
 -                              printf("  %s in %f sec\n", entry->object->id.name + 2, entry->duration);
 -                      }
 -
 -                      total_objects += thread_total_objects;
 -              }
 -
 -              BLI_freelistN(&state->statistics[i]);
 -      }
 -      if (state->has_updated_objects) {
 -              printf("Scene updated %d objects in %f sec\n",
 -                     total_objects,
 -                     finish_time - state->base_time);
 -      }
 -#endif
 -}
 -
 -static bool scene_need_update_objects(Main *bmain)
 -{
 -      return
 -              /* Object datablocks themselves (for OB_RECALC_OB) */
 -              DAG_id_type_tagged(bmain, ID_OB) ||
 -
 -              /* Objects data datablocks (for OB_RECALC_DATA) */
 -              DAG_id_type_tagged(bmain, ID_ME)  ||  /* Mesh */
 -              DAG_id_type_tagged(bmain, ID_CU)  ||  /* Curve */
 -              DAG_id_type_tagged(bmain, ID_MB)  ||  /* MetaBall */
 -              DAG_id_type_tagged(bmain, ID_LA)  ||  /* Lamp */
 -              DAG_id_type_tagged(bmain, ID_LT)  ||  /* Lattice */
 -              DAG_id_type_tagged(bmain, ID_CA)  ||  /* Camera */
 -              DAG_id_type_tagged(bmain, ID_KE)  ||  /* KE */
 -              DAG_id_type_tagged(bmain, ID_SPK) ||  /* Speaker */
 -              DAG_id_type_tagged(bmain, ID_AR);     /* Armature */
 -}
 -
 -static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
 -{
 -      TaskScheduler *task_scheduler;
 -      TaskPool *task_pool;
 -      ThreadedObjectUpdateState state;
 -      bool need_singlethread_pass;
 -      bool need_free_scheduler;
 -
 -      /* Early check for whether we need to invoke all the task-based
 -       * things (spawn new ppol, traverse dependency graph and so on).
 -       *
 -       * Basically if there's no ID datablocks tagged for update which
 -       * corresponds to object->recalc flags (which are checked in
 -       * BKE_object_handle_update() then we do nothing here.
 -       */
 -      if (!scene_need_update_objects(bmain)) {
 -              return;
 -      }
 -
 -      state.eval_ctx = eval_ctx;
 -      state.scene = scene;
 -      state.scene_parent = scene_parent;
 -
 -      if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
 -              task_scheduler = BLI_task_scheduler_create(1);
 -              need_free_scheduler = true;
 -      }
 -      else {
 -              task_scheduler = BLI_task_scheduler_get();
 -              need_free_scheduler = false;
 -      }
 -
 -      /* Those are only needed when blender is run with --debug argument. */
 -      if (G.debug & G_DEBUG_DEPSGRAPH) {
 -              const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
 -              state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics),
 -                                             "scene update objects stats");
 -              state.has_updated_objects = false;
 -              state.base_time = PIL_check_seconds_timer();
 -      }
 -
 -#ifdef MBALL_SINGLETHREAD_HACK
 -      state.has_mballs = false;
 -#endif
 -
 -      task_pool = BLI_task_pool_create(task_scheduler, &state);
 -
 -      DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
 -      BLI_task_pool_work_and_wait(task_pool);
 -      BLI_task_pool_free(task_pool);
 -
 -      if (G.debug & G_DEBUG_DEPSGRAPH) {
 -              print_threads_statistics(&state);
 -              MEM_freeN(state.statistics);
 -      }
 -
 -      /* We do single thread pass to update all the objects which are in cyclic dependency.
 -       * Such objects can not be handled by a generic DAG traverse and it's really tricky
 -       * to detect whether cycle could be solved or not.
 -       *
 -       * In this situation we simply update all remaining objects in a single thread and
 -       * it'll happen in the same exact order as it was in single-threaded DAG.
 -       *
 -       * We couldn't use threaded update for objects which are in cycle because they might
 -       * access data of each other which is being re-evaluated.
 -       *
 -       * Also, as was explained above, for now we also update all the mballs in single thread.
 -       *
 -       *                                                                   - sergey -
 -       */
 -      need_singlethread_pass = DAG_is_acyclic(scene) == false;
 -#ifdef MBALL_SINGLETHREAD_HACK
 -      need_singlethread_pass |= state.has_mballs;
 -#endif
 -
 -      if (need_singlethread_pass) {
 -              scene_update_all_bases(eval_ctx, scene, scene_parent);
 -      }
 -
 -      if (need_free_scheduler) {
 -              BLI_task_scheduler_free(task_scheduler);
 -      }
 -}
 -
 -static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
 -{
 -      scene->customdata_mask = scene_parent->customdata_mask;
 -
 -      /* sets first, we allow per definition current scene to have
 -       * dependencies on sets, but not the other way around. */
 -      if (scene->set)
 -              scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent);
 -
 -      /* scene objects */
 -      scene_update_objects(eval_ctx, bmain, scene, scene_parent);
 -
 -      /* scene drivers... */
 -      scene_update_drivers(bmain, scene);
 -
 -      /* update masking curves */
 -      BKE_mask_update_scene(bmain, scene);
 -      
 -}
 -#endif  /* WITH_LEGACY_DEPSGRAPH */
 -
  static bool check_rendered_viewport_visible(Main *bmain)
  {
        wmWindowManager *wm = bmain->wm.first;
        wmWindow *window;
        for (window = wm->windows.first; window != NULL; window = window->next) {
 -              bScreen *screen = window->screen;
 +              const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
 +              Scene *scene = window->scene;
                ScrArea *area;
 +              RenderEngineType *type = RE_engines_find(scene->r.engine);
 +              if ((type->draw_engine != NULL) || (type->render_to_view == NULL)) {
 +                      continue;
 +              }
 +              const bool use_legacy = (type->flag & RE_USE_LEGACY_PIPELINE) != 0;
                for (area = screen->areabase.first; area != NULL; area = area->next) {
                        View3D *v3d = area->spacedata.first;
                        if (area->spacetype != SPACE_VIEW3D) {
                                continue;
                        }
 -                      if (v3d->drawtype == OB_RENDER) {
 +                      if (v3d->drawtype == OB_RENDER || !use_legacy) {
                                return true;
                        }
                }
@@@ -1494,7 -1790,7 +1504,7 @@@ static void prepare_mesh_for_viewport_r
                        if (check_rendered_viewport_visible(bmain)) {
                                BMesh *bm = mesh->edit_btmesh->bm;
                                BM_mesh_bm_to_me(bm, mesh, (&(struct BMeshToMeshParams){0}));
 -                              DAG_id_tag_update(&mesh->id, 0);
 +                              DEG_id_tag_update(&mesh->id, 0);
                        }
                }
        }
  void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
  {
        Scene *sce_iter;
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      bool use_new_eval = !DEG_depsgraph_use_legacy();
 -#endif
 -
 -      /* keep this first */
 -      BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
  
        /* (re-)build dependency graph if needed */
        for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
 -              DAG_scene_relations_update(bmain, sce_iter);
 +              DEG_scene_relations_update(bmain, sce_iter);
                /* Uncomment this to check if graph was properly tagged for update. */
  #if 0
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -              if (use_new_eval)
 -#endif
 -              {
 -                      DAG_scene_relations_validate(bmain, sce_iter);
 -              }
 +              DEG_scene_relations_validate(bmain, sce_iter);
  #endif
        }
  
        prepare_mesh_for_viewport_render(bmain, scene);
  
        /* flush recalc flags to dependencies */
 -      DAG_ids_flush_tagged(bmain);
 +      DEG_ids_flush_tagged(bmain, scene);
  
        /* removed calls to quick_cache, see pointcache.c */
        
         *
         * in the future this should handle updates for all datablocks, not
         * only objects and scenes. - brecht */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!use_new_eval) {
 -              scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
 -      }
 -      else
 -#endif
 -      {
 -              DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
 -              /* TODO(sergey): This is to beocme a node in new depsgraph. */
 -              BKE_mask_update_scene(bmain, scene);
 -      }
 +      DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
 +      /* TODO(sergey): This is to beocme a node in new depsgraph. */
 +      BKE_mask_update_scene(bmain, scene);
  
        /* update sound system animation (TODO, move to depsgraph) */
        BKE_sound_update_scene(bmain, scene);
                        BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0);
        }
  
 -      /* Extra call here to recalc material animation.
 -       *
 -       * Need to do this so changing material settings from the graph/dopesheet
 -       * will update stuff in the viewport.
 -       */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
 -              Material *material;
 -              float ctime = BKE_scene_frame_get(scene);
 -
 -              for (material = bmain->mat.first;
 -                   material;
 -                   material = material->id.next)
 -              {
 -                      AnimData *adt = BKE_animdata_from_id(&material->id);
 -                      if (adt && (adt->recalc & ADT_RECALC_ANIM))
 -                              BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0);
 -              }
 -      }
 -
 -      /* Also do the same for node trees. */
 -      if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
 -              float ctime = BKE_scene_frame_get(scene);
 -
 -              FOREACH_NODETREE(bmain, ntree, id)
 -              {
 -                      AnimData *adt = BKE_animdata_from_id(&ntree->id);
 -                      if (adt && (adt->recalc & ADT_RECALC_ANIM))
 -                              BKE_animsys_evaluate_animdata(scene, &ntree->id, adt, ctime, 0);
 -              }
 -              FOREACH_NODETREE_END
 -      }
 -#endif
 -
 -      /* notify editors and python about recalc */
 -      BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
 -
        /* Inform editors about possible changes. */
 -      DAG_ids_check_recalc(bmain, scene, false);
 +      DEG_ids_check_recalc(bmain, scene, false);
  
        /* clear recalc flags */
 -      DAG_ids_clear_recalc(bmain);
 +      DEG_ids_clear_recalc(bmain);
  }
  
  /* applies changes right away, does all sets too */
 -void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay)
 -{
 -      BKE_scene_update_for_newframe_ex(eval_ctx, bmain, sce, lay, false);
 -}
 -
 -void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool do_invisible_flush)
 +void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce)
  {
        float ctime = BKE_scene_frame_get(sce);
        Scene *sce_iter;
 -#ifdef DETAILED_ANALYSIS_OUTPUT
 -      double start_time = PIL_check_seconds_timer();
 -#endif
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      bool use_new_eval = !DEG_depsgraph_use_legacy();
 -#else
 -      /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */
 -      (void) do_invisible_flush;
 -#endif
  
 -      DAG_editors_update_pre(bmain, sce, true);
 +      DEG_editors_update_pre(bmain, sce, true);
  
        /* keep this first */
        BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
 -      BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
  
        /* update animated image textures for particles, modifiers, gpu, etc,
         * call this at the start so modifiers with textures don't lag 1 frame */
        BKE_image_update_frame(bmain, sce->r.cfra);
 -      
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      /* rebuild rigid body worlds before doing the actual frame update
 -       * this needs to be done on start frame but animation playback usually starts one frame later
 -       * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
 -       */
 -      if (!use_new_eval) {
 -              scene_rebuild_rbw_recursive(sce, ctime);
 -      }
 -#endif
 -      
 +
        BKE_sound_set_cfra(sce->r.cfra);
 -      
 +
        /* clear animation overrides */
        /* XXX TODO... */
  
        for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
 -              DAG_scene_relations_update(bmain, sce_iter);
 -
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!use_new_eval) {
 -              /* flush recalc flags to dependencies, if we were only changing a frame
 -               * this would not be necessary, but if a user or a script has modified
 -               * some datablock before BKE_scene_update_tagged was called, we need the flush */
 -              DAG_ids_flush_tagged(bmain);
 -
 -              /* Following 2 functions are recursive
 -               * so don't call within 'scene_update_tagged_recursive' */
 -              DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush);   // only stuff that moves or needs display still
 -      }
 -#endif
 +              DEG_scene_relations_update(bmain, sce_iter);
  
        BKE_mask_evaluate_all_masks(bmain, ctime, true);
  
        scene_armature_depsgraph_workaround(bmain);
  #endif
  
 -      /* All 'standard' (i.e. without any dependencies) animation is handled here,
 -       * with an 'local' to 'macro' order of evaluation. This should ensure that
 -       * settings stored nestled within a hierarchy (i.e. settings in a Texture block
 -       * can be overridden by settings from Scene, which owns the Texture through a hierarchy
 -       * such as Scene->World->MTex/Texture) can still get correctly overridden.
 -       */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!use_new_eval) {
 -              BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
 -              /*...done with recursive funcs */
 -      }
 -#endif
 -
        /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
         * when trying to find materials with drivers that need evaluating [#32017] 
         */
        BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
        BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
  
 -      /* run rigidbody sim */
 -      /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!use_new_eval) {
 -              scene_do_rb_simulation_recursive(sce, ctime);
 -      }
 -#endif
 -      
        /* BKE_object_handle_update() on all objects, groups and sets */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (use_new_eval) {
 -              DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
 -      }
 -      else {
 -              scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
 -      }
 -#else
 -      DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
 -#endif
 +      DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime);
  
        /* update sound system animation (TODO, move to depsgraph) */
        BKE_sound_update_scene(bmain, sce);
  
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!use_new_eval) {
 -              scene_depsgraph_hack(eval_ctx, sce, sce);
 -      }
 -#endif
 -
        /* notify editors and python about recalc */
 -      BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
        BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
  
        /* Inform editors about possible changes. */
 -      DAG_ids_check_recalc(bmain, sce, true);
 +      DEG_ids_check_recalc(bmain, sce, true);
  
        /* clear recalc flags */
 -      DAG_ids_clear_recalc(bmain);
 -
 -#ifdef DETAILED_ANALYSIS_OUTPUT
 -      fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time);
 -#endif
 +      DEG_ids_clear_recalc(bmain);
  }
  
  /* return default layer, also used to patch old files */
@@@ -1661,7 -2092,15 +1671,7 @@@ bool BKE_scene_remove_render_layer(Mai
  
        for (sce = bmain->scene.first; sce; sce = sce->id.next) {
                if (sce->nodetree) {
 -                      bNode *node;
 -                      for (node = sce->nodetree->nodes.first; node; node = node->next) {
 -                              if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
 -                                      if (node->custom1 == act)
 -                                              node->custom1 = 0;
 -                                      else if (node->custom1 > act)
 -                                              node->custom1--;
 -                              }
 -                      }
 +                      BKE_nodetree_remove_layer_n(sce->nodetree, scene, act);
                }
        }
  
@@@ -1748,40 -2187,21 +1758,40 @@@ float get_render_aosss_error(const Rend
                return error;
  }
  
 -/* helper function for the SETLOOPER macro */
 +/**
 +  * Helper function for the SETLOOPER macro
 +  *
 +  * It iterates over the bases of the active layer and then the bases
 +  * of the active layer of the background (set) scenes recursively.
 +  */
  Base *_setlooper_base_step(Scene **sce_iter, Base *base)
  {
        if (base && base->next) {
                /* common case, step to the next */
                return base->next;
        }
 -      else if (base == NULL && (*sce_iter)->base.first) {
 +      else if (base == NULL) {
                /* first time looping, return the scenes first base */
 -              return (Base *)(*sce_iter)->base.first;
 +
 +              /* for the first loop we should get the layer from context */
 +              SceneLayer *sl = BKE_scene_layer_context_active((*sce_iter));
 +              /* TODO For first scene (non-background set), we should pass the render layer as argument.
 +               * In some cases we want it to be the workspace one, in other the scene one. */
 +              TODO_LAYER;
 +
 +              if (sl->object_bases.first) {
 +                      return (Base *)sl->object_bases.first;
 +              }
 +              /* no base on this scene layer */
 +              goto next_set;
        }
        else {
 +next_set:
                /* reached the end, get the next base in the set */
                while ((*sce_iter = (*sce_iter)->set)) {
 -                      base = (Base *)(*sce_iter)->base.first;
 +                      SceneLayer *sl = BKE_scene_layer_render_active((*sce_iter));
 +                      base = (Base *)sl->object_bases.first;
 +
                        if (base) {
                                return base;
                        }
@@@ -1826,60 -2246,23 +1836,60 @@@ bool BKE_scene_uses_blender_game(const 
        return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME);
  }
  
 -void BKE_scene_base_flag_to_objects(struct Scene *scene)
 +bool BKE_scene_uses_blender_eevee(const Scene *scene)
 +{
 +      return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
 +}
 +
 +void BKE_scene_base_flag_to_objects(SceneLayer *sl)
  {
 -      Base *base = scene->base.first;
 +      Base *base = sl->object_bases.first;
  
        while (base) {
 -              base->object->flag = base->flag;
 +              BKE_scene_object_base_flag_sync_from_base(base);
                base = base->next;
        }
  }
  
 -void BKE_scene_base_flag_from_objects(struct Scene *scene)
 +void BKE_scene_base_flag_sync_from_base(BaseLegacy *base)
  {
 -      Base *base = scene->base.first;
 +      BKE_scene_object_base_flag_sync_from_base(base);
 +}
  
 -      while (base) {
 -              base->flag = base->object->flag;
 -              base = base->next;
 +void BKE_scene_base_flag_sync_from_object(BaseLegacy *base)
 +{
 +      BKE_scene_object_base_flag_sync_from_object(base);
 +}
 +
 +void BKE_scene_object_base_flag_sync_from_base(Base *base)
 +{
 +      Object *ob = base->object;
 +
 +      /* keep the object only flags untouched */
 +      int flag = ob->flag & OB_FROMGROUP;
 +
 +      ob->flag = base->flag;
 +      ob->flag |= flag;
 +
 +      if ((base->flag & BASE_SELECTED) != 0) {
 +              ob->flag |= SELECT;
 +      }
 +      else {
 +              ob->flag &= ~SELECT;
 +      }
 +}
 +
 +void BKE_scene_object_base_flag_sync_from_object(Base *base)
 +{
 +      Object *ob = base->object;
 +      base->flag = ob->flag;
 +
 +      if ((ob->flag & SELECT) != 0) {
 +              base->flag |= BASE_SELECTED;
 +              BLI_assert((base->flag & BASE_SELECTABLED) != 0);
 +      }
 +      else {
 +              base->flag &= ~BASE_SELECTED;
        }
  }
  
index 8890aa5d1ac5c6ab466d7b752bc2a5acee830e35,a0d67626940ae9df3ec6d8878ff6bc581560b85f..659dfbfd57d507afcbfcc16fa941ca46941d3111
@@@ -56,6 -56,7 +56,6 @@@
  
  #include "BKE_colortools.h"
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_DerivedMesh.h"
  #include "BKE_icons.h"
  #include "BKE_image.h"
@@@ -69,8 -70,6 +69,8 @@@
  #include "BKE_sound.h"
  #include "BKE_scene.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "GPU_draw.h"
  #include "GPU_buffers.h"
  
@@@ -793,7 -792,6 +793,7 @@@ static int image_view_selected_exec(bCo
        SpaceImage *sima;
        ARegion *ar;
        Scene *scene;
 +      SceneLayer *sl;
        Object *obedit;
        Image *ima;
  
        sima = CTX_wm_space_image(C);
        ar = CTX_wm_region(C);
        scene = CTX_data_scene(C);
 +      sl = CTX_data_scene_layer(C);
        obedit = CTX_data_edit_object(C);
  
        ima = ED_space_image(sima);
                        return OPERATOR_CANCELLED;
                }
        }
 -      else if (ED_space_image_check_show_maskedit(scene, sima)) {
 +      else if (ED_space_image_check_show_maskedit(sl, sima)) {
                if (!ED_mask_selected_minmax(C, min, max)) {
                        return OPERATOR_CANCELLED;
                }
@@@ -1330,7 -1327,11 +1330,11 @@@ static int image_open_exec(bContext *C
                iuser->frames = frame_seq_len;
                iuser->sfra = 1;
                iuser->framenr = 1;
-               iuser->offset = frame_ofs - 1;
+               if (ima->source == IMA_SRC_MOVIE) {
+                       iuser->offset = 0;
+               } else {
+                       iuser->offset = frame_ofs - 1;
+               }
                iuser->fie_ima = 2;
                iuser->scene = scene;
                BKE_image_init_imageuser(ima, iuser);
@@@ -2344,7 -2345,7 +2348,7 @@@ static int image_reload_exec(bContext *
        
        // XXX other users?
        BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
 -      DAG_id_tag_update(&ima->id, 0);
 +      DEG_id_tag_update(&ima->id, 0);
  
        WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
        
index 799fb6d501886b6dc327e3118c7bec634a46c3bb,73fd77db4776be7e830109a6efe8425a34121fc0..471b8ae29d9f4a86b146562f1eed7469845d92b3
@@@ -62,7 -62,6 +62,7 @@@
  #include "BKE_global.h"
  #include "BKE_image.h"
  #include "BKE_key.h"
 +#include "BKE_layer.h"
  #include "BKE_lattice.h"
  #include "BKE_main.h"
  #include "BKE_mesh.h"
  #include "GPU_select.h"
  #include "GPU_basic_shader.h"
  #include "GPU_shader.h"
 +#include "GPU_immediate.h"
 +#include "GPU_immediate_util.h"
 +#include "GPU_batch.h"
 +#include "GPU_matrix.h"
  
  #include "ED_mesh.h"
  #include "ED_particle.h"
  
  #include "view3d_intern.h"  /* bad level include */
  
 +#include "../../draw/intern/draw_cache_impl.h"  /* bad level include (temporary) */
 +
 +/* prototypes */
 +static void imm_draw_box(const float vec[8][3], bool solid, unsigned pos);
 +
  /* Workaround for sequencer scene render mode.
   *
   * Strips doesn't use DAG to update objects or so, which
@@@ -139,7 -129,6 +139,7 @@@ typedef struct drawDMVerts_userData 
  
        BMVert *eve_act;
        char sel;
 +      unsigned int pos, color;
  
        /* cached theme values */
        unsigned char th_editmesh_active[4];
@@@ -192,7 -181,6 +192,7 @@@ typedef struct drawDMFacesSel_userData 
  } drawDMFacesSel_userData;
  
  typedef struct drawDMNormal_userData {
 +      unsigned int pos;
        BMesh *bm;
        int uniform_scale;
        float normalsize;
  } drawDMNormal_userData;
  
  typedef struct drawMVertOffset_userData {
 +      unsigned int pos, col;
        MVert *mvert;
        int offset;
  } drawMVertOffset_userData;
  typedef struct drawDMLayer_userData {
        BMesh *bm;
        int cd_layer_offset;
 +      unsigned int pos, col;
  } drawDMLayer_userData;
  
  typedef struct drawBMOffset_userData {
 +      unsigned int pos, col;
        BMesh *bm;
        int offset;
  } drawBMOffset_userData;
  typedef struct drawBMSelect_userData {
        BMesh *bm;
        bool select;
 +      unsigned int pos;
  } drawBMSelect_userData;
  
 -static void draw_bounding_volume(Object *ob, char type);
  
 -static void drawcube_size(float size);
 -static void drawcircle_size(float size);
 -static void draw_empty_sphere(float size);
 -static void draw_empty_cone(float size);
 -static void draw_box(const float vec[8][3], bool solid);
 +static void drawcube_size(float size, unsigned pos);
 +static void drawcircle_size(float size, unsigned pos);
 +static void draw_empty_sphere(float size, unsigned pos);
 +static void draw_empty_cone(float size, unsigned pos);
  
 -static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
 +static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac, float r_col[3])
  {
 -      float col_wire[3], col_bg[3], col[3];
 +      float col_wire[3], col_bg[3];
  
        rgb_uchar_to_float(col_wire, ob_wire_col);
  
        UI_GetThemeColor3fv(theme_id, col_bg);
 -      interp_v3_v3v3(col, col_bg, col_wire, fac);
 -      glColor3fv(col);
 +      interp_v3_v3v3(r_col, col_bg, col_wire, fac);
  }
  
  int view3d_effective_drawtype(const struct View3D *v3d)
@@@ -309,13 -296,13 +309,13 @@@ static bool check_ob_drawface_dot(Scen
  
  /* check for glsl drawing */
  
 -bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
 +bool draw_glsl_material(Scene *scene, SceneLayer *sl, Object *ob, View3D *v3d, const char dt)
  {
        if (G.f & G_PICKSEL)
                return false;
        if (!check_object_draw_texture(scene, v3d, dt))
                return false;
 -      if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
 +      if (ob == OBACT_NEW && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
                return false;
        
        if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)
  
  static bool check_alpha_pass(Base *base)
  {
 -      if (base->flag & OB_FROMDUPLI)
 +      if (base->flag_legacy & OB_FROMDUPLI)
                return false;
  
        if (G.f & G_PICKSEL)
@@@ -427,9 -414,9 +427,9 @@@ static const float cosval[CIRCLE_RESOL
   * \param viewmat_local_unit is typically the 'rv3d->viewmatob'
   * copied into a 3x3 matrix and normalized.
   */
 -static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis)
 +static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis, unsigned pos)
  {
 -      int line_type;
 +      Gwn_PrimType line_type = GWN_PRIM_LINES;
        float buffer[4][3];
        int n = 0;
  
  
        switch (axis) {
                case 0:     /* x axis */
 -                      line_type = GL_LINES;
 -
                        /* bottom left to top right */
                        negate_v3_v3(v1, dx);
                        sub_v3_v3(v1, dy);
  
                        break;
                case 1:     /* y axis */
 -                      line_type = GL_LINES;
 -                      
                        /* bottom left to top right */
                        mul_v3_fl(dx, 0.75f);
                        negate_v3_v3(v1, dx);
                        
                        break;
                case 2:     /* z axis */
 -                      line_type = GL_LINE_STRIP;
 +                      line_type = GWN_PRIM_LINE_STRIP;
                        
                        /* start at top left */
                        negate_v3_v3(v1, dx);
                        return;
        }
  
 +      immBegin(line_type, n);
        for (int i = 0; i < n; i++) {
                mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
                add_v3_v3(buffer[i], c);
 +              immVertex3fv(pos, buffer[i]);
        }
 +      immEnd();
  
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, buffer);
 -      glDrawArrays(line_type, 0, n);
 -      glDisableClientState(GL_VERTEX_ARRAY);
 +      /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */
  }
  
 -void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
 +void drawaxes(const float viewmat_local[4][4], float size, char drawtype, const unsigned char color[4])
  {
        int axis;
        float v1[3] = {0.0, 0.0, 0.0};
        float v2[3] = {0.0, 0.0, 0.0};
        float v3[3] = {0.0, 0.0, 0.0};
  
 -      glLineWidth(1);
 +      glLineWidth(1.0f);
 +
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (color) {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformColor4ubv(color);
 +      }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
 +      }
  
        switch (drawtype) {
 -
                case OB_PLAINAXES:
 +                      immBegin(GWN_PRIM_LINES, 6);
                        for (axis = 0; axis < 3; axis++) {
 -                              glBegin(GL_LINES);
 -
                                v1[axis] = size;
                                v2[axis] = -size;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
  
                                /* reset v1 & v2 to zero */
                                v1[axis] = v2[axis] = 0.0f;
 -
 -                              glEnd();
                        }
 +                      immEnd();
                        break;
 -              case OB_SINGLE_ARROW:
  
 -                      glBegin(GL_LINES);
 +              case OB_SINGLE_ARROW:
 +                      immBegin(GWN_PRIM_LINES, 2);
                        /* in positive z direction only */
                        v1[2] = size;
 -                      glVertex3fv(v1);
 -                      glVertex3fv(v2);
 -                      glEnd();
 +                      immVertex3fv(pos, v1);
 +                      immVertex3fv(pos, v2);
 +                      immEnd();
  
                        /* square pyramid */
 -                      glBegin(GL_TRIANGLES);
 +                      immBegin(GWN_PRIM_TRIS, 12);
  
                        v2[0] = size * 0.035f; v2[1] = size * 0.035f;
                        v3[0] = size * -0.035f; v3[1] = size * 0.035f;
                                        v3[0] = -v3[0];
                                }
  
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 -                              glVertex3fv(v3);
 -
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
 +                              immVertex3fv(pos, v3);
                        }
 -                      glEnd();
 -
 +                      immEnd();
                        break;
 +
                case OB_CUBE:
 -                      drawcube_size(size);
 +                      drawcube_size(size, pos);
                        break;
  
                case OB_CIRCLE:
 -                      drawcircle_size(size);
 +                      drawcircle_size(size, pos);
                        break;
  
                case OB_EMPTY_SPHERE:
 -                      draw_empty_sphere(size);
 +                      draw_empty_sphere(size, pos);
                        break;
  
                case OB_EMPTY_CONE:
 -                      draw_empty_cone(size);
 +                      draw_empty_cone(size, pos);
                        break;
  
                case OB_ARROWS:
                        for (axis = 0; axis < 3; axis++) {
                                const int arrow_axis = (axis == 0) ? 1 : 0;
  
 -                              glBegin(GL_LINES);
 +                              immBegin(GWN_PRIM_LINES, 6);
  
                                v2[axis] = size;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 -                              
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
 +
                                v1[axis] = size * 0.85f;
                                v1[arrow_axis] = -size * 0.08f;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 -                              
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
 +
                                v1[arrow_axis] = size * 0.08f;
 -                              glVertex3fv(v1);
 -                              glVertex3fv(v2);
 +                              immVertex3fv(pos, v1);
 +                              immVertex3fv(pos, v2);
  
 -                              glEnd();
 -                              
 -                              v2[axis] += size * 0.125f;
 +                              immEnd();
  
 -                              draw_xyz_wire(viewmat_local_unit, v2, size, axis);
 +                              v2[axis] += size * 0.125f;
  
 +                              draw_xyz_wire(viewmat_local_unit, v2, size, axis, pos);
  
                                /* reset v1 & v2 to zero */
                                v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f;
                        }
 -                      break;
                }
        }
 +
 +      immUnbindProgram();
  }
  
  
  static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview)
  {
        Image *ima = ob->data;
 -      ImBuf *ibuf;
 -      ImageUser iuser = *ob->iuser;
  
 -      /* Support multi-view */
 -      if (ima && (sview == STEREO_RIGHT_ID)) {
 -              iuser.multiview_eye = sview;
 -              iuser.flag |= IMA_SHOW_STEREO;
 -              BKE_image_multiview_index(ima, &iuser);
 -      }
 +      const float ob_alpha = ob->col[3];
 +      float ima_x, ima_y;
  
 -      ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
 +      int bindcode = 0;
  
 -      if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
 -              IMB_rect_from_float(ibuf);
 -      }
 +      if (ima) {
 +              ImageUser iuser = *ob->iuser;
  
 -      int ima_x, ima_y;
 +              /* Support multi-view */
 +              if (ima && (sview == STEREO_RIGHT_ID)) {
 +                      iuser.multiview_eye = sview;
 +                      iuser.flag |= IMA_SHOW_STEREO;
 +                      BKE_image_multiview_index(ima, &iuser);
 +              }
 +
 +              if (ob_alpha > 0.0f) {
 +                      bindcode = GPU_verify_image(ima, &iuser, GL_TEXTURE_2D, 0, false, false, false);
 +                      /* don't bother drawing the image if alpha = 0 */
 +              }
  
 -      /* Get the buffer dimensions so we can fallback to fake ones */
 -      if (ibuf && ibuf->rect) {
 -              ima_x = ibuf->x;
 -              ima_y = ibuf->y;
 +              int w, h;
 +              BKE_image_get_size(ima, &iuser, &w, &h);
 +              ima_x = w;
 +              ima_y = h;
        }
        else {
 -              ima_x = 1;
 -              ima_y = 1;
 +              /* if no image, make it a 1x1 empty square, honor scale & offset */
 +              ima_x = ima_y = 1.0f;
        }
  
 -      float sca_x = 1.0f;
 -      float sca_y = 1.0f;
 -
        /* Get the image aspect even if the buffer is invalid */
 +      float sca_x = 1.0f, sca_y = 1.0f;
        if (ima) {
                if (ima->aspx > ima->aspy) {
                        sca_y = ima->aspy / ima->aspx;
                }
        }
  
 -      /* Calculate the scale center based on object's origin */
 -      float ofs_x = ob->ima_ofs[0] * ima_x;
 -      float ofs_y = ob->ima_ofs[1] * ima_y;
 +      float scale_x;
 +      float scale_y;
 +      {
 +              const float scale_x_inv = ima_x * sca_x;
 +              const float scale_y_inv = ima_y * sca_y;
 +              if (scale_x_inv > scale_y_inv) {
 +                      scale_x = ob->empty_drawsize;
 +                      scale_y = ob->empty_drawsize * (scale_y_inv / scale_x_inv);
 +              }
 +              else {
 +                      scale_x = ob->empty_drawsize * (scale_x_inv / scale_y_inv);
 +                      scale_y = ob->empty_drawsize;
 +              }
 +      }
  
 -      glMatrixMode(GL_MODELVIEW);
 -      glPushMatrix();
 +      const float ofs_x = ob->ima_ofs[0] * scale_x;
 +      const float ofs_y = ob->ima_ofs[1] * scale_y;
  
 -      /* Calculate Image scale */
 -      float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
 +      const rctf rect = {
 +              .xmin = ofs_x,
 +              .xmax = ofs_x + scale_x,
 +              .ymin = ofs_y,
 +              .ymax = ofs_y + scale_y,
 +      };
  
 -      /* Set the object scale */
 -      glScalef(scale * sca_x, scale * sca_y, 1.0f);
 +      bool use_blend = false;
  
 -      if (ibuf && ibuf->rect) {
 -              const bool use_clip = (U.glalphaclip != 1.0f);
 -              int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP) ? GL_NEAREST : GL_LINEAR;
 -              /* Setup GL params */
 -              glEnable(GL_BLEND);
 -              glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +      if (bindcode) {
 +              use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima);
  
 -              if (use_clip) {
 -                      glEnable(GL_ALPHA_TEST);
 -                      glAlphaFunc(GL_GREATER, U.glalphaclip);
 +              if (use_blend) {
 +                      glEnable(GL_BLEND);
 +                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                }
  
 -              /* Use the object color and alpha */
 -              glColor4fv(ob->col);
 +              Gwn_VertFormat *format = immVertexFormat();
 +              unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +              unsigned int texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
 +              immUniform1f("alpha", ob_alpha);
 +              immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
  
 -              /* Draw the Image on the screen */
 -              glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
 +              immBegin(GWN_PRIM_TRI_FAN, 4);
 +              immAttrib2f(texCoord, 0.0f, 0.0f);
 +              immVertex2f(pos, rect.xmin, rect.ymin);
  
 -              glDisable(GL_BLEND);
 +              immAttrib2f(texCoord, 1.0f, 0.0f);
 +              immVertex2f(pos, rect.xmax, rect.ymin);
  
 -              if (use_clip) {
 -                      glDisable(GL_ALPHA_TEST);
 -                      glAlphaFunc(GL_ALWAYS, 0.0f);
 -              }
 +              immAttrib2f(texCoord, 1.0f, 1.0f);
 +              immVertex2f(pos, rect.xmax, rect.ymax);
 +
 +              immAttrib2f(texCoord, 0.0f, 1.0f);
 +              immVertex2f(pos, rect.xmin, rect.ymax);
 +              immEnd();
 +
 +              immUnbindProgram();
 +
 +              glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */
        }
  
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              glColor3ubv(ob_wire_col);
 +      /* Draw the image outline */
 +      glLineWidth(1.5f);
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +
 +      const bool picking = dflag & DRAW_CONSTCOLOR;
 +      if (picking) {
 +              /* TODO: deal with picking separately, use this function just to draw */
 +              immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
 +              if (use_blend) {
 +                      glDisable(GL_BLEND);
 +              }
 +
 +              imm_draw_line_box(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
        }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformColor3ubv(ob_wire_col);
 +              glEnable(GL_LINE_SMOOTH);
  
 -      /* Calculate the outline vertex positions */
 -      glBegin(GL_LINE_LOOP);
 -      glVertex2f(ofs_x, ofs_y);
 -      glVertex2f(ofs_x + ima_x, ofs_y);
 -      glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
 -      glVertex2f(ofs_x, ofs_y + ima_y);
 -      glEnd();
 +              if (!use_blend) {
 +                      glEnable(GL_BLEND);
 +                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +              }
  
 -      /* Reset GL settings */
 -      glPopMatrix();
 +              imm_draw_line_box(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 +
 +              glDisable(GL_LINE_SMOOTH);
 +              glDisable(GL_BLEND);
 +      }
  
 -      BKE_image_release_ibuf(ima, ibuf, NULL);
 +      immUnbindProgram();
  }
  
  static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
        }
  }
  
 -void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4])
 +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos)
  {
        float verts[CIRCLE_RESOL][3];
  
        circball_array_fill(verts, cent, rad, tmat);
  
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, verts);
 -      glDrawArrays(mode, 0, CIRCLE_RESOL);
 -      glDisableClientState(GL_VERTEX_ARRAY);
 +      immBegin(GWN_PRIM_LINE_LOOP, CIRCLE_RESOL);
 +      for (int i = 0; i < CIRCLE_RESOL; ++i) {
 +              immVertex3fv(pos, verts[i]);
 +      }
 +      immEnd();
  }
  
  /* circle for object centers, special_color is for library or ob users */
 -static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color)
 +static void drawcentercircle(View3D *v3d, RegionView3D *UNUSED(rv3d), const float co[3], int selstate, bool special_color)
  {
 -      const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
 -      float verts[CIRCLE_RESOL][3];
 +      const float outlineWidth = 1.0f * U.pixelsize;
 +      const float size = U.obcenter_dia * U.pixelsize + outlineWidth;
 +
 +      if (v3d->zbuf) {
 +              glDisable(GL_DEPTH_TEST);
 +              /* TODO(merwin): fit things like this into plates/buffers design */
 +      }
  
 -      /* using glDepthFunc guarantees that it does write z values,
 -       * but not checks for it, so centers remain visible independent of draw order */
 -      if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
 -      /* write to near buffer always */
 -      glDepthRange(0.0, 0.0);
        glEnable(GL_BLEND);
 -      
 +      GPU_enable_program_point_size();
 +
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
 +      immUniform1f("size", size);
 +
        if (special_color) {
 -              if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
 -              else glColor4ub(0x55, 0xCC, 0xCC, 155);
 +              if (selstate == ACTIVE || selstate == SELECT) immUniformColor4ub(0x88, 0xFF, 0xFF, 155);
 +              else immUniformColor4ub(0x55, 0xCC, 0xCC, 155);
        }
        else {
 -              if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
 -              else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
 -              else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
 +              if (selstate == ACTIVE) immUniformThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
 +              else if (selstate == SELECT) immUniformThemeColorShadeAlpha(TH_SELECT, 0, -80);
 +              else if (selstate == DESELECT) immUniformThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
        }
  
 -      circball_array_fill(verts, co, size, rv3d->viewinv);
 -
 -      /* enable vertex array */
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, verts);
 -
 -      /* 1. draw filled, blended polygon */
 -      glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
 +      /* set up outline */
 +      float outlineColor[4];
 +      UI_GetThemeColorShadeAlpha4fv(TH_WIRE, 0, -30, outlineColor);
 +      immUniform4fv("outlineColor", outlineColor);
 +      immUniform1f("outlineWidth", outlineWidth);
  
 -      /* 2. draw outline */
 -      glLineWidth(1);
 -      UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
 -      glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
 +      immBegin(GWN_PRIM_POINTS, 1);
 +      immVertex3fv(pos, co);
 +      immEnd();
  
 -      /* finish up */
 -      glDisableClientState(GL_VERTEX_ARRAY);
 +      immUnbindProgram();
  
 -      glDepthRange(0.0, 1.0);
 +      GPU_disable_program_point_size();
        glDisable(GL_BLEND);
  
 -      if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
 +      if (v3d->zbuf) {
 +              glEnable(GL_DEPTH_TEST);
 +      }
  }
  
  /* *********** text drawing for object/particles/armature ************* */
@@@ -948,30 -893,36 +948,30 @@@ void view3d_cached_text_draw_end(View3
        if (tot) {
                int col_pack_prev = 0;
  
 -#if 0
 -              bglMats mats; /* ZBuffer depth vars */
 -              double ux, uy, uz;
 -              float depth;
 -
 -              if (v3d->zbuf)
 -                      bgl_get_mats(&mats);
 -#endif
                if (rv3d->rflag & RV3D_CLIPPING) {
                        ED_view3d_clipping_disable();
                }
  
 -              glMatrixMode(GL_PROJECTION);
 -              glPushMatrix();
 -              glMatrixMode(GL_MODELVIEW);
 -              glPushMatrix();
 +              float original_proj[4][4];
 +              gpuGetProjectionMatrix(original_proj);
                wmOrtho2_region_pixelspace(ar);
 -              glLoadIdentity();
 +
 +              gpuPushMatrix();
 +              gpuLoadIdentity();
                
                if (depth_write) {
                        if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
                }
                else {
 -                      glDepthMask(0);
 +                      glDepthMask(GL_FALSE);
                }
                
 +              const int font_id = BLF_default();
 +
                for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
                        if (vos->sco[0] != IS_CLIPPED) {
                                if (col_pack_prev != vos->col.pack) {
 -                                      glColor3ubv(vos->col.ub);
 +                                      BLF_color3ubv(font_id, vos->col.ub);
                                        col_pack_prev = vos->col.pack;
                                }
  
                        if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
                }
                else {
 -                      glDepthMask(1);
 +                      glDepthMask(GL_TRUE);
                }
                
 -              glMatrixMode(GL_PROJECTION);
 -              glPopMatrix();
 -              glMatrixMode(GL_MODELVIEW);
 -              glPopMatrix();
 +              gpuPopMatrix();
 +              gpuLoadProjectionMatrix(original_proj);
  
                if (rv3d->rflag & RV3D_CLIPPING) {
                        ED_view3d_clipping_enable();
  /* draws a cube given the scaling of the cube, assuming that
   * all required matrices have been set (used for drawing empties)
   */
 -static void drawcube_size(float size)
 +static void drawcube_size(float size, unsigned pos)
  {
 -      const GLfloat pos[8][3] = {
 +      const float verts[8][3] = {
                {-size, -size, -size},
                {-size, -size,  size},
                {-size,  size, -size},
  
        const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6};
  
 +#if 0
        glEnableClientState(GL_VERTEX_ARRAY);
 -      glVertexPointer(3, GL_FLOAT, 0, pos);
 +      glVertexPointer(3, GL_FLOAT, 0, verts);
        glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
        glDisableClientState(GL_VERTEX_ARRAY);
 +#else
 +      immBegin(GWN_PRIM_LINES, 24);
 +      for (int i = 0; i < 24; ++i) {
 +              immVertex3fv(pos, verts[indices[i]]);
 +      }
 +      immEnd();
 +#endif
  }
  
 -static void drawshadbuflimits(Lamp *la, float mat[4][4])
 +static void drawshadbuflimits(const Lamp *la, const float mat[4][4], unsigned pos)
  {
        float sta[3], end[3], lavec[3];
  
        madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
        madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
  
 -      glBegin(GL_LINES);
 -      glVertex3fv(sta);
 -      glVertex3fv(end);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 2);
 +      immVertex3fv(pos, sta);
 +      immVertex3fv(pos, end);
 +      immEnd();
  
 -      glPointSize(3.0);
 -      glBegin(GL_POINTS);
 -      glVertex3fv(sta);
 -      glVertex3fv(end);
 -      glEnd();
 +      glPointSize(3.0f);
 +      immBegin(GWN_PRIM_POINTS, 2);
 +      immVertex3fv(pos, sta);
 +      immVertex3fv(pos, end);
 +      immEnd();
  }
  
  static void spotvolume(float lvec[3], float vvec[3], const float inp)
        mul_m3_v3(mat2, vvec);
  }
  
 -static void draw_spot_cone(Lamp *la, float x, float z)
 +static void draw_spot_cone(Lamp *la, float x, float z, unsigned pos)
  {
        z = fabsf(z);
  
 -      glBegin(GL_TRIANGLE_FAN);
 -      glVertex3f(0.0f, 0.0f, -x);
 +      const bool square = (la->mode & LA_SQUARE);
  
 -      if (la->mode & LA_SQUARE) {
 -              glVertex3f(z, z, 0);
 -              glVertex3f(-z, z, 0);
 -              glVertex3f(-z, -z, 0);
 -              glVertex3f(z, -z, 0);
 -              glVertex3f(z, z, 0);
 +      immBegin(GWN_PRIM_TRI_FAN, square ? 6 : 34);
 +      immVertex3f(pos, 0.0f, 0.0f, -x);
 +
 +      if (square) {
 +              immVertex3f(pos, z, z, 0);
 +              immVertex3f(pos, -z, z, 0);
 +              immVertex3f(pos, -z, -z, 0);
 +              immVertex3f(pos, z, -z, 0);
 +              immVertex3f(pos, z, z, 0);
        }
        else {
                for (int a = 0; a < 33; a++) {
                        float angle = a * M_PI * 2 / (33 - 1);
 -                      glVertex3f(z * cosf(angle), z * sinf(angle), 0);
 +                      immVertex3f(pos, z * cosf(angle), z * sinf(angle), 0.0f);
                }
        }
  
 -      glEnd();
 +      immEnd();
  }
  
 -static void draw_transp_spot_volume(Lamp *la, float x, float z)
 +static void draw_transp_spot_volume(Lamp *la, float x, float z, unsigned pos)
  {
        glEnable(GL_CULL_FACE);
        glEnable(GL_BLEND);
 -      glDepthMask(0);
 +      glDepthMask(GL_FALSE);
  
        /* draw backside darkening */
        glCullFace(GL_FRONT);
  
        glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
 -      glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
 +      immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
  
 -      draw_spot_cone(la, x, z);
 +      draw_spot_cone(la, x, z, pos);
  
        /* draw front side lighting */
        glCullFace(GL_BACK);
  
        glBlendFunc(GL_ONE, GL_ONE);
 -      glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
 +      immUniformColor3f(0.2f, 0.2f, 0.2f);
  
 -      draw_spot_cone(la, x, z);
 +      draw_spot_cone(la, x, z, pos);
  
        /* restore state */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDisable(GL_BLEND);
 -      glDepthMask(1);
 +      glDepthMask(GL_TRUE);
        glDisable(GL_CULL_FACE);
 -      glCullFace(GL_BACK);
  }
  
  #ifdef WITH_GAMEENGINE
 -static void draw_transp_sun_volume(Lamp *la)
 +static void draw_transp_sun_volume(Lamp *la, unsigned pos)
  {
        float box[8][3];
  
        box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta;
  
        /* draw edges */
 -      draw_box(box, false);
 +      imm_draw_box(box, false, pos);
  
        /* draw faces */
        glEnable(GL_CULL_FACE);
        glEnable(GL_BLEND);
 -      glDepthMask(0);
 +      glDepthMask(GL_FALSE);
  
        /* draw backside darkening */
        glCullFace(GL_FRONT);
  
        glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
 -      glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
 +      immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
  
 -      draw_box(box, true);
 +      imm_draw_box(box, true, pos);
  
        /* draw front side lighting */
        glCullFace(GL_BACK);
  
        glBlendFunc(GL_ONE, GL_ONE);
 -      glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
 +      immUniformColor3f(0.2f, 0.2f, 0.2f);
  
 -      draw_box(box, true);
 +      imm_draw_box(box, true, pos);
  
        /* restore state */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDisable(GL_BLEND);
 -      glDepthMask(1);
 +      glDepthMask(GL_TRUE);
        glDisable(GL_CULL_FACE);
 -      glCullFace(GL_BACK);
  }
  #endif
  
 -static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
 -                     const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
 +void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
 +              const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
  {
        Object *ob = base->object;
        const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
        Lamp *la = ob->data;
        float vec[3], lvec[3], vvec[3], circrad;
 -      float lampsize;
        float imat[4][4];
  
 -      unsigned char curcol[4];
 -      unsigned char col[4];
        /* cone can't be drawn for duplicated lamps, because duplilist would be freed */
        /* the moment of view3d_draw_transp() call */
        const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object);
                               !(G.f & G_PICKSEL) &&
                               (la->type == LA_SPOT) &&
                               (la->mode & LA_SHOW_CONE) &&
 -                             !(base->flag & OB_FROMDUPLI) &&
 +                             !(base->flag_legacy & OB_FROMDUPLI) &&
                               !is_view);
  
  #ifdef WITH_GAMEENGINE
                ((la->mode & LA_SHAD_BUF) || 
                (la->mode & LA_SHAD_RAY)) &&
                (la->mode & LA_SHOW_SHADOW_BOX) &&
 -              !(base->flag & OB_FROMDUPLI) &&
 +              !(base->flag_legacy & OB_FROMDUPLI) &&
                !is_view);
  #else
        const bool drawshadowbox = false;
  
        if ((drawcone || drawshadowbox) && !v3d->transp) {
                /* in this case we need to draw delayed */
 -              ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag);
 +              ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag);
                return;
        }
 -      
 +
        /* we first draw only the screen aligned & fixed scale stuff */
 -      glPushMatrix();
 -      glLoadMatrixf(rv3d->viewmat);
 +      gpuPushMatrix();
 +      gpuLoadMatrix(rv3d->viewmat);
  
        /* lets calculate the scale: */
 -      lampsize = pixsize * ((float)U.obcenter_dia * 0.5f);
 +      const float lampsize_px = U.obcenter_dia;
 +      const float lampsize = pixsize * lampsize_px * 0.5f;
  
        /* and view aligned matrix: */
        copy_m4_m4(imat, rv3d->viewinv);
        normalize_v3(imat[0]);
        normalize_v3(imat[1]);
  
 +      const unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
        /* lamp center */
        copy_v3_v3(vec, ob->obmat[3]);
  
 +      float curcol[4];
        if ((dflag & DRAW_CONSTCOLOR) == 0) {
                /* for AA effects */
 -              curcol[0] = ob_wire_col[0];
 -              curcol[1] = ob_wire_col[1];
 -              curcol[2] = ob_wire_col[2];
 -              curcol[3] = 154;
 -              glColor4ubv(curcol);
 +              rgb_uchar_to_float(curcol, ob_wire_col);
 +              curcol[3] = 0.6f;
 +              /* TODO: pay attention to GL_BLEND */
        }
  
 -      glLineWidth(1);
 +      glLineWidth(1.0f);
 +      setlinestyle(3);
  
        if (lampsize > 0.0f) {
 +              const float outlineWidth = 1.5f * U.pixelsize;
 +              const float lampdot_size = lampsize_px * U.pixelsize + outlineWidth;
  
 +              /* Inner Circle */
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                      const float *color = curcol;
                        if (ob->id.us > 1) {
 -                              if (is_obact || (ob->flag & SELECT)) {
 -                                      glColor4ub(0x88, 0xFF, 0xFF, 155);
 +                              if (is_obact || ((base->flag & BASE_SELECTED) != 0)) {
 +                                      static const float active_color[4] = {0.533f, 1.0f, 1.0f, 1.0f};
 +                                      color = active_color;
                                }
                                else {
 -                                      glColor4ub(0x77, 0xCC, 0xCC, 155);
 +                                      static const float inactive_color[4] = {0.467f, 0.8f, 0.8f, 1.0f};
 +                                      color = inactive_color;
                                }
                        }
 +
 +                      GPU_enable_program_point_size();
 +                      glEnable(GL_BLEND);
 +                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +
 +                      immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
 +                      immUniform1f("size", lampdot_size);
 +                      immUniform1f("outlineWidth", outlineWidth);
 +                      immUniformColor3fvAlpha(color, 0.3f);
 +                      immUniform4fv("outlineColor", color);
 +
 +                      immBegin(GWN_PRIM_POINTS, 1);
 +                      immVertex3fv(pos, vec);
 +                      immEnd();
 +
 +                      immUnbindProgram();
 +
 +                      glDisable(GL_BLEND);
 +                      GPU_disable_program_point_size();
                }
 -              
 -              /* Inner Circle */
 -              glEnable(GL_BLEND);
 -              drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
 -              glDisable(GL_BLEND);
 -              drawcircball(GL_POLYGON, vec, lampsize, imat);
 -              
 +              else {
 +                      /* CONSTCOLOR in effect */
 +                      /* TODO: separate picking from drawing */
 +                      immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
 +                      /* color doesn't matter, so don't set */
 +                      glPointSize(lampdot_size);
 +
 +                      immBegin(GWN_PRIM_POINTS, 1);
 +                      immVertex3fv(pos, vec);
 +                      immEnd();
 +
 +                      immUnbindProgram();
 +              }
 +
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              /* TODO(merwin): short term, use DEPTH_ONLY for picking
 +               *               long term, separate picking from drawing
 +               */
 +
                /* restore */
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                      if (ob->id.us > 1)
 -                              glColor4ubv(curcol);
 +                      immUniformColor4fv(curcol);
                }
  
                /* Outer circle */
                circrad = 3.0f * lampsize;
 -              setlinestyle(3);
  
 -              drawcircball(GL_LINE_LOOP, vec, circrad, imat);
 +              imm_drawcircball(vec, circrad, imat, pos);
  
                /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
                if (la->type != LA_HEMI) {
                        if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) {
 -                              drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat);
 +                              imm_drawcircball(vec, circrad + 3.0f * pixsize, imat, pos);
                        }
                }
        }
        else {
 -              setlinestyle(3);
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                      immUniformColor4fv(curcol);
 +              }
                circrad = 0.0f;
        }
 -      
 +
        /* draw the pretty sun rays */
        if (la->type == LA_SUN) {
                float v1[3], v2[3], mat[3][3];
                short axis;
 -              
 +
                /* setup a 45 degree rotation matrix */
                axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2);
  
                /* vectors */
                mul_v3_v3fl(v1, imat[0], circrad * 1.2f);
                mul_v3_v3fl(v2, imat[0], circrad * 2.5f);
 -              
 +
                /* center */
 -              glTranslate3fv(vec);
 -              
 +              gpuPushMatrix();
 +              gpuTranslate3fv(vec);
 +
                setlinestyle(3);
 -              
 -              glBegin(GL_LINES);
 +
 +              immBegin(GWN_PRIM_LINES, 16);
                for (axis = 0; axis < 8; axis++) {
 -                      glVertex3fv(v1);
 -                      glVertex3fv(v2);
 +                      immVertex3fv(pos, v1);
 +                      immVertex3fv(pos, v2);
                        mul_m3_v3(mat, v1);
                        mul_m3_v3(mat, v2);
                }
 -              glEnd();
 -              
 -              glTranslatef(-vec[0], -vec[1], -vec[2]);
 +              immEnd();
  
 +              gpuPopMatrix();
        }
 -      
 +
        if (la->type == LA_LOCAL) {
                if (la->mode & LA_SPHERE) {
 -                      drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
 +                      imm_drawcircball(vec, la->dist, imat, pos);
                }
        }
 -      
 -      glPopMatrix();  /* back in object space */
 +
 +      gpuPopMatrix();  /* back in object space */
        zero_v3(vec);
 -      
 +
        if (is_view) {
                /* skip drawing extra info */
        }
                            {z_abs, -z_abs, x},
                            {-z_abs, z_abs, x},
                        };
 -                      const unsigned char indices[] = {
 -                          0, 1, 3,
 -                          0, 3, 2,
 -                          0, 2, 4,
 -                          0, 1, 4,
 -                      };
 -
 -                      /* Draw call:
 -                       * activate and specify pointer to vertex array */
 -                      glEnableClientState(GL_VERTEX_ARRAY);
 -                      glVertexPointer(3, GL_FLOAT, 0, vertices);
 -                      /* draw the pyramid */
 -                      glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices);
  
 -                      /* deactivate vertex arrays after drawing */
 -                      glDisableClientState(GL_VERTEX_ARRAY);
 +                      immBegin(GWN_PRIM_LINES, 16);
 +                      for (int i = 1; i <= 4; ++i) {
 +                              immVertex3fv(pos, vertices[0]); /* apex to corner */
 +                              immVertex3fv(pos, vertices[i]);
 +                              int next_i = (i == 4) ? 1 : (i + 1);
 +                              immVertex3fv(pos, vertices[i]); /* corner to next corner */
 +                              immVertex3fv(pos, vertices[next_i]);
 +                      }
 +                      immEnd();
  
 -                      glTranslatef(0.0f, 0.0f, x);
 +                      gpuTranslate3f(0.0f, 0.0f, x);
  
                        /* draw the square representing spotbl */
                        if (la->type == LA_SPOT) {
                                 * previously it adjusted to always to show it but that seems
                                 * confusing because it doesn't show the actual blend size */
                                if (blend != 0.0f && blend != z_abs) {
 -                                      fdrawbox(blend, -blend, -blend, blend);
 +                                      imm_draw_line_box_3d(pos, blend, -blend, -blend, blend);
                                }
                        }
                }
                else {
 -
                        /* draw the angled sides of the cone */
 -                      glBegin(GL_LINE_STRIP);
 -                      glVertex3fv(vvec);
 -                      glVertex3fv(vec);
 -                      glVertex3fv(lvec);
 -                      glEnd();
 +                      immBegin(GWN_PRIM_LINE_STRIP, 3);
 +                      immVertex3fv(pos, vvec);
 +                      immVertex3fv(pos, vec);
 +                      immVertex3fv(pos, lvec);
 +                      immEnd();
  
                        /* draw the circle at the end of the cone */
 -                      glTranslatef(0.0f, 0.0f, x);
 -                      circ(0.0f, 0.0f, z_abs);
 +                      gpuTranslate3f(0.0f, 0.0f, x);
 +                      imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, z_abs, 32);
  
                        /* draw the circle representing spotbl */
                        if (la->type == LA_SPOT) {
                                 * previously it adjusted to always to show it but that seems
                                 * confusing because it doesn't show the actual blend size */
                                if (blend != 0.0f && blend != z_abs) {
 -                                      circ(0.0f, 0.0f, blend);
 +                                      imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, blend, 32);
                                }
                        }
                }
  
                if (drawcone)
 -                      draw_transp_spot_volume(la, x, z);
 +                      draw_transp_spot_volume(la, x, z, pos);
  
                /* draw clip start, useful for wide cones where its not obvious where the start is */
 -              glTranslatef(0.0, 0.0, -x);  /* reverse translation above */
 -              glBegin(GL_LINES);
 +              gpuTranslate3f(0.0f, 0.0f, -x);  /* reverse translation above */
 +              immBegin(GWN_PRIM_LINES, 2);
                if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
                        float lvec_clip[3];
                        float vvec_clip[3];
                        interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
                        interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
  
 -                      glVertex3fv(lvec_clip);
 -                      glVertex3fv(vvec_clip);
 +                      immVertex3fv(pos, lvec_clip);
 +                      immVertex3fv(pos, vvec_clip);
                }
                /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
                else {
 -                      glVertex3f(0.0, 0.0, -circrad);
 -                      glVertex3f(0.0, 0.0, -la->dist);
 +                      immVertex3f(pos, 0.0f, 0.0f, -circrad);
 +                      immVertex3f(pos, 0.0f, 0.0f, -la->dist);
                }
 -              glEnd();
 +              immEnd();
        }
        else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
 -              
                /* draw the line from the circle along the dist */
 -              glBegin(GL_LINES);
 +              immBegin(GWN_PRIM_LINES, 2);
                vec[2] = -circrad;
 -              glVertex3fv(vec);
 +              immVertex3fv(pos, vec);
                vec[2] = -la->dist;
 -              glVertex3fv(vec);
 -              glEnd();
 -              
 +              immVertex3fv(pos, vec);
 +              immEnd();
 +
                if (la->type == LA_HEMI) {
                        /* draw the hemisphere curves */
                        short axis, steps, dir;
                        float outdist, zdist, mul;
                        zero_v3(vec);
 -                      outdist = 0.14; mul = 1.4; dir = 1;
 -                      
 +                      outdist = 0.14f; mul = 1.4f; dir = 1;
 +
                        setlinestyle(4);
                        /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
                        for (axis = 0; axis < 4; axis++) {
 -                              float v[3] = {0.0, 0.0, 0.0};
 -                              zdist = 0.02;
 -                              
 -                              glBegin(GL_LINE_STRIP);
 -                              
 +                              float v[3] = {0.0f, 0.0f, 0.0f};
 +                              zdist = 0.02f;
 +
 +                              immBegin(GWN_PRIM_LINE_STRIP, 6);
 +
                                for (steps = 0; steps < 6; steps++) {
                                        if (axis == 0 || axis == 1) {       /* x axis up, x axis down */
                                                /* make the arcs start at the edge of the energy circle */
                                        }
  
                                        v[2] = v[2] - steps * zdist;
 -                                      
 -                                      glVertex3fv(v);
 -                                      
 +
 +                                      immVertex3fv(pos, v);
 +
                                        zdist = zdist * mul;
                                }
 -                              
 -                              glEnd();
 +
 +                              immEnd();
                                /* flip the direction */
                                dir = -dir;
                        }
  
  #ifdef WITH_GAMEENGINE
                if (drawshadowbox) {
 -                      draw_transp_sun_volume(la);
 +                      draw_transp_sun_volume(la, pos);
                }
  #endif
 -
        }
        else if (la->type == LA_AREA) {
                setlinestyle(3);
                if (la->area_shape == LA_AREA_SQUARE)
 -                      fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
 +                      imm_draw_line_box_3d(pos, -la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f);
                else if (la->area_shape == LA_AREA_RECT)
 -                      fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
 +                      imm_draw_line_box_3d(pos, -la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
  
 -              glBegin(GL_LINES);
 -              glVertex3f(0.0, 0.0, -circrad);
 -              glVertex3f(0.0, 0.0, -la->dist);
 -              glEnd();
 +              immBegin(GWN_PRIM_LINES, 2);
 +              immVertex3f(pos, 0.0f, 0.0f, -circrad);
 +              immVertex3f(pos, 0.0f, 0.0f, -la->dist);
 +              immEnd();
        }
 -      
 +
        /* and back to viewspace */
 -      glPushMatrix();
 -      glLoadMatrixf(rv3d->viewmat);
 +      gpuPushMatrix();
 +      gpuLoadMatrix(rv3d->viewmat);
        copy_v3_v3(vec, ob->obmat[3]);
  
        setlinestyle(0);
 -      
 +
        if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) {
 -              drawshadbuflimits(la, ob->obmat);
 +              drawshadbuflimits(la, ob->obmat, pos);
        }
 -      
 +
        if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              UI_GetThemeColor4ubv(TH_LAMP, col);
 -              glColor4ubv(col);
 +              immUniformThemeColor(TH_LAMP);
        }
  
        glEnable(GL_BLEND);
 -      
 +
        if (vec[2] > 0) vec[2] -= circrad;
        else vec[2] += circrad;
 -      
 -      glBegin(GL_LINES);
 -      glVertex3fv(vec);
 +
 +      immBegin(GWN_PRIM_LINES, 2);
 +      immVertex3fv(pos, vec);
        vec[2] = 0;
 -      glVertex3fv(vec);
 -      glEnd();
 -      
 -      glPointSize(2.0);
 -      glBegin(GL_POINTS);
 -      glVertex3fv(vec);
 -      glEnd();
 -      
 +      immVertex3fv(pos, vec);
 +      immEnd();
 +
 +      glPointSize(2.0f);
 +      immBegin(GWN_PRIM_POINTS, 1);
 +      immVertex3fv(pos, vec);
 +      immEnd();
 +
        glDisable(GL_BLEND);
 -      
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              /* restore for drawing extra stuff */
 -              glColor3ubv(ob_wire_col);
 -      }
 -      /* and finally back to org object space! */
 -      glPopMatrix();
 +
 +      immUnbindProgram();
 +      gpuPopMatrix();
  }
  
 -static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3])
 +static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3], unsigned pos)
  {
 -      glBegin(GL_LINES);
 -      glVertex3f(0.0, 0.0, -sta);
 -      glVertex3f(0.0, 0.0, -end);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 2);
 +      immVertex3f(pos, 0.0f, 0.0f, -sta);
 +      immVertex3f(pos, 0.0f, 0.0f, -end);
 +      immEnd();
  
        if (!(dflag & DRAW_PICKING)) {
 -              glPointSize(3.0);
 -              glBegin(GL_POINTS);
 +              glPointSize(3.0f);
 +              /* would like smooth round points here, but that means binding another shader...
 +               * if it's really desired, pull these points into their own function to be called after */
 +              immBegin(GWN_PRIM_POINTS, 2);
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                      glColor3ubv(col);
 +                      immUniformColor3ubv(col);
                }
 -              glVertex3f(0.0, 0.0, -sta);
 -              glVertex3f(0.0, 0.0, -end);
 -              glEnd();
 +              immVertex3f(pos, 0.0f, 0.0f, -sta);
 +              immVertex3f(pos, 0.0f, 0.0f, -end);
 +              immEnd();
        }
  }
  
  
  /* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
  /* qdn: now also enabled for Blender to set focus point for defocus composite node */
 -static void draw_focus_cross(float dist, float size)
 +static void draw_focus_cross(float dist, float size, unsigned pos)
  {
 -      glBegin(GL_LINES);
 -      glVertex3f(-size, 0.0f, -dist);
 -      glVertex3f(size, 0.0f, -dist);
 -      glVertex3f(0.0f, -size, -dist);
 -      glVertex3f(0.0f, size, -dist);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 4);
 +      immVertex3f(pos, -size, 0.0f, -dist);
 +      immVertex3f(pos, size, 0.0f, -dist);
 +      immVertex3f(pos, 0.0f, -size, -dist);
 +      immVertex3f(pos, 0.0f, size, -dist);
 +      immEnd();
  }
  
  #ifdef VIEW3D_CAMERA_BORDER_HACK
@@@ -1671,8 -1590,28 +1671,8 @@@ bool view3d_camera_border_hack_test = f
  
  /* ****************** draw clip data *************** */
  
 -static void draw_bundle_sphere(void)
 -{
 -      static GLuint displist = 0;
 -
 -      if (displist == 0) {
 -              GLUquadricObj *qobj;
 -
 -              displist = glGenLists(1);
 -              glNewList(displist, GL_COMPILE);
 -              qobj = gluNewQuadric();
 -              gluQuadricDrawStyle(qobj, GLU_FILL);
 -              gluSphere(qobj, 0.05, 8, 8);
 -              gluDeleteQuadric(qobj);
 -
 -              glEndList();
 -      }
 -
 -      glCallList(displist);
 -}
 -
  static void draw_viewport_object_reconstruction(
 -        Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d,
 +        Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d,
          MovieClip *clip, MovieTrackingObject *tracking_object,
          const short dflag, const unsigned char ob_wire_col[4],
          int *global_track_index, bool draw_selected)
        if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0)
                mul_v3_fl(camera_size, tracking_object->scale);
  
 -      glPushMatrix();
 +      gpuPushMatrix();
  
        if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
                /* current ogl matrix is translated in camera space, bundles should
                 * from current ogl matrix */
                invert_m4_m4(imat, base->object->obmat);
  
 -              glMultMatrixf(imat);
 -              glMultMatrixf(mat);
 +              gpuMultMatrix(imat);
 +              gpuMultMatrix(mat);
        }
        else {
                float obmat[4][4];
                BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat);
  
                invert_m4_m4(imat, obmat);
 -              glMultMatrixf(imat);
 +              gpuMultMatrix(imat);
        }
  
        for (track = tracksbase->first; track; track = track->next) {
                        continue;
  
                if (dflag & DRAW_PICKING)
 -                      GPU_select_load_id(base->selcol + (tracknr << 16));
 +                      GPU_select_load_id(base->object->select_color + (tracknr << 16));
  
 -              glPushMatrix();
 -              glTranslate3fv(track->bundle_pos);
 -              glScalef(v3d->bundle_size / 0.05f / camera_size[0],
 -                       v3d->bundle_size / 0.05f / camera_size[1],
 -                       v3d->bundle_size / 0.05f / camera_size[2]);
 +              gpuPushMatrix();
 +              gpuTranslate3fv(track->bundle_pos);
 +              gpuScale3f(v3d->bundle_size / 0.05f / camera_size[0],
 +                         v3d->bundle_size / 0.05f / camera_size[1],
 +                         v3d->bundle_size / 0.05f / camera_size[2]);
  
                const int v3d_drawtype = view3d_effective_drawtype(v3d);
                if (v3d_drawtype == OB_WIRE) {
 +                      unsigned char color[4];
 +                      const unsigned char *color_ptr = NULL;
                        if ((dflag & DRAW_CONSTCOLOR) == 0) {
                                if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
 -                                      glColor3ubv(ob_wire_col);
 +                                      color_ptr = ob_wire_col;
                                }
                                else {
 -                                      glColor3fv(track->color);
 +                                      rgba_float_to_uchar(color, track->color);
 +                                      color_ptr = color;
                                }
                        }
  
 -                      drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
 +                      drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
                }
                else if (v3d_drawtype > OB_WIRE) {
                        if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
 +                              Gwn_Batch *batch;
 +
 +                              gpuScaleUniform(0.05f);
 +
                                /* selection outline */
                                if (selected) {
 +                                      batch = Batch_get_sphere_wire(1);
 +
                                        if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                                              glColor3ubv(ob_wire_col);
 +                                              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +                                              GWN_batch_uniform_4f(batch, "color",
 +                                                              ob_wire_col[0] / 255.f,
 +                                                              ob_wire_col[1] / 255.f,
 +                                                              ob_wire_col[2] / 255.f, 1.0f);
 +                                      }
 +                                      else {
 +                                              Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
                                        }
 -
                                        glLineWidth(2.0f);
 -                                      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -
 -                                      draw_bundle_sphere();
  
 -                                      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +                                      GWN_batch_draw(batch);
                                }
  
 +                              batch = Batch_get_sphere(0);
 +
                                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                                      if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
 -                                      else UI_ThemeColor(TH_BUNDLE_SOLID);
 +                                      const float light[3] = {0.0f, 0.0f, 1.0f};
 +                                      float col[3];
 +                                      Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
 +                                      GWN_batch_uniform_3fv(batch, "light", light);
 +
 +                                      if (track->flag & TRACK_CUSTOMCOLOR) copy_v3_v3(col, track->color);
 +                                      else UI_GetThemeColor3fv(TH_BUNDLE_SOLID, col);
 +                                      GWN_batch_uniform_4f(batch, "color", col[0], col[1], col[2], 1.0f);
 +                              }
 +                              else {
 +                                      Batch_set_builtin_program(batch, GPU_SHADER_3D_DEPTH_ONLY);
                                }
  
 -                              draw_bundle_sphere();
 +                              GWN_batch_draw(batch);
                        }
                        else {
 +                              unsigned char color[4];
 +                              const unsigned char *color_ptr = NULL;
                                if ((dflag & DRAW_CONSTCOLOR) == 0) {
                                        if (selected) {
 -                                              glColor3ubv(ob_wire_col);
 +                                              color_ptr = ob_wire_col;
                                        }
                                        else {
 -                                              if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color);
 -                                              else UI_ThemeColor(TH_WIRE);
 +                                              if (track->flag & TRACK_CUSTOMCOLOR) rgba_float_to_uchar(color, track->color);
 +                                              else UI_GetThemeColor4ubv(TH_WIRE, color);
 +
 +                                              color_ptr = color;
                                        }
                                }
  
 -                              drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
 +                              drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype, color_ptr);
                        }
                }
  
 -              glPopMatrix();
 +              gpuPopMatrix();
  
                if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) {
                        float pos[3];
                        MovieTrackingReconstruction *reconstruction;
                        reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
  
 -                      if (reconstruction->camnr) {
 +                      if (reconstruction->camnr >= 2) {
                                MovieReconstructedCamera *camera = reconstruction->cameras;
 +                              unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +                              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +                              immUniformThemeColor(TH_CAMERA_PATH);
  
 -                              UI_ThemeColor(TH_CAMERA_PATH);
                                glLineWidth(2.0f);
  
 -                              glBegin(GL_LINE_STRIP);
 +                              immBegin(GWN_PRIM_LINE_STRIP, reconstruction->camnr);
                                for (int a = 0; a < reconstruction->camnr; a++, camera++) {
 -                                      glVertex3fv(camera->mat[3]);
 +                                      immVertex3fv(pos, camera->mat[3]);
                                }
 -                              glEnd();
 +                              immEnd();
 +
 +                              immUnbindProgram();
                        }
                }
        }
  
 -      glPopMatrix();
 +      gpuPopMatrix();
  
        *global_track_index = tracknr;
  }
  
  static void draw_viewport_reconstruction(
 -        Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
 +        Scene *scene, BaseLegacy *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
          const short dflag, const unsigned char ob_wire_col[4],
          const bool draw_selected)
  {
        /* restore */
        GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
  
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              glColor3ubv(ob_wire_col);
 -      }
 -
        if (dflag & DRAW_PICKING)
 -              GPU_select_load_id(base->selcol);
 +              GPU_select_load_id(base->object->select_color);
  }
  
 -static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
 +/* camera frame */
 +static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos)
  {
 -      glBegin(mode);
 -      glVertex3fv(near_plane[0]);
 -      glVertex3fv(far_plane[0]);
 -      glVertex3fv(far_plane[1]);
 -      glVertex3fv(near_plane[1]);
 -      glEnd();
 -
 -      glBegin(mode);
 -      glVertex3fv(near_plane[1]);
 -      glVertex3fv(far_plane[1]);
 -      glVertex3fv(far_plane[2]);
 -      glVertex3fv(near_plane[2]);
 -      glEnd();
 -
 -      glBegin(mode);
 -      glVertex3fv(near_plane[2]);
 -      glVertex3fv(far_plane[2]);
 -      glVertex3fv(far_plane[3]);
 -      glVertex3fv(near_plane[3]);
 -      glEnd();
 -
 -      glBegin(mode);
 -      glVertex3fv(far_plane[3]);
 -      glVertex3fv(near_plane[3]);
 -      glVertex3fv(near_plane[0]);
 -      glVertex3fv(far_plane[0]);
 -      glEnd();
 +      immBegin(filled ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_LOOP, 4);
 +      immVertex3fv(pos, vec[0]);
 +      immVertex3fv(pos, vec[1]);
 +      immVertex3fv(pos, vec[2]);
 +      immVertex3fv(pos, vec[3]);
 +      immEnd();
  }
  
 -/* camera frame */
 -static void drawcamera_frame(float vec[4][3], const GLenum mode)
 +/* center point to camera frame */
 +static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos)
  {
 -      glBegin(mode);
 -      glVertex3fv(vec[0]);
 -      glVertex3fv(vec[1]);
 -      glVertex3fv(vec[2]);
 -      glVertex3fv(vec[3]);
 -      glEnd();
 +      immBegin(GWN_PRIM_LINES, 8);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[0]);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[1]);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[2]);
 +      immVertex3fv(pos, origin);
 +      immVertex3fv(pos, vec[3]);
 +      immEnd();
  }
  
 -/* center point to camera frame */
 -static void drawcamera_framelines(float vec[4][3], float origin[3])
 +static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos)
  {
 -      glBegin(GL_LINE_STRIP);
 -      glVertex3fv(vec[1]);
 -      glVertex3fv(origin);
 -      glVertex3fv(vec[0]);
 -      glVertex3fv(vec[3]);
 -      glVertex3fv(origin);
 -      glVertex3fv(vec[2]);
 -      glEnd();
 +      drawcamera_frame(near_plane, filled, pos);
 +      drawcamera_frame(far_plane, filled, pos);
 +
 +      if (filled) {
 +              immBegin(GWN_PRIM_TRI_STRIP, 10);
 +
 +              immVertex3fv(pos, near_plane[0]);
 +              immVertex3fv(pos, far_plane[0]);
 +              immVertex3fv(pos, near_plane[1]);
 +              immVertex3fv(pos, far_plane[1]);
 +              immVertex3fv(pos, near_plane[2]);
 +              immVertex3fv(pos, far_plane[2]);
 +              immVertex3fv(pos, near_plane[3]);
 +              immVertex3fv(pos, far_plane[3]);
 +              immVertex3fv(pos, near_plane[0]);
 +              immVertex3fv(pos, far_plane[0]);
 +
 +              immEnd();
 +      }
 +      else {
 +              immBegin(GWN_PRIM_LINES, 8);
 +              for (int i = 0; i < 4; ++i) {
 +                      immVertex3fv(pos, near_plane[i]);
 +                      immVertex3fv(pos, far_plane[i]);
 +              }
 +              immEnd();
 +      }
  }
  
  static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob)
  
  static void drawcamera_stereo3d(
          Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
 -        float vec[4][3], float drawsize, const float scale[3])
 +        float vec[4][3], float drawsize, const float scale[3], unsigned pos)
  {
        float obmat[4][4];
        float vec_lr[2][4][3];
  
        zero_v3(tvec);
  
 -      glPushMatrix();
 +      /* caller bound GPU_SHADER_3D_UNIFORM_COLOR, passed in pos attribute ID */
  
        for (int i = 0; i < 2; i++) {
                ob = BKE_camera_multiview_render(scene, ob, names[i]);
                cam_lr[i] = ob->data;
  
 -              glLoadMatrixf(rv3d->viewmat);
 +              gpuLoadMatrix(rv3d->viewmat);
                BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
 -              glMultMatrixf(obmat);
 +              gpuMultMatrix(obmat);
  
                copy_m3_m3(vec_lr[i], vec);
                copy_v3_v3(vec_lr[i][3], vec[3]);
  
                if (is_stereo3d_cameras) {
                        /* camera frame */
 -                      drawcamera_frame(vec_lr[i], GL_LINE_LOOP);
 +                      drawcamera_frame(vec_lr[i], false, pos);
  
                        /* center point to camera frame */
 -                      drawcamera_framelines(vec_lr[i], tvec);
 +                      drawcamera_framelines(vec_lr[i], tvec, pos);
                }
  
                /* connecting line */
                }
        }
  
 -
        /* the remaining drawing takes place in the view space */
 -      glLoadMatrixf(rv3d->viewmat);
 +      gpuLoadMatrix(rv3d->viewmat);
  
        if (is_stereo3d_cameras) {
                /* draw connecting lines */
 -              GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
 -              GPU_basic_shader_line_stipple(2, 0xAAAA);
 +              glLineStipple(2, 0xAAAA);
 +              glEnable(GL_LINE_STIPPLE);
  
 -              glBegin(GL_LINES);
 -              glVertex3fv(origin[0]);
 -              glVertex3fv(origin[1]);
 -              glEnd();
 +              immBegin(GWN_PRIM_LINES, 2);
 +              immVertex3fv(pos, origin[0]);
 +              immVertex3fv(pos, origin[1]);
 +              immEnd();
  
 -              GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
 +              glDisable(GL_LINE_STIPPLE);
        }
  
        /* draw convergence plane */
                        add_v3_v3(local_plane[i], axis_center);
                }
  
 -              glColor3f(0.0f, 0.0f, 0.0f);
 +              immUniformColor3f(0.0f, 0.0f, 0.0f);
  
                /* camera frame */
 -              drawcamera_frame(local_plane, GL_LINE_LOOP);
 +              drawcamera_frame(local_plane, false, pos);
  
                if (v3d->stereo3d_convergence_alpha > 0.0f) {
                        glEnable(GL_BLEND);
 -                      glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
 -                      glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
 +                      immUniformColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha);
  
 -                      drawcamera_frame(local_plane, GL_QUADS);
 +                      drawcamera_frame(local_plane, true, pos);
  
                        glDisable(GL_BLEND);
 -                      glDepthMask(1);  /* restore write in zbuffer */
 +                      glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                }
        }
  
                        }
  
                        /* camera frame */
 -                      glColor3f(0.0f, 0.0f, 0.0f);
 +                      immUniformColor3f(0.0f, 0.0f, 0.0f);
  
 -                      drawcamera_frame(near_plane, GL_LINE_LOOP);
 -                      drawcamera_frame(far_plane, GL_LINE_LOOP);
 -                      drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP);
 +                      drawcamera_volume(near_plane, far_plane, false, pos);
  
                        if (v3d->stereo3d_volume_alpha > 0.0f) {
                                glEnable(GL_BLEND);
 -                              glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                              glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
                                if (i == 0)
 -                                      glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
 +                                      immUniformColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha);
                                else
 -                                      glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
 +                                      immUniformColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha);
  
 -                              drawcamera_frame(near_plane, GL_QUADS);
 -                              drawcamera_frame(far_plane, GL_QUADS);
 -                              drawcamera_volume(near_plane, far_plane, GL_QUADS);
 +                              drawcamera_volume(near_plane, far_plane, true, pos);
  
                                glDisable(GL_BLEND);
 -                              glDepthMask(1);  /* restore write in zbuffer */
 +                              glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                        }
                }
        }
 -
 -      glPopMatrix();
  }
  
  /* flag similar to draw_object() */
 -static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 -                       const short dflag, const unsigned char ob_wire_col[4])
 +void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 +                const short dflag, const unsigned char ob_wire_col[4])
  {
        /* a standing up pyramid with (0,0,0) as top */
        Camera *cam;
        BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
                                 asp, shift, &drawsize, vec);
  
 -      glDisable(GL_CULL_FACE);
 -      glLineWidth(1);
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      if (ob_wire_col) {
 +              immUniformColor3ubv(ob_wire_col);
 +      }
 +      glLineWidth(1.0f);
  
        /* camera frame */
        if (!is_stereo3d_cameras) {
                        float obmat[4][4];
                        bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
  
 -                      glPushMatrix();
 -                      glLoadMatrixf(rv3d->viewmat);
 +                      gpuPushMatrix();
 +                      gpuLoadMatrix(rv3d->viewmat);
                        BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
 -                      glMultMatrixf(obmat);
 +                      gpuMultMatrix(obmat);
  
 -                      drawcamera_frame(vec, GL_LINE_LOOP);
 -                      glPopMatrix();
 +                      drawcamera_frame(vec, false, pos);
 +                      gpuPopMatrix();
                }
                else {
 -                      drawcamera_frame(vec, GL_LINE_LOOP);
 +                      drawcamera_frame(vec, false, pos);
                }
        }
  
 -      if (is_view)
 +      if (is_view) {
 +              immUnbindProgram();
                return;
 +      }
  
        zero_v3(tvec);
  
        /* center point to camera frame */
        if (!is_stereo3d_cameras)
 -              drawcamera_framelines(vec, tvec);
 +              drawcamera_framelines(vec, tvec, pos);
  
        /* arrow on top */
        tvec[2] = vec[1][2]; /* copy the depth */
         * for active cameras. We actually draw both outline+filled
         * for active cameras so the wire can be seen side-on */
        for (int i = 0; i < 2; i++) {
 -              if (i == 0) glBegin(GL_LINE_LOOP);
 -              else if (i == 1 && is_active) glBegin(GL_TRIANGLES);
 +              if (i == 0) immBegin(GWN_PRIM_LINE_LOOP, 3);
 +              else if (i == 1 && is_active) {
 +                      glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */
 +                      immBegin(GWN_PRIM_TRIS, 3);
 +              }
                else break;
  
                tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
                tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
 -              glVertex3fv(tvec); /* left */
 +              immVertex3fv(pos, tvec); /* left */
                
                tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]);
 -              glVertex3fv(tvec); /* right */
 +              immVertex3fv(pos, tvec); /* right */
                
                tvec[0] = shift[0];
                tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
 -              glVertex3fv(tvec); /* top */
 +              immVertex3fv(pos, tvec); /* top */
  
 -              glEnd();
 +              immEnd();
        }
  
        if ((dflag & DRAW_SCENESET) == 0) {
                        copy_m4_m4(nobmat, ob->obmat);
                        normalize_m4(nobmat);
  
 -                      glPushMatrix();
 -                      glLoadMatrixf(rv3d->viewmat);
 -                      glMultMatrixf(nobmat);
 +                      gpuLoadMatrix(rv3d->viewmat);
 +                      gpuMultMatrix(nobmat);
  
                        if (cam->flag & CAM_SHOWLIMITS) {
                                const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120};
  
 -                              draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col));
 +                              draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col), pos);
                                /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
 -                              draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
 +                              draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize, pos);
                        }
  
                        if (cam->flag & CAM_SHOWMIST) {
  
                                if (world) {
                                        draw_limit_line(world->miststa, world->miststa + world->mistdist,
 -                                                      dflag, (is_active ? col_hi : col));
 +                                                      dflag, (is_active ? col_hi : col), pos);
                                }
                        }
 -                      glPopMatrix();
                }
        }
  
        /* stereo cameras drawing */
        if (is_stereo3d) {
 -              drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale);
 +              drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale, pos);
        }
 +
 +      immUnbindProgram();
  }
  
  /* flag similar to draw_object() */
 -static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d),
 -                        Object *UNUSED(ob), int UNUSED(flag))
 +void drawspeaker(const unsigned char ob_wire_col[3])
  {
 -      float vec[3];
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
 -      glEnable(GL_BLEND);
 -      glLineWidth(1);
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +      if (ob_wire_col) {
 +              immUniformColor3ubv(ob_wire_col);
 +      }
 +
 +      glLineWidth(1.0f);
 +
 +      const int segments = 16;
  
        for (int j = 0; j < 3; j++) {
 -              vec[2] = 0.25f * j - 0.125f;
 +              float z = 0.25f * j - 0.125f;
  
 -              glBegin(GL_LINE_LOOP);
 -              for (int i = 0; i < 16; i++) {
 -                      vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 -                      vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 -                      glVertex3fv(vec);
 +              immBegin(GWN_PRIM_LINE_LOOP, segments);
 +              for (int i = 0; i < segments; i++) {
 +                      float x = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 +                      float y = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
 +                      immVertex3f(pos, x, y, z);
                }
 -              glEnd();
 +              immEnd();
        }
  
        for (int j = 0; j < 4; j++) {
 -              vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
 -              vec[1] = ((j % 2) * (j - 2)) * 0.5f;
 -              glBegin(GL_LINE_STRIP);
 +              float x = (((j + 1) % 2) * (j - 1)) * 0.5f;
 +              float y = ((j % 2) * (j - 2)) * 0.5f;
 +              immBegin(GWN_PRIM_LINE_STRIP, 3);
                for (int i = 0; i < 3; i++) {
                        if (i == 1) {
 -                              vec[0] *= 0.5f;
 -                              vec[1] *= 0.5f;
 +                              x *= 0.5f;
 +                              y *= 0.5f;
                        }
  
 -                      vec[2] = 0.25f * i - 0.125f;
 -                      glVertex3fv(vec);
 +                      float z = 0.25f * i - 0.125f;
 +                      immVertex3f(pos, x, y, z);
                }
 -              glEnd();
 +              immEnd();
        }
  
 -      glDisable(GL_BLEND);
 +      immUnbindProgram();
  }
  
 -static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel)
 +static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel,
 +                               unsigned int pos, unsigned int color)
  {
        BPoint *bp = lt->def;
        const float *co = dl ? dl->verts : NULL;
 +      float active_color[4], draw_color[4];
  
 -      const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
 -      UI_ThemeColor(color);
 +      UI_GetThemeColor4fv(sel ? TH_VERTEX_SELECT : TH_VERTEX, draw_color);
 +      UI_GetThemeColor4fv(TH_ACTIVE_VERT, active_color);
  
        glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 -      glBegin(GL_POINTS);
 +      immBeginAtMost(GWN_PRIM_POINTS, lt->pntsw * lt->pntsv * lt->pntsu);
  
        for (int w = 0; w < lt->pntsw; w++) {
                int wxt = (w == 0 || w == lt->pntsw - 1);
                                        if (bp->hide == 0) {
                                                /* check for active BPoint and ensure selected */
                                                if ((bp == actbp) && (bp->f1 & SELECT)) {
 -                                                      UI_ThemeColor(TH_ACTIVE_VERT);
 -                                                      glVertex3fv(dl ? co : bp->vec);
 -                                                      UI_ThemeColor(color);
 +                                                      immAttrib4fv(color, active_color);
 +                                                      immVertex3fv(pos, dl ? co : bp->vec);
                                                }
                                                else if ((bp->f1 & SELECT) == sel) {
 -                                                      glVertex3fv(dl ? co : bp->vec);
 +                                                      immAttrib4fv(color, draw_color);
 +                                                      immVertex3fv(pos, dl ? co : bp->vec);
                                                }
                                        }
                                }
                }
        }
        
 -      glEnd();
 +      immEnd();
  }
  
 -static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
 +static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol,
 +                               unsigned int pos, unsigned int color)
  {
        int index = ((w * lt->pntsv + v) * lt->pntsu) + u;
  
        if (actdef_wcol) {
                float col[3];
                MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1);
 -              
                weight_to_rgb(col, mdw ? mdw->weight : 0.0f);
 -              glColor3fv(col);
 -
 +              immAttrib3fv(color, col);
        }
        
        if (dl) {
 -              glVertex3fv(&dl->verts[index * 3]);
 +              immVertex3fv(pos, &dl->verts[index * 3]);
        }
        else {
 -              glVertex3fv(lt->def[index].vec);
 +              immVertex3fv(pos, lt->def[index].vec);
        }
  }
  
@@@ -2435,7 -2334,7 +2435,7 @@@ static void ensure_curve_cache(Scene *s
  #endif
  
  /* lattice color is hardcoded, now also shows weightgroup values in edit mode */
 -static void drawlattice(View3D *v3d, Object *ob)
 +static void drawlattice(View3D *v3d, Object *ob, const short dflag, const unsigned char ob_wire_col[4])
  {
        Lattice *lt = ob->data;
        DispList *dl;
        if (is_edit) {
                lt = lt->editlatt->latt;
  
 -              UI_ThemeColor(TH_WIRE_EDIT);
 -              
                if (ob->defbase.first && lt->dvert) {
                        actdef_wcol = ob->actdef;
                }
        }
  
 -      glLineWidth(1);
 -      glBegin(GL_LINES);
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int color, pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      if (actdef_wcol) {
 +              color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR);
 +      }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +              if (is_edit) {
 +                      immUniformThemeColor(TH_WIRE_EDIT);
 +              }
 +              else {
 +                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                              immUniformColor3ubv(ob_wire_col);
 +                      }
 +                      else {
 +                              immUniformColor3f(0.0f, 0.0f, 0.0f);
 +                      }
 +              }
 +      }
 +
 +      glLineWidth(1.0f);
 +      immBeginAtMost(GWN_PRIM_LINES, lt->pntsw * lt->pntsv * lt->pntsu * 6);
 +
        for (w = 0; w < lt->pntsw; w++) {
                int wxt = (w == 0 || w == lt->pntsw - 1);
                for (v = 0; v < lt->pntsv; v++) {
                                int uxt = (u == 0 || u == lt->pntsu - 1);
  
                                if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
 -                                      drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol);
 -                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol);
 +                                      drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol, pos, color);
 +                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
                                }
                                if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
 -                                      drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol);
 -                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol);
 +                                      drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol, pos, color);
 +                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
                                }
                                if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
 -                                      drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol);
 -                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol);
 +                                      drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol, pos, color);
 +                                      drawlattice__point(lt, dl, u, v, w, actdef_wcol, pos, color);
                                }
                        }
                }
        }
 -      glEnd();
 +
 +      immEnd();
 +      immUnbindProgram();
  
        if (is_edit) {
                BPoint *actbp = BKE_lattice_active_point_get(lt);
  
                if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
 -              
 -              lattice_draw_verts(lt, dl, actbp, 0);
 -              lattice_draw_verts(lt, dl, actbp, 1);
 -              
 +
 +              Gwn_VertFormat *v_format = immVertexFormat();
 +              unsigned int v_pos = GWN_vertformat_attr_add(v_format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              unsigned int v_color = GWN_vertformat_attr_add(v_format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
 +
 +              immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
 +
 +              lattice_draw_verts(lt, dl, actbp, 0, v_pos, v_color);
 +              lattice_draw_verts(lt, dl, actbp, 1, v_pos, v_color);
 +
 +              immUnbindProgram();
 +
                if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
        }
  }
@@@ -2534,7 -2401,6 +2534,7 @@@ typedef struct drawDMVertSel_userData 
        int active;
        unsigned char *col[3];  /* (base, sel, act) */
        char sel_prev;
 +      unsigned int pos, color;
  } drawDMVertSel_userData;
  
  static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3],
        if (!(mv->flag & ME_HIDE)) {
                const char sel = (index == data->active) ? 2 : (mv->flag & SELECT);
                if (sel != data->sel_prev) {
 -                      glColor3ubv(data->col[sel]);
 +                      immAttrib3ubv(data->color, data->col[sel]);
                        data->sel_prev = sel;
                }
  
 -              glVertex3fv(co);
 +              immVertex3fv(data->pos, co);
        }
  }
  
  static void drawSelectedVertices(DerivedMesh *dm, Mesh *me)
  {
        drawDMVertSel_userData data;
 +      Gwn_VertFormat *format = immVertexFormat();
  
        /* TODO define selected color */
        unsigned char base_col[3] = {0x0, 0x0, 0x0};
        data.col[1] = sel_col;
        data.col[2] = act_col;
  
 -      glBegin(GL_POINTS);
 +      data.color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT);
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      if (dm->getNumVerts(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +
 +      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
        dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  /* ************** DRAW MESH ****************** */
@@@ -2630,34 -2486,25 +2630,34 @@@ static void draw_dm_face_normals__mapFu
                        copy_v3_v3(n, no);
                }
  
 -              glVertex3fv(cent);
 -              glVertex3f(cent[0] + n[0] * data->normalsize,
 -                         cent[1] + n[1] * data->normalsize,
 -                         cent[2] + n[2] * data->normalsize);
 +              immVertex3fv(data->pos, cent);
 +              immVertex3f(data->pos, cent[0] + n[0] * data->normalsize,
 +                                     cent[1] + n[1] * data->normalsize,
 +                                     cent[2] + n[2] * data->normalsize);
        }
  }
  
 -static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
 +static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
  {
 +      Gwn_VertFormat *format = immVertexFormat();
        drawDMNormal_userData data;
  
        data.bm = em->bm;
        data.normalsize = scene->toolsettings->normalsize;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
        calcDrawDMNormalScale(ob, &data);
  
 -      glBegin(GL_LINES);
 +      if (dm->getNumPolys(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformThemeColor(theme_id);
 +
 +      immBeginAtMost(GWN_PRIM_LINES, dm->getNumPolys(dm) * 2);
        dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
        if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
            (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
        {
 -              glVertex3fv(cent);
 +              immVertex3fv(data->pos, cent);
        }
  }
 -static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
 +static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select, const unsigned char fcol[3])
  {
 -      drawBMSelect_userData data = {em->bm, select};
 +      Gwn_VertFormat *format = immVertexFormat();
 +
 +      drawBMSelect_userData data;
 +      data.bm = em->bm;
 +      data.select = select;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
 -      glBegin(GL_POINTS);
 +      if (dm->getNumPolys(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformColor3ubv(fcol);
 +
 +      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumPolys(dm));
        dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
                        copy_v3_v3(n, no);
                }
  
 -              glVertex3fv(co);
 -              glVertex3f(co[0] + n[0] * data->normalsize,
 -                         co[1] + n[1] * data->normalsize,
 -                         co[2] + n[2] * data->normalsize);
 +              immVertex3fv(data->pos, co);
 +              immVertex3f(data->pos, co[0] + n[0] * data->normalsize,
 +                               co[1] + n[1] * data->normalsize,
 +                               co[2] + n[2] * data->normalsize);
        }
  }
  
 -static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
 +static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
  {
        drawDMNormal_userData data;
 +      Gwn_VertFormat *format = immVertexFormat();
  
        data.bm = em->bm;
        data.normalsize = scene->toolsettings->normalsize;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
  
        calcDrawDMNormalScale(ob, &data);
  
 -      glBegin(GL_LINES);
 +      if (dm->getNumVerts(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformThemeColor(theme_id);
 +
 +      immBeginAtMost(GWN_PRIM_LINES, dm->getNumVerts(dm) * 2);
        dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
 -/* Draw verts with color set based on selection */
 -static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
 -                                   const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
 +static void draw_dm_verts_skin_root__mapFunc(void *userData, int index, const float co[3],
 +                                             const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
  {
        drawDMVerts_userData *data = userData;
        BMVert *eve = BM_vert_at_index(data->bm, index);
  
        if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
                /* skin nodes: draw a red circle around the root node(s) */
 -              if (data->cd_vskin_offset != -1) {
 -                      const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
 -                      if (vs->flag & MVERT_SKIN_ROOT) {
 -                              float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
 -                              glEnd();
 -                      
 -                              glColor4ubv(data->th_skin_root);
 -                              drawcircball(GL_LINES, co, radius, data->imat);
 -
 -                              glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
 -                              glBegin(GL_POINTS);
 -                      }
 +              const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
 +              if (vs->flag & MVERT_SKIN_ROOT) {
 +                      float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
 +                      imm_drawcircball(co, radius, data->imat, data->pos);
                }
 +      }
 +}
 +
 +/* Draw verts with color set based on selection */
 +static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
 +                                   const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
 +{
 +      drawDMVerts_userData *data = userData;
 +      BMVert *eve = BM_vert_at_index(data->bm, index);
  
 +      if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) {
                /* draw active in a different color - no need to stop/start point drawing for this :D */
                if (eve == data->eve_act) {
 -                      glColor4ubv(data->th_editmesh_active);
 -                      glVertex3fv(co);
 -
 -                      /* back to regular vertex color */
 -                      glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
 +                      immAttrib4ubv(data->color, data->th_editmesh_active);
 +                      immVertex3fv(data->pos, co);
                }
                else {
 -                      glVertex3fv(co);
 +                      immAttrib4ubv(data->color, data->sel ? data->th_vertex_select : data->th_vertex);
 +                      immVertex3fv(data->pos, co);
                }
        }
  }
  
  static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act,
 -                          RegionView3D *rv3d)
 +                          RegionView3D *rv3d, const unsigned char col[4])
  {
 +      Gwn_VertFormat *format = immVertexFormat();
 +
        drawDMVerts_userData data;
        data.sel = sel;
        data.eve_act = eve_act;
        data.bm = em->bm;
 +      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      data.color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
  
        /* Cache theme values */
        UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active);
        UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
        UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
  
 -      /* For skin root drawing */
 -      data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
 +      /* Set correct alpha */
 +      data.th_editmesh_active[3] = data.th_vertex_select[3] = data.th_vertex[3] = data.th_skin_root[3] = col[3];
 +
        /* view-aligned matrix */
        mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
        invert_m4(data.imat);
  
 +      if (dm->getNumVerts(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +
        glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 -      glBegin(GL_POINTS);
 +
 +      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
        dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
 +
 +      /* For skin root drawing */
 +      data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
 +
 +      if (data.cd_vskin_offset != -1) {
 +              data.pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformColor4ubv(data.th_skin_root);
 +
 +              dm->foreachMappedVert(dm, draw_dm_verts_skin_root__mapFunc, &data, DM_FOREACH_NOP);
 +
 +              immUnbindProgram();
 +      }
  }
  
  /* Draw edges with color set based on selection */
@@@ -3136,32 -2938,24 +3136,32 @@@ static void draw_dm_loop_normals__mapFu
                        }
                        mul_v3_fl(vec, data->normalsize);
                        add_v3_v3(vec, co);
 -                      glVertex3fv(co);
 -                      glVertex3fv(vec);
 +                      immVertex3fv(data->pos, co);
 +                      immVertex3fv(data->pos, vec);
                }
        }
  }
  
 -static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm)
 +static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm, int theme_id)
  {
        drawDMNormal_userData data;
  
        data.bm = em->bm;
        data.normalsize = scene->toolsettings->normalsize;
 +      data.pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      if (dm->getNumLoops(dm) == 0) return;
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      immUniformThemeColor(theme_id);
  
        calcDrawDMNormalScale(ob, &data);
  
 -      glBegin(GL_LINES);
 +      immBeginAtMost(GWN_PRIM_LINES, dm->getNumLoops(dm) * 2);
        dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL);
 -      glEnd();
 +      immEnd();
 +
 +      immUnbindProgram();
  }
  
  /* Draw faces with color set based on selection
@@@ -3278,7 -3072,7 +3278,7 @@@ static void draw_dm_creases(BMEditMesh 
        data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
  
        if (data.cd_layer_offset != -1) {
 -              glLineWidth(3.0);
 +              glLineWidth(3.0f);
                dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
        }
  }
@@@ -3308,10 -3102,8 +3308,10 @@@ static void draw_dm_bweights__mapFunc(v
        if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
                const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
                if (bweight != 0.0f) {
 -                      UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_BEVEL, bweight);
 -                      glVertex3fv(co);
 +                      unsigned char col[3];
 +                      UI_GetThemeColorBlend3ubv(TH_VERTEX, TH_VERTEX_BEVEL, bweight, col);
 +                      immAttrib3ubv(data->col, col);
 +                      immVertex3fv(data->pos, co);
                }
        }
  }
@@@ -3325,21 -3117,11 +3325,21 @@@ static void draw_dm_bweights(BMEditMes
                data.bm = em->bm;
                data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT);
  
 +              /* is that ever true? */
                if (data.cd_layer_offset != -1) {
 -                      glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
 -                      glBegin(GL_POINTS);
 +                      Gwn_VertFormat *format = immVertexFormat();
 +                      data.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                      data.col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT);
 +
 +                      immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
 +
 +                      glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2.0f);
 +
 +                      immBeginAtMost(GWN_PRIM_POINTS, dm->getNumVerts(dm));
                        dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
 -                      glEnd();
 +                      immEnd();
 +
 +                      immUnbindProgram();
                }
        }
        else {
                data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
  
                if (data.cd_layer_offset != -1) {
 -                      glLineWidth(3.0);
 +                      glLineWidth(3.0f);
                        dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
                }
        }
@@@ -3370,7 -3152,7 +3370,7 @@@ static void draw_em_fancy_verts(Scene *
  {
        ToolSettings *ts = scene->toolsettings;
  
 -      if (v3d->zbuf) glDepthMask(0);  /* disable write in zbuffer, zbuf select */
 +      if (v3d->zbuf) glDepthMask(GL_FALSE);  /* disable write in zbuffer, zbuf select */
  
        for (int sel = 0; sel < 2; sel++) {
                unsigned char col[4], fcol[4];
                        }
  
                        if (ts->selectmode & SCE_SELECT_VERTEX) {
 -                              glPointSize(size);
 -                              glColor4ubv(col);
 -                              draw_dm_verts(em, cageDM, sel, eve_act, rv3d);
 +                              draw_dm_verts(em, cageDM, sel, eve_act, rv3d, col);
                        }
                        
                        if (check_ob_drawface_dot(scene, v3d, obedit->dt)) {
                                glPointSize(fsize);
 -                              glColor4ubv(fcol);
 -                              draw_dm_face_centers(em, cageDM, sel);
 +                              draw_dm_face_centers(em, cageDM, sel, fcol);
                        }
                        
                        if (pass == 0) {
                }
        }
  
 -      if (v3d->zbuf) glDepthMask(1);
 +      if (v3d->zbuf) glDepthMask(GL_TRUE);
  }
  
  static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
@@@ -3522,9 -3307,11 +3522,9 @@@ static void draw_em_measure_stats(ARegi
  
        if (me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_EDGEANG)) {
                BoundBox bb;
 -              bglMats mats = {{0}};
                const rcti rect = {0, ar->winx, 0, ar->winy};
  
 -              view3d_get_transformation(ar, ar->regiondata, em->ob, &mats);
 -              ED_view3d_clipping_calc(&bb, clip_planes, &mats, &rect);
 +              ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
        }
  
        if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
@@@ -3888,7 -3675,7 +3888,7 @@@ static DMDrawOption draw_em_fancy__setG
        }
  }
  
 -static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
 +static void draw_em_fancy(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d,
                            Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
  
  {
        const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE);
        bool use_depth_offset = false;
        
 -      glLineWidth(1);
 +      glLineWidth(1.0f);
        
        BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
  
                        draw_mesh_paint_weight_faces(finalDM, true, draw_em_fancy__setFaceOpts, me->edit_btmesh);
  
                        ED_view3d_polygon_offset(rv3d, 1.0);
 -                      glDepthMask(0);
 +                      glDepthMask(GL_FALSE);
                        use_depth_offset = true;
                }
                else {
                        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
                }
                else if (check_object_draw_texture(scene, v3d, dt)) {
 -                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 +                      if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
                                glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
                                finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind,
                                glFrontFace(GL_CCW);
                        }
                        else {
 -                              draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0);
 +                              draw_mesh_textured(scene, sl, v3d, rv3d, ob, finalDM, 0);
                        }
                }
                else {
                UI_ThemeColor(TH_WIRE_EDIT);
  
                ED_view3d_polygon_offset(rv3d, 1.0);
 -              glDepthMask(0);
 +              glDepthMask(GL_FALSE);
                use_depth_offset = true;
        }
        else {
  #endif
  
                        glEnable(GL_BLEND);
 -                      glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
                        /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
                        if (check_object_draw_texture(scene, v3d, dt))
  #endif
  
                        glDisable(GL_BLEND);
 -                      glDepthMask(1);  /* restore write in zbuffer */
 +                      glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                }
                else if (efa_act) {
                        /* even if draw faces is off it would be nice to draw the stipple face
                        UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
  
                        glEnable(GL_BLEND);
 -                      glDepthMask(0);  /* disable write in zbuffer, needed for nice transp */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, needed for nice transp */
  
  #ifdef WITH_FREESTYLE
                        draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
  #endif
  
                        glDisable(GL_BLEND);
 -                      glDepthMask(1);  /* restore write in zbuffer */
 +                      glDepthMask(GL_TRUE);  /* restore write in zbuffer */
                }
  
                /* here starts all fancy draw-extra over */
                else {
                        if (me->drawflag & ME_DRAWSEAMS) {
                                UI_ThemeColor(TH_EDGE_SEAM);
 -                              glLineWidth(2);
 +                              glLineWidth(2.0f);
  
                                draw_dm_edges_seams(em, cageDM);
  
  
                        if (me->drawflag & ME_DRAWSHARP) {
                                UI_ThemeColor(TH_EDGE_SHARP);
 -                              glLineWidth(2);
 +                              glLineWidth(2.0f);
  
                                draw_dm_edges_sharp(em, cageDM);
  
  #ifdef WITH_FREESTYLE
                        if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
                                UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
 -                              glLineWidth(2);
 +                              glLineWidth(2.0f);
  
                                draw_dm_edges_freestyle(em, cageDM);
  
                                draw_dm_bweights(em, scene, cageDM);
                        }
  
 -                      glLineWidth(1);
 +                      glLineWidth(1.0f);
                        draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
                }
  
                        draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
  
                        if (me->drawflag & ME_DRAWNORMALS) {
 -                              UI_ThemeColor(TH_NORMAL);
 -                              draw_dm_face_normals(em, scene, ob, cageDM);
 +                              draw_dm_face_normals(em, scene, ob, cageDM, TH_NORMAL);
                        }
                        if (me->drawflag & ME_DRAW_VNORMALS) {
 -                              UI_ThemeColor(TH_VNORMAL);
 -                              draw_dm_vert_normals(em, scene, ob, cageDM);
 +                              draw_dm_vert_normals(em, scene, ob, cageDM, TH_VNORMAL);
                        }
                        if (me->drawflag & ME_DRAW_LNORMALS) {
 -                              UI_ThemeColor(TH_LNORMAL);
 -                              draw_dm_loop_normals(em, scene, ob, cageDM);
 +                              draw_dm_loop_normals(em, scene, ob, cageDM, TH_LNORMAL);
                        }
  
                        if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
        }
  
        if (use_depth_offset) {
 -              glDepthMask(1);
 +              glDepthMask(GL_TRUE);
                ED_view3d_polygon_offset(rv3d, 0.0);
                GPU_object_material_unbind();
        }
  #endif
  }
  
 +static void draw_em_fancy_new(Scene *UNUSED(scene), ARegion *UNUSED(ar), View3D *UNUSED(v3d),
 +                              Object *UNUSED(ob), Mesh *me, BMEditMesh *UNUSED(em), DerivedMesh *UNUSED(cageDM), DerivedMesh *UNUSED(finalDM), const char UNUSED(dt))
 +{
 +      /* for now... something simple! */
 +      Gwn_Batch *surface = DRW_mesh_batch_cache_get_all_triangles(me);
 +
 +      glEnable(GL_DEPTH_TEST);
 +      glDepthFunc(GL_LEQUAL);
 +
 +      glEnable(GL_BLEND);
 +
 +      /* disable depth writes for transparent surface, so it doesn't interfere with itself */
 +      glDepthMask(GL_FALSE);
 +
 +      Batch_set_builtin_program(surface, GPU_SHADER_3D_UNIFORM_COLOR);
 +      GWN_batch_uniform_4f(surface, "color", 1.0f, 0.5f, 0.0f, 0.5f);
 +      GWN_batch_draw(surface);
 +
 +#if 0 /* until I understand finalDM better */
 +      if (finalDM != cageDM) {
 +              puts("finalDM != cageDM");
 +              Gwn_Batch *finalSurface = MBC_get_all_triangles(finalDM);
 +              Batch_set_builtin_program(finalSurface, GPU_SHADER_3D_UNIFORM_COLOR);
 +              GWN_batch_uniform_4f(finalSurface, "color", 0.0f, 0.0f, 0.0f, 0.05f);
 +              GWN_batch_draw(finalSurface);
 +      }
 +#endif
 +
 +      glDepthMask(GL_TRUE);
 +
 +      /* now write surface depth so other objects won't poke through
 +       * NOTE: does not help as much as desired
 +       * TODO: draw edit object last to avoid this mess
 +       */
 +      Batch_set_builtin_program(surface, GPU_SHADER_3D_DEPTH_ONLY);
 +      GWN_batch_draw(surface);
 +
 +      if (GLEW_VERSION_3_2) {
 +#if 0
 +              Gwn_Batch *overlay = DRW_mesh_batch_cache_get_overlay_edges(me);
 +              Batch_set_builtin_program(overlay, GPU_SHADER_EDGES_OVERLAY);
 +              GWN_batch_uniform_2f(overlay, "viewportSize", ar->winx, ar->winy);
 +              GWN_batch_draw(overlay);
 +#endif
 +
 +#if 0 /* TODO: use this SIMPLE variant for pure triangle meshes */
 +              Batch_set_builtin_program(surface, GPU_SHADER_EDGES_OVERLAY_SIMPLE);
 +              /* use these defaults:
 +               * const float edgeColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
 +               * GWN_batch_uniform_4f(surface, "fillColor", edgeColor[0], edgeColor[1], edgeColor[2], 0.0f);
 +               * GWN_batch_uniform_4fv(surface, "outlineColor", edgeColor);
 +               * GWN_batch_uniform_1f(surface, "outlineWidth", 1.0f);
 +               */
 +              GWN_batch_uniform_2f(surface, "viewportSize", ar->winx, ar->winy);
 +              GWN_batch_draw(surface);
 +#endif
 +      }
 +      else {
 +              Gwn_Batch *edges = DRW_mesh_batch_cache_get_all_edges(me);
 +              Batch_set_builtin_program(edges, GPU_SHADER_3D_UNIFORM_COLOR);
 +              GWN_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
 +              glEnable(GL_LINE_SMOOTH);
 +              glLineWidth(1.5f);
 +              GWN_batch_draw(edges);
 +              glDisable(GL_LINE_SMOOTH);
 +      }
 +
 +#if 0 /* looks good even without points */
 +      Gwn_Batch *verts = MBC_get_all_verts(me);
 +      glEnable(GL_BLEND);
 +
 +      Batch_set_builtin_program(verts, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
 +      GWN_batch_uniform_4f(verts, "color", 0.0f, 0.0f, 0.0f, 1.0f);
 +      GWN_batch_uniform_1f(verts, "size", UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.5f);
 +      GWN_batch_draw(verts);
 +
 +      glDisable(GL_BLEND);
 +#endif
 +}
 +
  /* Mesh drawing routines */
  
 -static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
 +void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm, const unsigned char ob_wire_col[4]) /* LEGACY */
  {
        if ((v3d->transp == false) &&  /* not when we draw the transparent pass */
            (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */
        {
                glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
 -              glDepthMask(0);
 +              glDepthMask(GL_FALSE);
 +
 +              if (ob_wire_col) glColor4ubv(ob_wire_col);
  
                /* if transparent, we cannot draw the edges for solid select... edges
                 * have no material info. GPU_object_material_visible will skip the
                        dm->drawEdges(dm, 0, 1);
                }
  
 -              glDepthMask(1);
 +              glDepthMask(GL_TRUE);
 +      }
 +}
 +
 +static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, Mesh *me, const bool is_active)
 +{
 +      if ((v3d->transp == false) &&  /* not when we draw the transparent pass */
 +          (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */
 +      {
 +              glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
 +              glDepthMask(GL_FALSE);
 +
 +              float outline_color[4];
 +              UI_GetThemeColor4fv((is_active ? TH_ACTIVE : TH_SELECT), outline_color);
 +
 +#if 1 /* new version that draws only silhouette edges */
 +              Gwn_Batch *fancy_edges = DRW_mesh_batch_cache_get_fancy_edges(me);
 +
 +              if (rv3d->persp == RV3D_ORTHO) {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO);
 +                      /* set eye vector, transformed to object coords */
 +                      float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
 +                      mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye);
 +                      GWN_batch_uniform_3fv(fancy_edges, "eye", eye);
 +              }
 +              else {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
 +              }
 +
 +              GWN_batch_uniform_1b(fancy_edges, "drawFront", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawBack", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", true);
 +              GWN_batch_uniform_4fv(fancy_edges, "silhouetteColor", outline_color);
 +
 +              GWN_batch_draw(fancy_edges);
 +#else /* alternate version that matches look of old viewport (but more efficient) */
 +              Gwn_Batch *batch = MBC_get_all_edges(dm);
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +              GWN_batch_uniform_4fv(batch, "color", outline_color);
 +              GWN_batch_draw(batch);
 +#endif
 +
 +              glDepthMask(GL_TRUE);
        }
  }
  
@@@ -4293,11 -3959,11 +4293,11 @@@ static bool object_is_halo(Scene *scene
        return (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene));
  }
  
 -static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static void draw_mesh_fancy(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
                              const char dt, const unsigned char ob_wire_col[4], const short dflag)
  {
  #ifdef WITH_GAMEENGINE
 -      Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : base->object;
 +      Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, sl) : base->object;
  #else
        Object *ob = base->object;
  #endif
        eWireDrawMode draw_wire = OBDRAW_WIRE_OFF;
        bool /* no_verts,*/ no_edges, no_faces;
        DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
 -      const bool is_obact = (ob == OBACT);
 +      const bool is_obact = (ob == OBACT_NEW);
        int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
  
        if (!dm)
  
        if (dt == OB_BOUNDBOX) {
                if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
 -                      draw_bounding_volume(ob, ob->boundtype);
 +                      draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
        }
        else if ((no_faces && no_edges) ||
                 ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
        {
 -              glPointSize(1.5);
 +              glPointSize(1.5f);
                dm->drawVerts(dm);
        }
        else if ((dt == OB_WIRE) || no_faces) {
  
                if ((v3d->flag & V3D_SELECT_OUTLINE) &&
                    ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 -                  (base->flag & SELECT) &&
 +                  (base->flag & BASE_SELECTED) &&
                    !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
                    (draw_wire == OBDRAW_WIRE_OFF))
                {
 -                      draw_mesh_object_outline(v3d, ob, dm);
 +                      draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
                }
  
 -              if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
 +              if (draw_glsl_material(scene, sl, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
                        Paint *p;
  
                        glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
 -                      if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) {
 +                      if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
                                GPUVertexAttribs gattribs;
                                float planes[4][4];
                                float (*fpl)[4] = NULL;
  
                                if (ob->sculpt->partial_redraw) {
                                        if (ar->do_draw & RGN_DRAW_PARTIAL) {
 -                                              ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
                                                fpl = planes;
                                                ob->sculpt->partial_redraw = 0;
                                        }
                                draw_mesh_face_select(rv3d, me, dm, false);
                }
                else {
 -                      draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags);
 +                      draw_mesh_textured(scene, sl, v3d, rv3d, ob, dm, draw_flags);
                }
  
                if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) {
                                /* draw outline */
                                if ((v3d->flag & V3D_SELECT_OUTLINE) &&
                                    ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 -                                  (base->flag & SELECT) &&
 +                                  (base->flag & BASE_SELECTED) &&
                                    (draw_wire == OBDRAW_WIRE_OFF) &&
                                    (ob->sculpt == NULL))
                                {
 -                                      draw_mesh_object_outline(v3d, ob, dm);
 +                                      draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
                                }
  
                                /* materials arent compatible with vertex colors */
  
                        if ((v3d->flag & V3D_SELECT_OUTLINE) &&
                            ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 -                          (base->flag & SELECT) &&
 +                          (base->flag & BASE_SELECTED) &&
                            (draw_wire == OBDRAW_WIRE_OFF) &&
                            (ob->sculpt == NULL))
                        {
 -                              draw_mesh_object_outline(v3d, ob, dm);
 +                              draw_mesh_object_outline(v3d, ob, dm, ob_wire_col);
                        }
  
                        glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
 -                      if (ob->sculpt && (p = BKE_paint_get_active(scene))) {
 +                      if (ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
                                float planes[4][4];
                                float (*fpl)[4] = NULL;
                                const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
  
                                if (ob->sculpt->partial_redraw) {
                                        if (ar->do_draw & RGN_DRAW_PARTIAL) {
 -                                              ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
                                                fpl = planes;
                                                ob->sculpt->partial_redraw = 0;
                                        }
  
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
                        if (is_obact && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
 -                              ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f);
 +                              float color[3];
 +                              ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f, color);
 +                              glColor3fv(color);
                        }
                        else {
                                glColor3ubv(ob_wire_col);
                 */
                if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
                        ED_view3d_polygon_offset(rv3d, 1.0);
 -                      glDepthMask(0);  /* disable write in zbuffer, selected edge wires show better */
 +                      glDepthMask(GL_FALSE);  /* disable write in zbuffer, selected edge wires show better */
                }
                
                glLineWidth(1.0f);
                dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
  
                if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
 -                      glDepthMask(1);
 +                      glDepthMask(GL_TRUE);
                        ED_view3d_polygon_offset(rv3d, 0.0);
                }
        }
  }
  
  /* returns true if nothing was drawn, for detecting to draw an object center */
 -static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static bool draw_mesh_object(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base,
                               const char dt, const unsigned char ob_wire_col[4], const short dflag)
  {
        Object *ob = base->object;
        /* If we are drawing shadows and any of the materials don't cast a shadow,
         * then don't draw the object */
        if (v3d->flag2 & V3D_RENDER_SHADOW) {
 -              for (int i = 1; i <= ob->totcol; ++i) {
 +              for (int i = 0; i < ob->totcol; ++i) {
                        Material *ma = give_current_material(ob, i);
                        if (ma && !(ma->mode2 & MA_CASTSHADOW)) {
                                return true;
  
                if (use_material) {
                        if (dt > OB_WIRE) {
 -                              const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
 +                              const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
  
 -                              GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
 +                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
                        }
                }
  
 -              draw_em_fancy(scene, ar, v3d, ob, em, cageDM, finalDM, dt);
 +              draw_em_fancy(scene, sl, ar, v3d, ob, em, cageDM, finalDM, dt);
  
                if (use_material) {
                        GPU_end_object_materials();
                /* ob->bb was set by derived mesh system, do NULL check just to be sure */
                if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) {
                        if (dt > OB_WIRE) {
 -                              const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
 +                              const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
  
                                if (dt == OB_SOLID || glsl) {
                                        const bool check_alpha = check_alpha_pass(base);
 -                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl,
                                                                   (check_alpha) ? &do_alpha_after : NULL);
                                }
                        }
  
 -                      draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
 +                      draw_mesh_fancy(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
  
                        GPU_end_object_materials();
                        
                }
        }
        
 -      if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
 +      if ((dflag & DRAW_PICKING) == 0 && (base->flag_legacy & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
                /* GPU_begin_object_materials checked if this is needed */
                if (do_alpha_after) {
                        if (ob->dtx & OB_DRAWXRAY) {
        return retval;
  }
  
 -/* ************** DRAW DISPLIST ****************** */
 -
 -
 -/**
 - * \param dl_type_mask Only draw types matching this mask.
 - * \return true when nothing was drawn
 - */
 -static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
 +static void make_color_variations(const unsigned char base_ubyte[4], float low[4], float med[4], float high[4], const bool other_obedit)
  {
 -      if (dlbase == NULL) return true;
 -      
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 +      /* original idea: nice variations (lighter & darker shades) of base color
 +       * current implementation uses input color as high; med & low get closer to background color
 +       */
  
 -      for (DispList *dl = dlbase->first; dl; dl = dl->next) {
 -              if (dl->parts == 0 || dl->nr == 0) {
 -                      continue;
 -              }
 +      float bg[3];
 +      UI_GetThemeColor3fv(TH_BACK, bg);
  
 -              if ((dl_type_mask & (1 << dl->type)) == 0) {
 -                      continue;
 -              }
 -              
 -              const float *data = dl->verts;
 -              int parts;
 +      float base[4];
 +      rgba_uchar_to_float(base, base_ubyte);
  
 -              switch (dl->type) {
 -                      case DL_SEGM:
 +      if (other_obedit) {
 +              /* this object should fade away so user can focus on the object being edited */
 +              interp_v3_v3v3(low, bg, base, 0.1f);
 +              interp_v3_v3v3(med, bg, base, 0.2f);
 +              interp_v3_v3v3(high, bg, base, 0.25f);
 +      }
 +      else {
 +              interp_v3_v3v3(low, bg, base, 0.333f);
 +              interp_v3_v3v3(med, bg, base, 0.667f);
 +              copy_v3_v3(high, base);
 +      }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +      /* use original alpha */
 +      low[3] = base[3];
 +      med[3] = base[3];
 +      high[3] = base[3];
 +}
  
 -                              for (parts = 0; parts < dl->parts; parts++)
 -                                      glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
 -                              
 -                              break;
 -                      case DL_POLY:
 +static void draw_mesh_fancy_new(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
 +                                const char dt, const unsigned char ob_wire_col[4], const short dflag, const bool other_obedit)
 +{
 +      if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) {
 +              /* too complicated! use existing methods */
 +              /* TODO: move this into a separate depth pre-pass */
 +              draw_mesh_fancy(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
 +              return;
 +      }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +#ifdef WITH_GAMEENGINE
 +      Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, sl) : base->object;
 +#else
 +      Object *ob = base->object;
 +#endif
 +      Mesh *me = ob->data;
 +      eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; /* could be bool draw_wire_overlay */
 +      bool no_edges, no_faces;
 +      DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
 +      const bool is_obact = (ob == OBACT_NEW);
 +      int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
  
 -                              for (parts = 0; parts < dl->parts; parts++)
 -                                      glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
 +      if (!dm)
 +              return;
  
 -                              break;
 -                      case DL_SURF:
 +      const bool solid = dt >= OB_SOLID;
 +      if (solid) {
 +              DM_update_materials(dm, ob);
 +      }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +      /* Check to draw dynamic paint colors (or weights from WeightVG modifiers).
 +       * Note: Last "preview-active" modifier in stack will win! */
 +      if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob))
 +              draw_flags |= DRAW_MODIFIERS_PREVIEW;
  
 -                              for (parts = 0; parts < dl->parts; parts++) {
 -                                      if (dl->flag & DL_CYCL_U)
 -                                              glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
 -                                      else
 -                                              glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
 -                              }
 +      /* Unwanted combination */
 +      if (draw_flags & DRAW_FACE_SELECT) {
 +              draw_wire = OBDRAW_WIRE_OFF;
 +      }
 +      else if (ob->dtx & OB_DRAWWIRE) {
 +              draw_wire = OBDRAW_WIRE_ON;
 +      }
  
 -                              for (int nr = 0; nr < dl->nr; nr++) {
 -                                      int ofs = 3 * dl->nr;
 +      /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */
 +      if (dm->type == DM_TYPE_CCGDM) {
 +              no_edges = !subsurf_has_edges(dm);
 +              no_faces = !subsurf_has_faces(dm);
 +      }
 +      else {
 +              no_edges = (dm->getNumEdges(dm) == 0);
 +              no_faces = (dm->getNumPolys(dm) == 0);
 +      }
  
 -                                      data = (dl->verts) + 3 * nr;
 -                                      parts = dl->parts;
 +      if (solid) {
 +              /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
 +              glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 +      }
  
 -                                      if (dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP);
 -                                      else glBegin(GL_LINE_STRIP);
 +      if (dt == OB_BOUNDBOX) {
 +              if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
 +                      draw_bounding_volume(ob, ob->boundtype, ob_wire_col);
 +      }
 +      else if ((no_faces && no_edges) ||
 +               ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
 +      {
 +              glPointSize(1.5f);
 +              // dm->drawVerts(dm);
 +              // TODO: draw smooth round points as a batch
 +      }
 +      else if ((dt == OB_WIRE) || no_faces) {
 +              draw_wire = OBDRAW_WIRE_ON;
  
 -                                      while (parts--) {
 -                                              glVertex3fv(data);
 -                                              data += ofs;
 -                                      }
 -                                      glEnd();
 +              /* enable depth for wireframes */
 +              glEnable(GL_DEPTH_TEST);
 +              glDepthFunc(GL_LESS);
  
 -#if 0
 -                              /* (ton) this code crashes for me when resolv is 86 or higher... no clue */
 -                              glVertexPointer(3, GL_FLOAT, sizeof(float) * 3 * dl->nr, data + 3 * nr);
 -                              if (dl->flag & DL_CYCL_V)
 -                                      glDrawArrays(GL_LINE_LOOP, 0, dl->parts);
 -                              else
 -                                      glDrawArrays(GL_LINE_STRIP, 0, dl->parts);
 -#endif
 -                              }
 -                              break;
 +              glLineWidth(1.0f);
  
 -                      case DL_INDEX3:
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              break;
 +#if 1 /* fancy wireframes */
  
 -                      case DL_INDEX4:
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              break;
 +              Gwn_Batch *fancy_edges = DRW_mesh_batch_cache_get_fancy_edges(me);
 +
 +              if (rv3d->persp == RV3D_ORTHO) {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_ORTHO);
 +                      /* set eye vector, transformed to object coords */
 +                      float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */
 +                      mul_m3_v3(gpuGetNormalMatrixInverse(NULL), eye);
 +                      GWN_batch_uniform_3fv(fancy_edges, "eye", eye);
 +              }
 +              else {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
                }
 -      }
 -      
 -      glDisableClientState(GL_VERTEX_ARRAY);
 -      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -      
 -      return false;
 -}
  
 -static bool drawDispListwire(ListBase *dlbase, const short ob_type)
 -{
 -      unsigned int dl_mask = 0xffffffff;
 +              float frontColor[4];
 +              float backColor[4];
 +              float outlineColor[4];
 +              make_color_variations(ob_wire_col, backColor, frontColor, outlineColor, other_obedit);
  
 -      /* skip fill-faces for curves & fonts */
 -      if (ELEM(ob_type, OB_FONT, OB_CURVE)) {
 -              dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4));
 -      }
 +              GWN_batch_uniform_4fv(fancy_edges, "frontColor", frontColor);
 +              GWN_batch_uniform_4fv(fancy_edges, "backColor", backColor);
 +              GWN_batch_uniform_1b(fancy_edges, "drawFront", true);
 +              GWN_batch_uniform_1b(fancy_edges, "drawBack", true); /* false here = backface cull */
 +              GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", false);
  
 -      return drawDispListwire_ex(dlbase, dl_mask);
 -}
 +              GWN_batch_draw(fancy_edges);
  
 -static bool index3_nors_incr = true;
 +              /* extra oomph for the silhouette contours */
 +              glLineWidth(2.0f);
 +              GWN_batch_program_use_begin(fancy_edges); /* hack to make the following uniforms stick */
 +              GWN_batch_uniform_1b(fancy_edges, "drawFront", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawBack", false);
 +              GWN_batch_uniform_1b(fancy_edges, "drawSilhouette", true);
 +              GWN_batch_uniform_4fv(fancy_edges, "silhouetteColor", outlineColor);
  
 -static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
 -                              const unsigned char ob_wire_col[4], const bool use_glsl)
 -{
 -      GPUVertexAttribs gattribs;
 -      
 -      if (lb == NULL) return;
 +              GWN_batch_draw(fancy_edges);
  
 -      glEnableClientState(GL_VERTEX_ARRAY);
 +#else /* simple wireframes */
  
 -      /* track current material, -1 for none (needed for lines) */
 -      short col = -1;
 -      
 -      DispList *dl = lb->first;
 -      while (dl) {
 -              const float *data = dl->verts;
 -              const float *ndata = dl->nors;
 +              Gwn_Batch *batch = MBC_get_all_edges(dm);
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
  
 -              switch (dl->type) {
 -                      case DL_SEGM:
 -                              if (ob->type == OB_SURF) {
 -                                      if (col != -1) {
 -                                              GPU_object_material_unbind();
 -                                              col = -1;
 -                                      }
 +              float color[4];
 +              rgba_uchar_to_float(color, ob_wire_col);
  
 -                                      if ((dflag & DRAW_CONSTCOLOR) == 0)
 -                                              glColor3ubv(ob_wire_col);
 +              GWN_batch_uniform_4fv(batch, "color", color);
 +
 +              GWN_batch_draw(batch);
 +#endif
 +      }
 +      else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) ||
 +               check_object_draw_texture(scene, v3d, dt))
 +      {
 +              bool draw_loose = true;
 +
 +              if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                  ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                  (base->flag & BASE_SELECTED) &&
 +                  !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
 +                  (draw_wire == OBDRAW_WIRE_OFF))
 +              {
 +                      draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
 +              }
 +
 +              if (draw_glsl_material(scene, sl, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
 +                      Paint *p;
 +
 +                      glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 +
 +                      if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
 +                              GPUVertexAttribs gattribs;
 +                              float planes[4][4];
 +                              float (*fpl)[4] = NULL;
 +                              const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
 +
 +                              if (ob->sculpt->partial_redraw) {
 +                                      if (ar->do_draw & RGN_DRAW_PARTIAL) {
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
 +                                              fpl = planes;
 +                                              ob->sculpt->partial_redraw = 0;
 +                                      }
 +                              }
 +
 +                              GPU_object_material_bind(1, &gattribs);
 +                              dm->drawFacesSolid(dm, fpl, fast, NULL);
 +                              draw_loose = false;
 +                      }
 +                      else
 +                              dm->drawFacesGLSL(dm, GPU_object_material_bind);
 +
 +                      GPU_object_material_unbind();
 +
 +                      glFrontFace(GL_CCW);
 +
 +                      if (draw_flags & DRAW_FACE_SELECT)
 +                              draw_mesh_face_select(rv3d, me, dm, false);
 +              }
 +              else {
 +                      draw_mesh_textured(scene, sl, v3d, rv3d, ob, dm, draw_flags);
 +              }
 +
 +              if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) {
 +                      if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
 +                              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                                      glColor3ubv(ob_wire_col);
 +                              }
 +                              glLineWidth(1.0f);
 +                              dm->drawLooseEdges(dm);
 +                      }
 +              }
 +      }
 +      else if (dt == OB_SOLID) {
 +              if (draw_flags & DRAW_MODIFIERS_PREVIEW) {
 +                      /* for object selection draws no shade */
 +                      if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) {
 +                              /* TODO: draw basic faces with GPU_SHADER_3D_DEPTH_ONLY */
 +                      }
 +                      else {
 +                              const float specular[3] = {0.47f, 0.47f, 0.47f};
 +
 +                              /* draw outline */
 +                              /* TODO: move this into a separate pass */
 +                              if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                                  ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                                  (base->flag & BASE_SELECTED) &&
 +                                  (draw_wire == OBDRAW_WIRE_OFF) &&
 +                                  (ob->sculpt == NULL))
 +                              {
 +                                      draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
 +                              }
 +
 +                              /* materials arent compatible with vertex colors */
 +                              GPU_end_object_materials();
 +
 +                              /* set default specular */
 +                              GPU_basic_shader_colors(NULL, specular, 35, 1.0f);
 +                              GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
 +
 +                              dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS);
 +
 +                              GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
 +                      }
 +              }
 +              else {
 +                      Paint *p;
 +
 +                      if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                          ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                          (base->flag & BASE_SELECTED) &&
 +                          (draw_wire == OBDRAW_WIRE_OFF) &&
 +                          (ob->sculpt == NULL))
 +                      {
 +                              /* TODO: move this into a separate pass */
 +                              draw_mesh_object_outline_new(v3d, rv3d, ob, me, (ob == OBACT_NEW));
 +                      }
 +
 +                      glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 +
 +                      if (ob->sculpt && (p = BKE_paint_get_active(scene, sl))) {
 +                              float planes[4][4];
 +                              float (*fpl)[4] = NULL;
 +                              const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
 +
 +                              if (ob->sculpt->partial_redraw) {
 +                                      if (ar->do_draw & RGN_DRAW_PARTIAL) {
 +                                              ED_sculpt_redraw_planes_get(planes, ar, ob);
 +                                              fpl = planes;
 +                                              ob->sculpt->partial_redraw = 0;
 +                                      }
 +                              }
 +
 +                              dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind);
 +                      }
 +                      else
 +                              dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
 +
 +                      glFrontFace(GL_CCW);
 +
 +                      GPU_object_material_unbind();
 +
 +                      if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
 +                              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                                      glColor3ubv(ob_wire_col);
 +                              }
 +                              glLineWidth(1.0f);
 +                              dm->drawLooseEdges(dm);
 +                      }
 +              }
 +      }
 +      else if (dt == OB_PAINT) {
 +              draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags);
 +
 +              /* since we already draw wire as wp guide, don't draw over the top */
 +              draw_wire = OBDRAW_WIRE_OFF;
 +      }
 +
 +      if ((draw_wire != OBDRAW_WIRE_OFF) &&  /* draw extra wire */
 +          /* when overriding with render only, don't bother */
 +          (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)) // <-- is this "== 0" in the right spot???
 +      {
 +              /* When using wireframe object draw in particle edit mode
 +               * the mesh gets in the way of seeing the particles, fade the wire color
 +               * with the background. */
 +
 +              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                      /* TODO:
 +                       * Batch_UniformColor4ubv(ob_wire_col);
 +                       */
 +              }
 +
 +              /* If drawing wire and drawtype is not OB_WIRE then we are
 +               * overlaying the wires.
 +               *
 +               * No need for polygon offset because new technique is AWESOME.
 +               */
 +#if 0
 +              glLineWidth(1.0f);
 +              dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
 +#else
 +              /* something */
 +#endif
 +      }
 +      
 +#if 0 // (merwin) what is this for?
 +      if (is_obact && BKE_paint_select_vert_test(ob)) {
 +              const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0;
 +              glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 +
 +              if (!use_depth) glDisable(GL_DEPTH_TEST);
 +              else            ED_view3d_polygon_offset(rv3d, 1.0);
 +              drawSelectedVertices(dm, ob->data);
 +              if (!use_depth) glEnable(GL_DEPTH_TEST);
 +              else            ED_view3d_polygon_offset(rv3d, 0.0);
 +      }
 +#endif
 +
 +      dm->release(dm);
 +}
 +
 +static bool UNUSED_FUNCTION(draw_mesh_object_new)(Scene *scene, SceneLayer *sl, ARegion *ar, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base,
 +                                 const char dt, const unsigned char ob_wire_col[4], const short dflag)
 +{
 +      Object *ob = base->object;
 +      Object *obedit = scene->obedit;
 +      Mesh *me = ob->data;
 +      BMEditMesh *em = me->edit_btmesh;
 +      bool do_alpha_after = false, drawlinked = false, retval = false;
 +
 +      if (v3d->flag2 & V3D_RENDER_SHADOW) {
 +              /* TODO: handle shadow pass separately */
 +              return true;
 +      }
 +      
 +      if (obedit && ob != obedit && ob->data == obedit->data) {
 +              if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {}
 +              else if (ob->modifiers.first || obedit->modifiers.first) {}
 +              else drawlinked = true;
 +      }
 +
 +      /* backface culling */
 +      const bool solid = dt > OB_WIRE;
 +      const bool cullBackface = solid && (v3d->flag2 & V3D_BACKFACE_CULLING);
 +      if (cullBackface) {
 +              glEnable(GL_CULL_FACE);
 +              glCullFace(GL_BACK);
 +      }
 +
 +      if (ob == obedit || drawlinked) {
 +              DerivedMesh *finalDM, *cageDM;
 +
 +              if (obedit != ob) {
 +                      /* linked to the edit object */
 +                      finalDM = cageDM = editbmesh_get_derived_base(
 +                              ob, em, scene->customdata_mask);
 +              }
 +              else {
 +                      cageDM = editbmesh_get_derived_cage_and_final(
 +                              scene, ob, em, scene->customdata_mask,
 +                              &finalDM);
 +              }
 +
 +              const bool use_material = solid && ((me->drawflag & ME_DRAWEIGHT) == 0);
 +
 +#if 0 // why update if not being used?
 +              DM_update_materials(finalDM, ob);
 +              if (cageDM != finalDM) {
 +                      DM_update_materials(cageDM, ob);
 +              }
 +#endif // moved to below
 +
 +              if (use_material) {
 +                      DM_update_materials(finalDM, ob);
 +                      if (cageDM != finalDM) {
 +                              DM_update_materials(cageDM, ob);
 +                      }
 +
 +                      const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
 +
 +                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
 +              }
 +
 +              draw_em_fancy_new(scene, ar, v3d, ob, me, em, cageDM, finalDM, dt);
 +
 +              if (use_material) {
 +                      GPU_end_object_materials();
 +              }
 +
 +              if (obedit != ob)
 +                      finalDM->release(finalDM);
 +      }
 +      else {
 +              /* ob->bb was set by derived mesh system, do NULL check just to be sure */
 +              if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) {
 +                      if (solid) {
 +                              const bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
 +
 +                              if (dt == OB_SOLID || glsl) {
 +                                      const bool check_alpha = check_alpha_pass(base);
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl,
 +                                                                 (check_alpha) ? &do_alpha_after : NULL);
 +                              }
 +                      }
 +
 +                      const bool other_obedit = obedit && (obedit != ob);
 +
 +                      draw_mesh_fancy_new(scene, sl, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit);
 +
 +                      GPU_end_object_materials();
 +
 +                      if (me->totvert == 0) retval = true;
 +              }
 +      }
 +
 +      if (cullBackface)
 +              glDisable(GL_CULL_FACE);
 +
 +      return retval;
 +}
 +
 +/* ************** DRAW DISPLIST ****************** */
 +
 +static void drawDispListVerts(Gwn_PrimType prim_type, const void *data, unsigned int vert_ct, const unsigned char wire_col[3])
 +{
 +      Gwn_VertFormat format = {0};
 +      unsigned int pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +      GWN_vertbuf_data_alloc(vbo, vert_ct);
 +
 +      GWN_vertbuf_attr_fill(vbo, pos_id, data);
 +
 +      Gwn_Batch *batch = GWN_batch_create(prim_type, vbo, NULL);
 +      Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +      if (wire_col) {
 +              GWN_batch_uniform_4f(batch, "color", wire_col[0] / 255.0f, wire_col[1] / 255.0f, wire_col[2] / 255.0f, 1.0f);
 +      }
 +      GWN_batch_draw(batch);
 +      GWN_batch_discard_all(batch);
 +}
 +
 +/* convert dispList with elem indices to batch, only support triangles and quads
 + * XXX : This is a huge perf issue. We should cache the resulting batches inside the object instead.
 + *       But new viewport will do it anyway
 + * TODO implement flat drawing */
 +static void drawDispListElem(
 +        bool quads, bool UNUSED(smooth), bool ndata_is_single,
 +        const float *data, const float *ndata, unsigned int data_len,
 +        const int *elem, unsigned int elem_len, const unsigned char wire_col[3])
 +{
 +      Gwn_VertFormat format = {0};
 +      int i;
 +      const int *idx = elem;
 +      unsigned int pos_id, nor_id;
 +
 +      pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (ndata) {
 +              if (ndata_is_single) {
 +                      /* pass */
 +              }
 +              else {
 +                      nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +              }
 +      }
 +
 +      Gwn_IndexBufBuilder elb;
 +      GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, (quads) ? elem_len * 2 : elem_len, 0xffffffff);
 +
 +      if (quads) {
 +              for (i = elem_len; i; --i, idx += 4) {
 +                      GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
 +                      GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[2], idx[3]);
 +              }
 +      }
 +      else {
 +              for (i = elem_len; i; --i, idx += 3) {
 +                      GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
 +              }
 +      }
 +
 +      Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +      GWN_vertbuf_data_alloc(vbo, data_len);
 +
 +      GWN_vertbuf_attr_fill(vbo, pos_id, data);
 +
 +      if (ndata) {
 +              if (ndata_is_single) {
 +                      /* TODO: something like glNormal for a single value */
 +              }
 +              else {
 +                      GWN_vertbuf_attr_fill(vbo, nor_id, ndata);
 +              }
 +      }
 +
 +      Gwn_Batch *batch = GWN_batch_create(GWN_PRIM_TRIS, vbo, GWN_indexbuf_build(&elb));
 +      Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
 +      if (wire_col) {
 +              GWN_batch_uniform_4f(batch, "color", wire_col[0] / 255.0f, wire_col[1] / 255.0f, wire_col[2] / 255.0f, 1.0f);
 +      }
 +      GWN_batch_uniform_4f(batch, "color", 0.8f, 0.8f, 0.8f, 1.0f);
 +      GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
 +      GWN_batch_draw(batch);
 +      GWN_batch_discard_all(batch);
 +}
 +
 +/**
 + * \param dl_type_mask Only draw types matching this mask.
 + * \return true when nothing was drawn
 + */
 +static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask, const unsigned char wire_col[3])
 +{
 +      if (dlbase == NULL) return true;
 +      
 +      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 +
 +      for (DispList *dl = dlbase->first; dl; dl = dl->next) {
 +              if (dl->parts == 0 || dl->nr == 0) {
 +                      continue;
 +              }
 +
 +              if ((dl_type_mask & (1 << dl->type)) == 0) {
 +                      continue;
 +              }
 +
 +              const float *data = dl->verts;
 +              int parts;
 +
 +              switch (dl->type) {
 +                      case DL_SEGM:
 +                              for (parts = 0; parts < dl->parts; parts++)
 +                                      drawDispListVerts(GWN_PRIM_LINE_STRIP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                              break;
  
 -                                      // glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                                      // glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
 -                                      glBegin(GL_LINE_STRIP);
 -                                      for (int nr = dl->nr; nr; nr--, data += 3)
 -                                              glVertex3fv(data);
 -                                      glEnd();
 -                              }
 -                              break;
                        case DL_POLY:
 +                              for (parts = 0; parts < dl->parts; parts++)
 +                                      drawDispListVerts(GWN_PRIM_LINE_LOOP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                              break;
 +
 +                      case DL_SURF:
 +                              for (parts = 0; parts < dl->parts; parts++) {
 +                                      if (dl->flag & DL_CYCL_U)
 +                                              drawDispListVerts(GWN_PRIM_LINE_LOOP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                                      else
 +                                              drawDispListVerts(GWN_PRIM_LINE_STRIP, data + (parts * dl->nr * 3), dl->nr, wire_col);
 +                              }
 +
 +                              float *data_aligned = MEM_mallocN(sizeof(float) * 3 * dl->parts, "aligned data");
 +                              for (int nr = 0; nr < dl->nr; nr++) {
 +                                      int ofs = 3 * dl->nr;
 +                                      int idx = 0;
 +
 +                                      data = (dl->verts) + 3 * nr;
 +                                      parts = dl->parts;
 +
 +                                      while (parts--) {
 +                                              copy_v3_v3(data_aligned + idx, data);
 +                                              data += ofs;
 +                                              idx += 3;
 +                                      }
 +
 +                                      if (dl->flag & DL_CYCL_V)
 +                                              drawDispListVerts(GWN_PRIM_LINE_LOOP, data_aligned, dl->parts, wire_col);
 +                                      else
 +                                              drawDispListVerts(GWN_PRIM_LINE_STRIP, data_aligned, dl->parts, wire_col);
 +                              }
 +
 +                              if (data_aligned)
 +                                      MEM_freeN(data_aligned);
 +
 +                              break;
 +
 +                      case DL_INDEX3:
 +                              drawDispListElem(
 +                                      false, true, false,
 +                                      dl->verts, NULL, dl->nr,
 +                                      dl->index, dl->parts, wire_col);
 +                              break;
 +
 +                      case DL_INDEX4:
 +                              drawDispListElem(
 +                                      true, true, false,
 +                                      dl->verts, NULL, dl->nr,
 +                                      dl->index, dl->parts, wire_col);
 +                              break;
 +              }
 +      }
 +      
 +      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +      
 +      return false;
 +}
 +
 +static bool drawDispListwire(ListBase *dlbase, const short ob_type, const unsigned char wire_col[3])
 +{
 +      unsigned int dl_mask = 0xffffffff;
 +
 +      /* skip fill-faces for curves & fonts */
 +      if (ELEM(ob_type, OB_FONT, OB_CURVE)) {
 +              dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4));
 +      }
 +
 +      return drawDispListwire_ex(dlbase, dl_mask, wire_col);
 +}
 +
 +static bool index3_nors_incr = true;
 +
 +static void drawDispListsolid(ListBase *lb, Object *ob, const short UNUSED(dflag),
 +                              const unsigned char ob_wire_col[4], const bool use_glsl)
 +{
 +      GPUVertexAttribs gattribs;
 +      
 +      if (lb == NULL) return;
 +
 +      /* track current material, -1 for none (needed for lines) */
 +      short col = -1;
 +      
 +      DispList *dl = lb->first;
 +      while (dl) {
 +              const float *data = dl->verts;
 +              //const float *ndata = dl->nors;
 +
 +              switch (dl->type) {
 +                      case DL_SEGM:
                                if (ob->type == OB_SURF) {
                                        if (col != -1) {
                                                GPU_object_material_unbind();
                                                col = -1;
                                        }
  
 -                                      /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */
 -                                      //glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                                      //glDrawArrays(GL_LINE_LOOP, 0, dl->nr);
 +                                      drawDispListVerts(GWN_PRIM_LINE_STRIP, data, dl->nr, ob_wire_col);
 +                              }
 +                              break;
 +                      case DL_POLY:
 +                              if (ob->type == OB_SURF) {
 +                                      if (col != -1) {
 +                                              GPU_object_material_unbind();
 +                                              col = -1;
 +                                      }
  
 -                                      glBegin(GL_LINE_LOOP);
 -                                      for (int nr = dl->nr; nr; nr--, data += 3)
 -                                              glVertex3fv(data);
 -                                      glEnd();
 +                                      drawDispListVerts(GWN_PRIM_LINE_LOOP, data, dl->nr, ob_wire_col);
                                }
                                break;
                        case DL_SURF:
                                                GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
                                                col = dl->col;
                                        }
 -                                      /* FLAT/SMOOTH shading for surfaces */
 -                                      glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT);
 +                                      const unsigned int verts_len = dl->nr * dl->parts;
  
 -                                      glEnableClientState(GL_NORMAL_ARRAY);
 -                                      glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                                      glNormalPointer(GL_FLOAT, 0, dl->nors);
 -                                      glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index);
 -                                      glDisableClientState(GL_NORMAL_ARRAY);
 -                                      glShadeModel(GL_SMOOTH);
 +                                      drawDispListElem(
 +                                              true, (dl->rt & CU_SMOOTH) != 0, false,
 +                                              dl->verts, dl->nors, verts_len,
 +                                              dl->index, dl->totindex, ob_wire_col);
                                }
                                break;
  
                                        col = dl->col;
                                }
  
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -
 +#if 0
                                /* for polys only one normal needed */
                                if (index3_nors_incr) {
                                        glEnableClientState(GL_NORMAL_ARRAY);
                                }
                                else
                                        glNormal3fv(ndata);
 +#endif
 +                              /* special case, 'nors' is a single value */
 +                              drawDispListElem(
 +                                      false, (dl->rt & CU_SMOOTH) != 0, true,
 +                                      dl->verts, dl->nors, dl->nr,
 +                                      dl->index, dl->parts, ob_wire_col);
  
 -                              glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -
 +#if 0
                                if (index3_nors_incr)
                                        glDisableClientState(GL_NORMAL_ARRAY);
 +#endif
  
                                break;
  
                                        col = dl->col;
                                }
  
 -                              glEnableClientState(GL_NORMAL_ARRAY);
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glNormalPointer(GL_FLOAT, 0, dl->nors);
 -                              glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              glDisableClientState(GL_NORMAL_ARRAY);
 +                              drawDispListElem(
 +                                      true, true, false,
 +                                      dl->verts, dl->nors, dl->nr,
 +                                      dl->index, dl->parts, ob_wire_col);
  
                                break;
                }
                dl = dl->next;
        }
  
 -      glDisableClientState(GL_VERTEX_ARRAY);
        glFrontFace(GL_CCW);
  
        if (col != -1) {
@@@ -5415,7 -4574,7 +5415,7 @@@ static void drawCurveDMWired(Object *ob
  }
  
  /* return true when nothing was drawn */
 -static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt)
 +static bool drawCurveDerivedMesh(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, BaseLegacy *base, const char dt)
  {
        Object *ob = base->object;
        DerivedMesh *dm = ob->derivedFinal;
        glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
        if (dt > OB_WIRE && dm->getNumPolys(dm)) {
 -              bool glsl = draw_glsl_material(scene, ob, v3d, dt);
 -              GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
 +              bool glsl = draw_glsl_material(scene, sl, ob, v3d, dt);
 +              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, glsl, NULL);
  
                if (!glsl)
                        dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
   * Only called by #drawDispList
   * \return true when nothing was drawn
   */
 -static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static bool drawDispList_nobackface(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base,
                                      const char dt, const short dflag, const unsigned char ob_wire_col[4])
  {
        Object *ob = base->object;
                                if (!render_only) {
                                        /* when we have faces, only draw loose-wire */
                                        if (has_faces) {
 -                                              drawDispListwire_ex(lb, (1 << DL_SEGM));
 +                                              drawDispListwire_ex(lb, (1 << DL_SEGM), ob_wire_col);
                                        }
                                        else {
 -                                              drawDispListwire(lb, ob->type);
 +                                              drawDispListwire(lb, ob->type, ob_wire_col);
                                        }
                                }
  
                                        /* pass */
                                }
                                else {
 -                                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
 +                                      if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 1, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
                                                GPU_end_object_materials();
                                        }
                                        else {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
                                                GPU_end_object_materials();
                                        }
                                        if (cu->editnurb && cu->bevobj == NULL && cu->taperobj == NULL && cu->ext1 == 0.0f && cu->ext2 == 0.0f) {
 -                                              cpack(0);
 -                                              drawDispListwire(lb, ob->type);
 +                                              unsigned char col[4] = {0, 0, 0, 0};
 +                                              drawDispListwire(lb, ob->type, col);
                                        }
                                }
                                index3_nors_incr = true;
                        }
                        else {
                                if (!render_only || BKE_displist_has_faces(lb)) {
 -                                      return drawDispListwire(lb, ob->type);
 +                                      return drawDispListwire(lb, ob->type, ob_wire_col);
                                }
                        }
                        break;
  
                                if (dl->nors == NULL) BKE_displist_normals_add(lb);
  
 -                              if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
 +                              if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 1, NULL);
                                        drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
                                        GPU_end_object_materials();
                                }
                                else {
 -                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
                                        drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
                                        GPU_end_object_materials();
                                }
                        }
                        else {
 -                              return drawDispListwire(lb, ob->type);
 +                              return drawDispListwire(lb, ob->type, ob_wire_col);
                        }
                        break;
                case OB_MBALL:
  
                                if (solid) {
  
 -                                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
 +                                      if (draw_glsl_material(scene, sl, ob, v3d, dt)) {
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 1, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
                                                GPU_end_object_materials();
                                        }
                                        else {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
 +                                              GPU_begin_object_materials(v3d, rv3d, scene, sl, ob, 0, NULL);
                                                drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
                                                GPU_end_object_materials();
                                        }
                                }
                                else {
 -                                      return drawDispListwire(lb, ob->type);
 +                                      return drawDispListwire(lb, ob->type, ob_wire_col);
                                }
                        }
                        break;
  
        return false;
  }
 -static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 +static bool drawDispList(Scene *scene, SceneLayer *sl, View3D *v3d, RegionView3D *rv3d, Base *base,
                           const char dt, const short dflag, const unsigned char ob_wire_col[4])
  {
        bool retval;
        ensure_curve_cache(scene, base->object);
  #endif
  
 -      if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
 +      if (drawCurveDerivedMesh(scene, sl, v3d, rv3d, base, dt) == false) {
                retval = false;
        }
        else {
  
                glFrontFace(mode);
  
 -              retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
 +              retval = drawDispList_nobackface(scene, sl, v3d, rv3d, base, dt, dflag, ob_wire_col);
  
                if (mode != GL_CCW) {
                        glFrontFace(GL_CCW);
  }
  
  /* *********** drawing for particles ************* */
 -static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select)
 +/* stride :   offset size in bytes
 + * col[4] :   the color to use when *color is NULL, can be also NULL */
 +static void draw_vertex_array(Gwn_PrimType prim_type, const float *vert, const float *nor, const float *color, int stride, int vert_ct, float col[4])
 +{
 +      Gwn_VertFormat format = {0};
 +      unsigned int pos_id, nor_id, col_id;
 +      pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (nor) nor_id = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +      if (color) col_id = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +
 +      Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format);
 +      GWN_vertbuf_data_alloc(vbo, vert_ct);
 +
 +      if (stride == 0) {
 +              GWN_vertbuf_attr_fill(vbo, pos_id, vert);
 +              if (nor) GWN_vertbuf_attr_fill(vbo, nor_id, nor);
 +              if (color) GWN_vertbuf_attr_fill(vbo, col_id, color);
 +      }
 +      else {
 +              GWN_vertbuf_attr_fill_stride(vbo, pos_id, stride, vert);
 +              if (nor) GWN_vertbuf_attr_fill_stride(vbo, nor_id, stride, nor);
 +              if (color) GWN_vertbuf_attr_fill_stride(vbo, col_id, stride, color);
 +      }
 +
 +      Gwn_Batch *batch = GWN_batch_create(prim_type, vbo, NULL);
 +      if (nor && color) {
 +              Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR);
 +              GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
 +      }
 +      else if (nor) {
 +              Batch_set_builtin_program(batch, GPU_SHADER_SIMPLE_LIGHTING);
 +              GWN_batch_uniform_3f(batch, "light", 0.0f, 0.0f, 1.0f);
 +              if (col) GWN_batch_uniform_4fv(batch, "color", col);
 +      }
 +      else if (color) {
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_SMOOTH_COLOR);
 +      }
 +      else {
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +              if (col) GWN_batch_uniform_4fv(batch, "color", col);
 +      }
 +      GWN_batch_draw(batch);
 +      GWN_batch_discard_all(batch);
 +}
 +
 +static void draw_particle_arrays_new(int draw_as, int ob_dt, int select,
 +                                     const float *vert, const float *nor, const float *color,
 +                                     int totpoint, float col[4])
  {
        /* draw created data arrays */
        switch (draw_as) {
                case PART_DRAW_AXIS:
                case PART_DRAW_CROSS:
 -                      glDrawArrays(GL_LINES, 0, 6 * totpoint);
 +                      draw_vertex_array(GWN_PRIM_LINES, vert, nor, color, 0, 6 * totpoint, col);
                        break;
                case PART_DRAW_LINE:
 -                      glDrawArrays(GL_LINES, 0, 2 * totpoint);
 +                      draw_vertex_array(GWN_PRIM_LINES, vert, nor, color, 0, 2 * totpoint, col);
                        break;
                case PART_DRAW_BB:
                        if (ob_dt <= OB_WIRE || select)
                        else
                                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  
 -                      glDrawArrays(GL_QUADS, 0, 4 * totpoint);
 +                      draw_vertex_array(GWN_PRIM_TRIS, vert, nor, color, 0, 6 * totpoint, col);
                        break;
                default:
 -                      glDrawArrays(GL_POINTS, 0, totpoint);
 +                      draw_vertex_array(GWN_PRIM_POINTS, vert, nor, color, 0, totpoint, col);
                        break;
        }
  }
  static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize,
 -                          float imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd)
 +                          float imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd,
 +                          unsigned int pos)
  {
        float vec[3], vec2[3];
        float *vd = NULL;
                }
                case PART_DRAW_CIRC:
                {
 -                      drawcircball(GL_LINE_LOOP, state->co, pixsize, imat);
 +                      imm_drawcircball(state->co, pixsize, imat, pos);
                        break;
                }
                case PART_DRAW_BB:
                {
                        float xvec[3], yvec[3], zvec[3], bb_center[3];
 -                      if (cd) {
 -                              cd[0] = cd[3] = cd[6] = cd[9] = ma_col[0];
 -                              cd[1] = cd[4] = cd[7] = cd[10] = ma_col[1];
 -                              cd[2] = cd[5] = cd[8] = cd[11] = ma_col[2];
 -                              pdd->cd += 12;
 -                      }
  
                        copy_v3_v3(bb->vec, state->co);
                        copy_v3_v3(bb->vel, state->vel);
  
                        psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
 -                      
 +
 +                      /* First tri */
                        add_v3_v3v3(pdd->vd, bb_center, xvec);
                        add_v3_v3(pdd->vd, yvec); pdd->vd += 3;
  
                        sub_v3_v3v3(pdd->vd, bb_center, xvec);
                        sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
  
 +                      /* Second tri */
 +                      add_v3_v3v3(pdd->vd, bb_center, xvec);
 +                      add_v3_v3(pdd->vd, yvec); pdd->vd += 3;
 +
 +                      sub_v3_v3v3(pdd->vd, bb_center, xvec);
 +                      sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
 +
                        add_v3_v3v3(pdd->vd, bb_center, xvec);
                        sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3;
  
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 -                      copy_v3_v3(pdd->nd, zvec); pdd->nd += 3;
 +                      if (cd) {
 +                              for (int i = 0; i < 6; i++, cd += 3, pdd->cd += 3) {
 +                                      copy_v3_v3(cd, ma_col);
 +                              }
 +                      }
 +                      for (int i = 0; i < 6; i++, pdd->nd += 3) {
 +                              copy_v3_v3(pdd->nd, zvec);
 +                      }
                        break;
                }
        }
  static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
                                 ParticleKey *state, int draw_as,
                                 float imat[4][4], ParticleBillboardData *bb, ParticleDrawData *pdd,
 -                               const float ct, const float pa_size, const float r_tilt, const float pixsize_scale)
 +                               const float ct, const float pa_size, const float r_tilt, const float pixsize_scale,
 +                               unsigned int pos)
  {
        ParticleSettings *part = psys->part;
        float pixsize;
  
        pixsize = ED_view3d_pixel_size(rv3d, state->co) * pixsize_scale;
  
 -      draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
 +      draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd, pos);
  }
  /* unified drawing of all new particle systems draw types except dupli ob & group
   * mostly tries to use vertex arrays for speed
@@@ -5914,11 -5018,10 +5914,11 @@@ static void draw_new_particle_system(Sc
        float cfra;
        float ma_col[3] = {0.0f, 0.0f, 0.0f};
        int a, totpart, totpoint = 0, totve = 0, drawn, draw_as, totchild = 0;
 -      bool select = (ob->flag & SELECT) != 0, create_cdata = false, need_v = false;
 +      bool select = (base->flag & BASE_SELECTED) != 0, create_cdata = false, need_v = false;
        GLint polygonmode[2];
        char numstr[32];
        unsigned char tcol[4] = {0, 0, 0, 255};
 +      unsigned int pos;
  
  /* 1. */
        if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
                copy_v3_v3(ma_col, &ma->r);
        }
  
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              glColor3ubv(tcol);
 -      }
 -
        timestep = psys_get_timestep(&sim);
  
 -      if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) {
 +      if ((ob->flag & OB_FROMGROUP) != 0) {
                float mat[4][4];
                mul_m4_m4m4(mat, ob->obmat, psys->imat);
 -              glMultMatrixf(mat);
 +              gpuMultMatrix(mat);
        }
  
        /* needed for text display */
                                tot_vec_size *= 2;
                                break;
                        case PART_DRAW_BB:
 -                              tot_vec_size *= 4;
 +                              tot_vec_size *= 6;  /* New OGL only understands tris, no choice here. */
                                create_ndata = 1;
                                break;
                }
                        totpoint = pdd->totpoint; /* draw data is up to date */
                }
                else {
 +                      if ((draw_as == PART_DRAW_CIRC) || (part->draw & PART_DRAW_SIZE)) {
 +                              pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
 +                              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +                              imm_cpack(0xFFFFFF);
 +                      }
                        for (a = 0, pa = pars; a < totpart + totchild; a++, pa++) {
                                /* setup per particle individual stuff */
                                if (a < totpart) {
  
                                                draw_particle_data(psys, rv3d,
                                                                   &state, draw_as, imat, &bb, psys->pdd,
 -                                                                 ct, pa_size, r_tilt, pixsize_scale);
 +                                                                 ct, pa_size, r_tilt, pixsize_scale, pos);
  
                                                totpoint++;
                                                drawn = 1;
  
                                                draw_particle_data(psys, rv3d,
                                                                   &state, draw_as, imat, &bb, psys->pdd,
 -                                                                 pa_time, pa_size, r_tilt, pixsize_scale);
 +                                                                 pa_time, pa_size, r_tilt, pixsize_scale, pos);
  
                                                totpoint++;
                                                drawn = 1;
  
                                        if (part->draw & PART_DRAW_SIZE) {
                                                setlinestyle(3);
 -                                              drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
 +                                              imm_drawcircball(state.co, pa_size, imat, pos);
                                                setlinestyle(0);
                                        }
  
                                        }
                                }
                        }
 +                      if ((draw_as == PART_DRAW_CIRC) || (part->draw & PART_DRAW_SIZE)) {
 +                              immUnbindProgram();
 +                      }
                }
        }
  /* 6. */
  
        glGetIntegerv(GL_POLYGON_MODE, polygonmode);
 -      glEnableClientState(GL_VERTEX_ARRAY);
  
        if (draw_as == PART_DRAW_PATH) {
                ParticleCacheKey **cache, *path;
                float *cdata2 = NULL;
  
 -              /* setup gl flags */
 -              if (1) { //ob_dt > OB_WIRE) {
 -                      glEnableClientState(GL_NORMAL_ARRAY);
 -
 -                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                              if (part->draw_col == PART_DRAW_COL_MAT)
 -                                      glEnableClientState(GL_COLOR_ARRAY);
 -                      }
 -
 -                      // XXX test
 -                      GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
 -                      GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
 -              }
 -
                if (totchild && (part->draw & PART_DRAW_PARENT) == 0)
                        totpart = 0;
                else if (psys->pathcache == NULL)
                for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
                        path = cache[a];
                        if (path->segments > 0) {
 -                              glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 -
 -                              if (1) { //ob_dt > OB_WIRE) {
 -                                      glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
 -                                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                                              if (part->draw_col == PART_DRAW_COL_MAT) {
 -                                                      glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
 -                                              }
 -                                      }
 +                              if (((dflag & DRAW_CONSTCOLOR) == 0) && (part->draw_col == PART_DRAW_COL_MAT)) {
 +                                      draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, path->col, sizeof(ParticleCacheKey), path->segments + 1, NULL);
 +                              }
 +                              else {
 +                                      float color[4];
 +                                      rgba_uchar_to_float(color, tcol);
 +                                      draw_vertex_array(GWN_PRIM_LINE_STRIP, path->co, path->vel, NULL, sizeof(ParticleCacheKey), path->segments + 1, color);
                                }
 -
 -                              glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
                        }
                }
  
                if (part->type ==  PART_HAIR) {
                        if (part->draw & PART_DRAW_GUIDE_HAIRS) {
                                DerivedMesh *hair_dm = psys->hair_out_dm;
 -                              
 -                              glDisableClientState(GL_NORMAL_ARRAY);
 -    &