Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Sat, 19 Nov 2016 15:28:39 +0000 (16:28 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Sat, 19 Nov 2016 15:28:39 +0000 (16:28 +0100)
Conflicts:
source/blender/blenloader/intern/versioning_270.c
source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
source/blender/depsgraph/intern/builder/deg_builder_relations.cc
source/blender/editors/space_view3d/drawobject.c

1  2 
intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
release/scripts/startup/bl_ui/properties_paint_common.py
source/blender/blenkernel/intern/library_remap.c
source/blender/blenloader/intern/versioning_270.c
source/blender/blenloader/intern/writefile.c
source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
source/blender/depsgraph/intern/builder/deg_builder_relations.cc
source/blender/depsgraph/intern/builder/deg_builder_relations.h
source/blender/editors/space_view3d/drawobject.c

index 3888cdef70e5cf755ba46ab295f899aa1dacc2e0,a7dff1f79f323dc2e54aa8a664745d4e35f093de..fc08a913f58f91267c07d28690718cff3f066578
@@@ -1094,6 -1094,49 +1094,6 @@@ class CyclesCurveRenderSettings(bpy.typ
          del bpy.types.Scene.cycles_curves
  
  
 -class CyclesCurveSettings(bpy.types.PropertyGroup):
 -    @classmethod
 -    def register(cls):
 -        bpy.types.ParticleSettings.cycles = PointerProperty(
 -                name="Cycles Hair Settings",
 -                description="Cycles hair settings",
 -                type=cls,
 -                )
 -        cls.radius_scale = FloatProperty(
 -                name="Radius Scaling",
 -                description="Multiplier of width properties",
 -                min=0.0, max=1000.0,
 -                default=0.01,
 -                )
 -        cls.root_width = FloatProperty(
 -                name="Root Size",
 -                description="Strand's width at root",
 -                min=0.0, max=1000.0,
 -                default=1.0,
 -                )
 -        cls.tip_width = FloatProperty(
 -                name="Tip Multiplier",
 -                description="Strand's width at tip",
 -                min=0.0, max=1000.0,
 -                default=0.0,
 -                )
 -        cls.shape = FloatProperty(
 -                name="Strand Shape",
 -                description="Strand shape parameter",
 -                min=-1.0, max=1.0,
 -                default=0.0,
 -                )
 -        cls.use_closetip = BoolProperty(
 -                name="Close tip",
 -                description="Set tip radius to zero",
 -                default=True,
 -                )
 -
 -    @classmethod
 -    def unregister(cls):
 -        del bpy.types.ParticleSettings.cycles
 -
 -
  class CyclesDeviceSettings(bpy.types.PropertyGroup):
      @classmethod
      def register(cls):
@@@ -1156,15 -1199,21 +1156,21 @@@ class CyclesPreferences(bpy.types.Addon
          return cuda_devices, opencl_devices
  
  
-     def has_active_device(self):
+     def get_num_gpu_devices(self):
          import _cycles
          device_list = _cycles.available_devices()
+         num = 0
          for device in device_list:
              if device[1] != self.compute_device_type:
                  continue
-             if any(dev.use and dev.id == device[2] for dev in self.devices):
-                 return True
-         return False
+             for dev in self.devices:
+                 if dev.use and dev.id == device[2]:
+                     num += 1
+         return num
+     def has_active_device(self):
+         return self.get_num_gpu_devices() > 0
  
  
      def draw_impl(self, layout, context):
@@@ -1201,6 -1250,7 +1207,6 @@@ def register()
      bpy.utils.register_class(CyclesMeshSettings)
      bpy.utils.register_class(CyclesObjectSettings)
      bpy.utils.register_class(CyclesCurveRenderSettings)
 -    bpy.utils.register_class(CyclesCurveSettings)
      bpy.utils.register_class(CyclesDeviceSettings)
      bpy.utils.register_class(CyclesPreferences)
  
@@@ -1215,5 -1265,6 +1221,5 @@@ def unregister()
      bpy.utils.unregister_class(CyclesObjectSettings)
      bpy.utils.unregister_class(CyclesVisibilitySettings)
      bpy.utils.unregister_class(CyclesCurveRenderSettings)
 -    bpy.utils.unregister_class(CyclesCurveSettings)
      bpy.utils.unregister_class(CyclesDeviceSettings)
      bpy.utils.unregister_class(CyclesPreferences)
index 2d9785b94d08bece25dbaf87c229b2ae54ccab3a,f435af178b555c312686547d171aa3c0934f4d1a..7ed8c5f0a1310d9955c244469b1d253bb2c5cf3e
@@@ -1358,6 -1358,37 +1358,6 @@@ class CyclesTexture_PT_colors(CyclesBut
              layout.template_color_ramp(mapping, "color_ramp", expand=True)
  
  
 -class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
 -    bl_label = "Textures"
 -    bl_context = "particle"
 -    bl_options = {'DEFAULT_CLOSED'}
 -
 -    @classmethod
 -    def poll(cls, context):
 -        psys = context.particle_system
 -        return psys and CyclesButtonsPanel.poll(context)
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        psys = context.particle_system
 -        part = psys.settings
 -
 -        row = layout.row()
 -        row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2)
 -
 -        col = row.column(align=True)
 -        col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
 -        col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
 -        col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
 -
 -        if not part.active_texture:
 -            layout.template_ID(part, "active_texture", new="texture.new")
 -        else:
 -            slot = part.texture_slots[part.active_texture_index]
 -            layout.template_ID(slot, "texture", new="texture.new")
 -
 -
  class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
      bl_label = "Cycles Hair Rendering"
      bl_context = "particle"
@@@ -1506,6 -1537,37 +1506,6 @@@ class CyclesRender_PT_debug(CyclesButto
          col.prop(cscene, "debug_use_opencl_debug", text="Debug")
  
  
 -class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
 -    bl_label = "Cycles Hair Settings"
 -    bl_context = "particle"
 -
 -    @classmethod
 -    def poll(cls, context):
 -        scene = context.scene
 -        ccscene = scene.cycles_curves
 -        psys = context.particle_system
 -        use_curves = ccscene.use_curves and psys
 -        return CyclesButtonsPanel.poll(context) and use_curves and psys.settings.type == 'HAIR'
 -
 -    def draw(self, context):
 -        layout = self.layout
 -
 -        psys = context.particle_settings
 -        cpsys = psys.cycles
 -
 -        row = layout.row()
 -        row.prop(cpsys, "shape", text="Shape")
 -
 -        layout.label(text="Thickness:")
 -        row = layout.row()
 -        row.prop(cpsys, "root_width", text="Root")
 -        row.prop(cpsys, "tip_width", text="Tip")
 -
 -        row = layout.row()
 -        row.prop(cpsys, "radius_scale", text="Scaling")
 -        row.prop(cpsys, "use_closetip", text="Close tip")
 -
 -
  class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
      bl_label = "Simplify"
      bl_context = "scene"
          col = split.column()
          col.label(text="Viewport:")
          col.prop(rd, "simplify_subdivision", text="Subdivision")
 -        col.prop(rd, "simplify_child_particles", text="Child Particles")
  
          col = split.column()
          col.label(text="Render:")
          col.prop(rd, "simplify_subdivision_render", text="Subdivision")
 -        col.prop(rd, "simplify_child_particles_render", text="Child Particles")
  
          col = layout.column()
          col.prop(cscene, "use_camera_cull")
@@@ -1556,7 -1620,7 +1556,7 @@@ def draw_device(self, context)
          sub = row.split(align=True)
          sub.active = show_device_selection(context)
          sub.prop(cscene, "device", text="")
-         row.operator("wm.addon_userpref_show", text="Preferences", icon='PREFERENCES').module = __package__
+         row.operator("wm.addon_userpref_show", text="", icon='PREFERENCES').module = __package__
  
          if engine.with_osl() and use_cpu(context):
              layout.prop(cscene, "shading_system")
index c18aa10e229ff0730d4e65e35fd840e4db9f5a7e,09a3a19cbcee0ed011542817932684ff0d7fffe9..c7bae0d87d645738bf6c96cbe4b5ab6606de8529
@@@ -40,6 -40,8 +40,6 @@@ class UnifiedPaintPanel
                  return toolsettings.image_paint
  
              return None
 -        elif context.particle_edit_object:
 -            return toolsettings.particle_edit
  
          return None
  
@@@ -117,16 -119,14 +117,14 @@@ def brush_texpaint_common(panel, contex
                  col.label("Gradient Colors")
                  col.template_color_ramp(brush, "gradient", expand=True)
  
-                 if brush.image_tool != 'FILL':
+                 if brush.image_tool == 'DRAW':
                      col.label("Background Color")
                      row = col.row(align=True)
                      panel.prop_unified_color(row, context, brush, "secondary_color", text="")
-                 if brush.image_tool == 'DRAW':
                      col.prop(brush, "gradient_stroke_mode", text="Mode")
                      if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
                          col.prop(brush, "grad_spacing")
-                 elif brush.image_tool == 'FILL':
+                 else: # if brush.image_tool == 'FILL':
                      col.prop(brush, "gradient_fill_mode")
              else:
                  row = col.row(align=True)
                      panel.prop_unified_color(row, context, brush, "secondary_color", text="")
                      row.separator()
                      row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
+         else:
+             if brush.image_tool == 'FILL' and not projpaint:
+                 col.prop(brush, "fill_threshold")
  
      elif brush.image_tool == 'SOFTEN':
          col = layout.column(align=True)
index 785fb44c9460f1c4739750434473769273e986b5,62f59832481294d536a1c222a5194d69bc5acc2c..3b757a46e2e79da8ec30a8fc8f656e43ddbd54ee
@@@ -98,6 -98,7 +98,6 @@@
  #include "BKE_node.h"
  #include "BKE_object.h"
  #include "BKE_paint.h"
 -#include "BKE_particle.h"
  #include "BKE_sca.h"
  #include "BKE_speaker.h"
  #include "BKE_sound.h"
@@@ -377,6 -378,18 +377,18 @@@ static void libblock_remap_data_postpro
        }
  }
  
+ static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
+ {
+       /* Verify all nodetree user nodes. */
+       ntreeVerifyNodes(bmain, new_id);
+       /* Update node trees as necessary. */
+       FOREACH_NODETREE(bmain, ntree, id) {
+               /* make an update call for the tree */
+               ntreeUpdateTree(bmain, ntree);
+       } FOREACH_NODETREE_END
+ }
  /**
   * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks).
   *
@@@ -550,6 -563,8 +562,8 @@@ void BKE_libblock_remap_locked
                default:
                        break;
        }
+       /* Node trees may virtually use any kind of data-block... */
+       libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
  
        /* Full rebuild of DAG! */
        DAG_relations_tag_update(bmain);
@@@ -773,6 -788,9 +787,6 @@@ void BKE_libblock_free_ex(Main *bmain, 
                case ID_BR:
                        BKE_brush_free((Brush *)id);
                        break;
 -              case ID_PA:
 -                      BKE_particlesettings_free((ParticleSettings *)id);
 -                      break;
                case ID_WM:
                        if (free_windowmanager_cb)
                                free_windowmanager_cb(NULL, (wmWindowManager *)id);
index 577c278e0e4f7c11c20b232d8223020d36f73c9e,25d78b73d5950caafbd7b1457ea55fb3b6564153..3fa3f037600367b35d084e8fc0cc6c18ca2ee307
@@@ -48,6 -48,7 +48,6 @@@
  #include "DNA_object_types.h"
  #include "DNA_mesh_types.h"
  #include "DNA_modifier_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_linestyle_types.h"
  #include "DNA_actuator_types.h"
  #include "DNA_view3d_types.h"
@@@ -444,6 -445,22 +444,6 @@@ void blo_do_versions_270(FileData *fd, 
                }
        }
  
 -      if (!MAIN_VERSION_ATLEAST(main, 271, 6)) {
 -              Object *ob;
 -              for (ob = main->object.first; ob; ob = ob->id.next) {
 -                      ModifierData *md;
 -
 -                      for (md = ob->modifiers.first; md; md = md->next) {
 -                              if (md->type == eModifierType_ParticleSystem) {
 -                                      ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
 -                                      if (pmd->psys && pmd->psys->clmd) {
 -                                              pmd->psys->clmd->sim_parms->vel_damping = 1.0f;
 -                                      }
 -                              }
 -                      }
 -              }
 -      }
 -
        if (!MAIN_VERSION_ATLEAST(main, 272, 0)) {
                if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) {
                        Scene *scene;
                }
        }
        
 -      if (!MAIN_VERSION_ATLEAST(main, 273, 3)) {
 -              ParticleSettings *part;
 -              for (part = main->particle.first; part; part = part->id.next) {
 -                      if (part->clumpcurve)
 -                              part->child_flag |= PART_CHILD_USE_CLUMP_CURVE;
 -                      if (part->roughcurve)
 -                              part->child_flag |= PART_CHILD_USE_ROUGH_CURVE;
 -              }
 -      }
 -
        if (!MAIN_VERSION_ATLEAST(main, 273, 6)) {
                if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "bending_damping")) {
                        Object *ob;
                                                ClothModifierData *clmd = (ClothModifierData *)md;
                                                clmd->sim_parms->bending_damping = 0.5f;
                                        }
 -                                      else if (md->type == eModifierType_ParticleSystem) {
 -                                              ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
 -                                              if (pmd->psys->clmd) {
 -                                                      pmd->psys->clmd->sim_parms->bending_damping = 0.5f;
 -                                              }
 -                                      }
 -                              }
 -                      }
 -              }
 -
 -              if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "float", "clump_noise_size")) {
 -                      ParticleSettings *part;
 -                      for (part = main->particle.first; part; part = part->id.next) {
 -                              part->clump_noise_size = 1.0f;
 -                      }
 -              }
 -
 -              if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "int", "kink_extra_steps")) {
 -                      ParticleSettings *part;
 -                      for (part = main->particle.first; part; part = part->id.next) {
 -                              part->kink_extra_steps = 4;
 -                      }
 -              }
 -
 -              if (!DNA_struct_elem_find(fd->filesdna, "MTex", "float", "kinkampfac")) {
 -                      ParticleSettings *part;
 -                      for (part = main->particle.first; part; part = part->id.next) {
 -                              int a;
 -                              for (a = 0; a < MAX_MTEX; a++) {
 -                                      MTex *mtex = part->mtex[a];
 -                                      if (mtex) {
 -                                              mtex->kinkampfac = 1.0f;
 -                                      }
                                }
                        }
                }
        }
  
        if (!MAIN_VERSION_ATLEAST(main, 274, 1)) {
 -              /* particle systems need to be forced to redistribute for jitter mode fix */
 -              {
 -                      Object *ob;
 -                      ParticleSystem *psys;
 -                      for (ob = main->object.first; ob; ob = ob->id.next) {
 -                              for (psys = ob->particlesystem.first; psys; psys = psys->next) {
 -                                      if ((psys->pointcache->flag & PTCACHE_BAKED) == 0) {
 -                                              psys->recalc |= PSYS_RECALC_RESET;
 -                                      }
 -                              }
 -                      }
 -              }
 -
                /* hysteresis setted to 10% but not actived */
                if (!DNA_struct_elem_find(fd->filesdna, "LodLevel", "int", "obhysteresis")) {
                        Object *ob;
        }
  
        if (!MAIN_VERSION_ATLEAST(main, 277, 1)) {
 -              for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
 -                      ParticleEditSettings *pset = &scene->toolsettings->particle;
 -                      for (int a = 0; a < PE_TOT_BRUSH; a++) {
 -                              if (pset->brush[a].strength > 1.0f) {
 -                                      pset->brush[a].strength *= 0.01f;
 -                              }
 -                      }
 -              }
 -
                for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
                        for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
                                for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
                                                ClothModifierData *clmd = (ClothModifierData *)md;
                                                clmd->sim_parms->time_scale = 1.0f;
                                        }
 -                                      else if (md->type == eModifierType_ParticleSystem) {
 -                                              ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
 -                                              if (pmd->psys->clmd) {
 -                                                      pmd->psys->clmd->sim_parms->time_scale = 1.0f;
 -                                              }
 -                                      }
                                }
                        }
                }
        }
  
        if (!MAIN_VERSION_ATLEAST(main, 278, 3)) {
 -              for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) {
 -                      if (scene->toolsettings != NULL) {
 -                              ToolSettings *ts = scene->toolsettings;
 -                              ParticleEditSettings *pset = &ts->particle;
 -                              for (int a = 0; a < PE_TOT_BRUSH; a++) {
 -                                      if (pset->brush[a].count == 0) {
 -                                              pset->brush[a].count = 10;
 -                                      }
 -                              }
 -                      }
 -              }
 -
                if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) {
                        Object *ob;
                        for (ob = main->object.first; ob; ob = ob->id.next) {
                }
        }
  
+       if (!MAIN_VERSION_ATLEAST(main, 278, 4)) {
+               const float sqrt_3 = (float)M_SQRT3;
+               for (Brush *br = main->brush.first; br; br = br->id.next) {
+                       br->fill_threshold /= sqrt_3;
+               }
+       }
++
 +      {
 +              if (!DNA_struct_elem_find(fd->filesdna, "View3DDebug", "char", "background")) {
 +                      bScreen *screen;
 +
 +                      for (screen = main->screen.first; screen; screen = screen->id.next) {
 +                              ScrArea *sa;
 +                              for (sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      SpaceLink *sl;
 +
 +                                      for (sl = sa->spacedata.first; sl; sl = sl->next) {
 +                                              switch (sl->spacetype) {
 +                                                      case SPACE_VIEW3D:
 +                                                      {
 +                                                              View3D *v3d = (View3D *)sl;
 +                                                              v3d->debug.background = V3D_DEBUG_BACKGROUND_NONE;
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
  }
index 03436f4658ace15261a93c6bab638a7cbc2045ea,ad1999c0bc7927dc6edbf22e56e58d3d74d5eb78..d8097f1a50adb9e35eb359d32a71c2492b241b44
  #include "DNA_object_types.h"
  #include "DNA_object_force.h"
  #include "DNA_packedFile_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_property_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_scene_types.h"
  #include "BKE_subsurf.h"
  #include "BKE_modifier.h"
  #include "BKE_fcurve.h"
 -#include "BKE_pointcache.h"
  #include "BKE_mesh.h"
  
  #ifdef USE_NODE_COMPAT_CUSTOMNODES
@@@ -912,20 -914,22 +912,22 @@@ static void write_curvemapping(WriteDat
  static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock)
  {
  #ifdef USE_NODE_COMPAT_CUSTOMNODES
-       /* forward compatibility code, so older blenders still open */
-       sock->stack_type = 1;
-       if (node->type == NODE_GROUP) {
-               bNodeTree *ngroup = (bNodeTree *)node->id;
-               if (ngroup) {
-                       /* for node groups: look up the deprecated groupsock pointer */
-                       sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
-                       BLI_assert(sock->groupsock != NULL);
-                       /* node group sockets now use the generic identifier string to verify group nodes,
-                        * old blender uses the own_index.
-                        */
-                       sock->own_index = sock->groupsock->own_index;
+       /* forward compatibility code, so older blenders still open (not for undo) */
+       if (wd->current == NULL) {
+               sock->stack_type = 1;
+               if (node->type == NODE_GROUP) {
+                       bNodeTree *ngroup = (bNodeTree *)node->id;
+                       if (ngroup) {
+                               /* for node groups: look up the deprecated groupsock pointer */
+                               sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier);
+                               BLI_assert(sock->groupsock != NULL);
+                               /* node group sockets now use the generic identifier string to verify group nodes,
+                                * old blender uses the own_index.
+                                */
+                               sock->own_index = sock->groupsock->own_index;
+                       }
                }
        }
  #endif
@@@ -1184,6 -1188,210 +1186,6 @@@ static void write_userdef(WriteData *wd
        }
  }
  
 -static void write_boid_state(WriteData *wd, BoidState *state)
 -{
 -      BoidRule *rule = state->rules.first;
 -
 -      writestruct(wd, DATA, BoidState, 1, state);
 -
 -      for (; rule; rule = rule->next) {
 -              switch (rule->type) {
 -                      case eBoidRuleType_Goal:
 -                      case eBoidRuleType_Avoid:
 -                              writestruct(wd, DATA, BoidRuleGoalAvoid, 1, rule);
 -                              break;
 -                      case eBoidRuleType_AvoidCollision:
 -                              writestruct(wd, DATA, BoidRuleAvoidCollision, 1, rule);
 -                              break;
 -                      case eBoidRuleType_FollowLeader:
 -                              writestruct(wd, DATA, BoidRuleFollowLeader, 1, rule);
 -                              break;
 -                      case eBoidRuleType_AverageSpeed:
 -                              writestruct(wd, DATA, BoidRuleAverageSpeed, 1, rule);
 -                              break;
 -                      case eBoidRuleType_Fight:
 -                              writestruct(wd, DATA, BoidRuleFight, 1, rule);
 -                              break;
 -                      default:
 -                              writestruct(wd, DATA, BoidRule, 1, rule);
 -                              break;
 -              }
 -      }
 -#if 0
 -      BoidCondition *cond = state->conditions.first;
 -      for (; cond; cond = cond->next) {
 -              writestruct(wd, DATA, BoidCondition, 1, cond);
 -      }
 -#endif
 -}
 -
 -/* update this also to readfile.c */
 -static const char *ptcache_data_struct[] = {
 -      "", // BPHYS_DATA_INDEX
 -      "", // BPHYS_DATA_LOCATION
 -      "", // BPHYS_DATA_VELOCITY
 -      "", // BPHYS_DATA_ROTATION
 -      "", // BPHYS_DATA_AVELOCITY / BPHYS_DATA_XCONST */
 -      "", // BPHYS_DATA_SIZE:
 -      "", // BPHYS_DATA_TIMES:
 -      "BoidData" // case BPHYS_DATA_BOIDS:
 -};
 -static const char *ptcache_extra_struct[] = {
 -      "",
 -      "ParticleSpring"
 -};
 -static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
 -{
 -      PointCache *cache = ptcaches->first;
 -      int i;
 -
 -      for (; cache; cache = cache->next) {
 -              writestruct(wd, DATA, PointCache, 1, cache);
 -
 -              if ((cache->flag & PTCACHE_DISK_CACHE) == 0) {
 -                      PTCacheMem *pm = cache->mem_cache.first;
 -
 -                      for (; pm; pm = pm->next) {
 -                              PTCacheExtra *extra = pm->extradata.first;
 -
 -                              writestruct(wd, DATA, PTCacheMem, 1, pm);
 -
 -                              for (i = 0; i < BPHYS_TOT_DATA; i++) {
 -                                      if (pm->data[i] && pm->data_types & (1 << i)) {
 -                                              if (ptcache_data_struct[i][0] == '\0') {
 -                                                      writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]);
 -                                              }
 -                                              else {
 -                                                      writestruct_id(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]);
 -                                              }
 -                                      }
 -                              }
 -
 -                              for (; extra; extra = extra->next) {
 -                                      if (ptcache_extra_struct[extra->type][0] == '\0') {
 -                                              continue;
 -                                      }
 -                                      writestruct(wd, DATA, PTCacheExtra, 1, extra);
 -                                      writestruct_id(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data);
 -                              }
 -                      }
 -              }
 -      }
 -}
 -static void write_particlesettings(WriteData *wd, ListBase *idbase)
 -{
 -      ParticleSettings *part;
 -      ParticleDupliWeight *dw;
 -      GroupObject *go;
 -      int a;
 -
 -      part = idbase->first;
 -      while (part) {
 -              if (part->id.us > 0 || wd->current) {
 -                      /* write LibData */
 -                      writestruct(wd, ID_PA, ParticleSettings, 1, part);
 -                      write_iddata(wd, &part->id);
 -
 -                      if (part->adt) {
 -                              write_animdata(wd, part->adt);
 -                      }
 -                      writestruct(wd, DATA, PartDeflect, 1, part->pd);
 -                      writestruct(wd, DATA, PartDeflect, 1, part->pd2);
 -                      writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights);
 -
 -                      if (part->clumpcurve) {
 -                              write_curvemapping(wd, part->clumpcurve);
 -                      }
 -                      if (part->roughcurve) {
 -                              write_curvemapping(wd, part->roughcurve);
 -                      }
 -
 -                      dw = part->dupliweights.first;
 -                      for (; dw; dw = dw->next) {
 -                              /* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
 -                              if (dw->ob != NULL) {
 -                                      dw->index = 0;
 -                                      if (part->dup_group) { /* can be NULL if lining fails or set to None */
 -                                              for (go = part->dup_group->gobject.first; go && go->ob != dw->ob; go = go->next, dw->index++);
 -                                      }
 -                              }
 -                              writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
 -                      }
 -
 -                      if (part->boids && part->phystype == PART_PHYS_BOIDS) {
 -                              BoidState *state = part->boids->states.first;
 -
 -                              writestruct(wd, DATA, BoidSettings, 1, part->boids);
 -
 -                              for (; state; state = state->next) {
 -                                      write_boid_state(wd, state);
 -                              }
 -                      }
 -                      if (part->fluid && part->phystype == PART_PHYS_FLUID) {
 -                              writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid);
 -                      }
 -
 -                      for (a = 0; a < MAX_MTEX; a++) {
 -                              if (part->mtex[a]) {
 -                                      writestruct(wd, DATA, MTex, 1, part->mtex[a]);
 -                              }
 -                      }
 -              }
 -              part = part->id.next;
 -      }
 -}
 -static void write_particlesystems(WriteData *wd, ListBase *particles)
 -{
 -      ParticleSystem *psys = particles->first;
 -      ParticleTarget *pt;
 -      int a;
 -
 -      for (; psys; psys = psys->next) {
 -              writestruct(wd, DATA, ParticleSystem, 1, psys);
 -
 -              if (psys->particles) {
 -                      writestruct(wd, DATA, ParticleData, psys->totpart, psys->particles);
 -
 -                      if (psys->particles->hair) {
 -                              ParticleData *pa = psys->particles;
 -
 -                              for (a = 0; a < psys->totpart; a++, pa++) {
 -                                      writestruct(wd, DATA, HairKey, pa->totkey, pa->hair);
 -                              }
 -                      }
 -
 -                      if (psys->particles->boid &&
 -                          (psys->part->phystype == PART_PHYS_BOIDS))
 -                      {
 -                              writestruct(wd, DATA, BoidParticle, psys->totpart, psys->particles->boid);
 -                      }
 -
 -                      if (psys->part->fluid &&
 -                          (psys->part->phystype == PART_PHYS_FLUID) &&
 -                          (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS))
 -                      {
 -                              writestruct(wd, DATA, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs);
 -                      }
 -              }
 -              pt = psys->targets.first;
 -              for (; pt; pt = pt->next) {
 -                      writestruct(wd, DATA, ParticleTarget, 1, pt);
 -              }
 -
 -              if (psys->child) {
 -                      writestruct(wd, DATA, ChildParticle, psys->totchild, psys->child);
 -              }
 -
 -              if (psys->clmd) {
 -                      writestruct(wd, DATA, ClothModifierData, 1, psys->clmd);
 -                      writestruct(wd, DATA, ClothSimSettings, 1, psys->clmd->sim_parms);
 -                      writestruct(wd, DATA, ClothCollSettings, 1, psys->clmd->coll_parms);
 -              }
 -
 -              write_pointcaches(wd, &psys->ptcaches);
 -      }
 -}
 -
  static void write_properties(WriteData *wd, ListBase *lb)
  {
        bProperty *prop;
@@@ -1507,18 -1715,33 +1509,18 @@@ static void write_modifiers(WriteData *
                        writestruct(wd, DATA, ClothSimSettings, 1, clmd->sim_parms);
                        writestruct(wd, DATA, ClothCollSettings, 1, clmd->coll_parms);
                        writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights);
 -                      write_pointcaches(wd, &clmd->ptcaches);
                }
                else if (md->type == eModifierType_Smoke) {
                        SmokeModifierData *smd = (SmokeModifierData *)md;
  
                        if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
 -                              if (smd->domain) {
 -                                      write_pointcaches(wd, &(smd->domain->ptcaches[0]));
 -
 -                                      /* create fake pointcache so that old blender versions can read it */
 -                                      smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]);
 -                                      smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE;
 -                                      smd->domain->point_cache[1]->step = 1;
 +                              writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
  
 -                                      write_pointcaches(wd, &(smd->domain->ptcaches[1]));
 +                              if (smd->domain) {
  
                                        if (smd->domain->coba) {
                                                writestruct(wd, DATA, ColorBand, 1, smd->domain->coba);
                                        }
 -                              }
 -
 -                              writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain);
 -
 -                              if (smd->domain) {
 -                                      /* cleanup the fake pointcache */
 -                                      BKE_ptcache_free_list(&smd->domain->ptcaches[1]);
 -                                      smd->domain->point_cache[1] = NULL;
  
                                        writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights);
                                }
                                }
                                /* write caches and effector weights */
                                for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) {
 -                                      write_pointcaches(wd, &(surface->ptcaches));
 -
                                        writestruct(wd, DATA, EffectorWeights, 1, surface->effector_weights);
                                }
                        }
@@@ -1647,6 -1872,7 +1649,6 @@@ static void write_objects(WriteData *wd
                        writestruct(wd, DATA, PartDeflect, 1, ob->pd);
                        writestruct(wd, DATA, SoftBody, 1, ob->soft);
                        if (ob->soft) {
 -                              write_pointcaches(wd, &ob->soft->ptcaches);
                                writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights);
                        }
                        writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft);
                                writestruct(wd, DATA, ImageUser, 1, ob->iuser);
                        }
  
 -                      write_particlesystems(wd, &ob->particlesystem);
                        write_modifiers(wd, &ob->modifiers);
  
                        writelist(wd, DATA, LinkData, &ob->pc_ids);
@@@ -2609,6 -2836,7 +2611,6 @@@ static void write_scenes(WriteData *wd
                if (sce->rigidbody_world) {
                        writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world);
                        writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights);
 -                      write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
                }
  
                write_previews(wd, sce->preview);
@@@ -3864,6 -4092,7 +3866,6 @@@ static bool write_file_handle
        write_materials(wd, &mainvar->mat);
        write_textures(wd, &mainvar->tex);
        write_meshes(wd, &mainvar->mesh);
 -      write_particlesettings(wd, &mainvar->particle);
        write_nodetrees(wd, &mainvar->nodetree);
        write_brushes(wd, &mainvar->brush);
        write_palettes(wd, &mainvar->palettes);
index 1abce2e6b18ad344a2528c0f0f87bbea423fbcf9,4de82dd63e4a0ad2b5639bd31af2834581cf62cc..3cf510eef2597839918c8dfa60a44356b75eaae6
@@@ -55,9 -55,12 +55,11 @@@ extern "C" 
  #include "DNA_key_types.h"
  #include "DNA_lamp_types.h"
  #include "DNA_material_types.h"
+ #include "DNA_mask_types.h"
  #include "DNA_mesh_types.h"
  #include "DNA_meta_types.h"
+ #include "DNA_movieclip_types.h"
  #include "DNA_node_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_object_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_scene_types.h"
@@@ -84,6 -87,7 +86,6 @@@
  #include "BKE_modifier.h"
  #include "BKE_node.h"
  #include "BKE_object.h"
 -#include "BKE_particle.h"
  #include "BKE_rigidbody.h"
  #include "BKE_sound.h"
  #include "BKE_texture.h"
  #include "intern/nodes/deg_node_operation.h"
  #include "intern/depsgraph_types.h"
  #include "intern/depsgraph_intern.h"
+ #include "util/deg_util_foreach.h"
  
  namespace DEG {
  
@@@ -315,92 -320,6 +318,6 @@@ OperationDepsNode *DepsgraphNodeBuilder
  
  /* **** Build functions for entity nodes **** */
  
- void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
- {
-       /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
-        * created or not. This flag is being set in add_id_node(), so functions
-        * shouldn't bother with setting it, they only might query this flag when
-        * needed.
-        */
-       BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
-       /* XXX nested node trees are not included in tag-clearing above,
-        * so we need to do this manually.
-        */
-       FOREACH_NODETREE(bmain, nodetree, id) {
-               if (id != (ID *)nodetree)
-                       nodetree->id.tag &= ~LIB_TAG_DOIT;
-       } FOREACH_NODETREE_END
-       /* scene ID block */
-       add_id_node(&scene->id);
-       /* timesource */
-       add_time_source(NULL);
-       /* build subgraph for set, and link this in... */
-       // XXX: depending on how this goes, that scene itself could probably store its
-       //      own little partial depsgraph?
-       if (scene->set) {
-               build_scene(bmain, scene->set);
-       }
-       /* scene objects */
-       for (Base *base = (Base *)scene->base.first; base; base = base->next) {
-               Object *ob = base->object;
-               /* object itself */
-               build_object(scene, base, ob);
-               /* object that this is a proxy for */
-               // XXX: the way that proxies work needs to be completely reviewed!
-               if (ob->proxy) {
-                       ob->proxy->proxy_from = ob;
-                       build_object(scene, base, ob->proxy);
-               }
-               /* Object dupligroup. */
-               if (ob->dup_group) {
-                       build_group(scene, base, ob->dup_group);
-               }
-       }
-       /* rigidbody */
-       if (scene->rigidbody_world) {
-               build_rigidbody(scene);
-       }
-       /* scene's animation and drivers */
-       if (scene->adt) {
-               build_animdata(&scene->id);
-       }
-       /* world */
-       if (scene->world) {
-               build_world(scene->world);
-       }
-       /* compo nodes */
-       if (scene->nodetree) {
-               build_compositor(scene);
-       }
-       /* sequencer */
-       // XXX...
-       /* grease pencil */
-       if (scene->gpd) {
-               build_gpencil(scene->gpd);
-       }
-       /* cache files */
-       for (CacheFile *cachefile = static_cast<CacheFile *>(bmain->cachefiles.first);
-            cachefile;
-            cachefile = static_cast<CacheFile *>(cachefile->id.next))
-       {
-               build_cachefile(cachefile);
-       }
- }
  void DepsgraphNodeBuilder::build_group(Scene *scene,
                                         Base *base,
                                         Group *group)
        }
        group_id->tag |= LIB_TAG_DOIT;
  
-       for (GroupObject *go = (GroupObject *)group->gobject.first;
-            go != NULL;
-            go = go->next)
-       {
+       LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
                build_object(scene, base, go->ob);
        }
  }
@@@ -431,10 -347,7 +345,7 @@@ SubgraphDepsNode *DepsgraphNodeBuilder:
        DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
  
        /* add group objects */
-       for (GroupObject *go = (GroupObject *)group->gobject.first;
-            go != NULL;
-            go = go->next)
-       {
+       LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
                /*Object *ob = go->ob;*/
  
                /* Each "group object" is effectively a separate instance of the
@@@ -552,6 -465,11 +463,6 @@@ void DepsgraphNodeBuilder::build_object
         */
        build_animdata(&ob->id);
  
 -      /* particle systems */
 -      if (ob->particlesystem.first) {
 -              build_particles(scene, ob);
 -      }
 -
        /* grease pencil */
        if (ob->gpd) {
                build_gpencil(ob->gpd);
@@@ -619,14 -537,6 +530,6 @@@ void DepsgraphNodeBuilder::build_object
                           DEG_OPCODE_TRANSFORM_CONSTRAINTS);
  }
  
- void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
- {
-       /* create node for constraint stack */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                          DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
-                          DEG_OPCODE_BONE_CONSTRAINTS);
- }
  /**
   * Build graph nodes for AnimData block
   * \param id: ID-Block which hosts the AnimData
@@@ -654,7 -564,7 +557,7 @@@ void DepsgraphNodeBuilder::build_animda
                }
  
                /* drivers */
-               for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+               LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
                        /* create driver */
                        build_driver(id, fcu);
                }
@@@ -767,7 -677,7 +670,7 @@@ void DepsgraphNodeBuilder::build_rigidb
  
        /* objects - simulation participants */
        if (rbw->group) {
-               for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+               LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
                        Object *ob = go->ob;
  
                        if (!ob || (ob->type != OB_MESH))
        }
  }
  
- /* IK Solver Eval Steps */
- void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
- {
-       bKinematicConstraint *data = (bKinematicConstraint *)con->data;
-       /* Find the chain's root. */
-       bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
-       if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
-                              DEG_OPCODE_POSE_IK_SOLVER))
-       {
-               return;
-       }
-       /* Operation node for evaluating/running IK Solver. */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
-                          DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
-                          DEG_OPCODE_POSE_IK_SOLVER);
- }
- /* Spline IK Eval Steps */
- void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
- {
-       bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
-       /* Find the chain's root. */
-       bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
-       /* Operation node for evaluating/running Spline IK Solver.
-        * Store the "root bone" of this chain in the solver, so it knows where to start.
-        */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
-                          DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
-                          DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
- }
- /* Pose/Armature Bones Graph */
- void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
 -void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
--{
-       bArmature *arm = (bArmature *)ob->data;
-       /* animation and/or drivers linking posebones to base-armature used to define them
-        * NOTE: AnimData here is really used to control animated deform properties,
-        *       which ideally should be able to be unique across different instances.
-        *       Eventually, we need some type of proxy/isolation mechanism in-between here
-        *       to ensure that we can use same rig multiple times in same scene...
-        */
-       build_animdata(&arm->id);
-       /* Rebuild pose if not up to date. */
-       if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
-               BKE_pose_rebuild_ex(ob, arm, false);
-               /* XXX: Without this animation gets lost in certain circumstances
-                * after loading file. Need to investigate further since it does
-                * not happen with simple scenes..
-                */
-               if (ob->adt) {
-                       ob->adt->recalc |= ADT_RECALC_ANIM;
-               }
-       }
-       /* speed optimization for animation lookups */
-       if (ob->pose) {
-               BKE_pose_channels_hash_make(ob->pose);
-               if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
-                       BKE_pose_update_constraint_flags(ob->pose);
-               }
-       }
-       /* Make sure pose is up-to-date with armature updates. */
-       add_operation_node(&arm->id,
-                          DEPSNODE_TYPE_PARAMETERS,
-                          DEPSOP_TYPE_EXEC,
-                          NULL,
-                          DEG_OPCODE_PLACEHOLDER,
-                          "Armature Eval");
--      /**
-        * Pose Rig Graph
-        * ==============
-        *
-        * Pose Component:
-        * - Mainly used for referencing Bone components.
-        * - This is where the evaluation operations for init/exec/cleanup
-        *   (ik) solvers live, and are later hooked up (so that they can be
-        *   interleaved during runtime) with bone-operations they depend on/affect.
-        * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
-        *   steps of pose eval process. ALL bone operations must be performed
-        *   between these two...
 -       * Particle Systems Nodes
 -       * ======================
--       *
-        * Bone Component:
-        * - Used for representing each bone within the rig
-        * - Acts to encapsulate the evaluation operations (base matrix + parenting,
-        *   and constraint stack) so that they can be easily found.
-        * - Everything else which depends on bone-results hook up to the component only
-        *   so that we can redirect those to point at either the the post-IK/
-        *   post-constraint/post-matrix steps, as needed.
 -       * There are two types of nodes associated with representing
 -       * particle systems:
 -       *  1) Component (EVAL_PARTICLES) - This is the particle-system
 -       *     evaluation context for an object. It acts as the container
 -       *     for all the nodes associated with a particular set of particle
 -       *     systems.
 -       *  2) Particle System Eval Operation - This operation node acts as a
 -       *     blackbox evaluation step for one particle system referenced by
 -       *     the particle systems stack. All dependencies link to this operation.
--       */
-       /* pose eval context */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
-       /* bones */
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               /* node for bone eval */
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
-                                  DEG_OPCODE_BONE_LOCAL);
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
-                                  DEG_OPCODE_BONE_POSE_PARENT);
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
-                                  DEG_OPCODE_BONE_READY);
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
-                                  DEG_OPCODE_BONE_DONE);
-               /* constraints */
-               if (pchan->constraints.first != NULL) {
-                       build_pose_constraints(ob, pchan);
-               }
-               /**
-                * IK Solvers...
-                *
-                * - These require separate processing steps are pose-level
-                *   to be executed between chains of bones (i.e. once the
-                *   base transforms of a bunch of bones is done)
-                *
-                * Unsolved Issues:
-                * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
-                * - Animated chain-lengths are a problem...
-                */
-               for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
-                       switch (con->type) {
-                               case CONSTRAINT_TYPE_KINEMATIC:
-                                       build_ik_pose(scene, ob, pchan, con);
-                                       break;
-                               case CONSTRAINT_TYPE_SPLINEIK:
-                                       build_splineik_pose(scene, ob, pchan, con);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-       }
- }
- void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
- {
-       ID *obdata = (ID *)ob->data;
-       build_animdata(obdata);
-       BLI_assert(ob->pose != NULL);
-       /* speed optimization for animation lookups */
-       BKE_pose_channels_hash_make(ob->pose);
-       if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
-               BKE_pose_update_constraint_flags(ob->pose);
-       }
--
-       add_operation_node(&ob->id,
-                          DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_INIT,
-                          function_bind(BKE_pose_eval_proxy_copy, _1, ob),
-                          DEG_OPCODE_POSE_INIT);
 -      /* component for all particle systems */
 -      ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
--
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
-            pchan != NULL;
-            pchan = pchan->next)
-       {
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_INIT, NULL,
-                                  DEG_OPCODE_BONE_LOCAL);
 -      /* particle systems */
 -      LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
 -              ParticleSettings *part = psys->part;
--
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_EXEC, NULL,
-                                  DEG_OPCODE_BONE_READY);
 -              /* particle settings */
 -              // XXX: what if this is used more than once!
 -              build_animdata(&part->id);
--
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_POST, NULL,
-                                  DEG_OPCODE_BONE_DONE);
 -              /* this particle system */
 -              // TODO: for now, this will just be a placeholder "ubereval" node
 -              add_operation_node(psys_comp,
 -                                 DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval,
 -                                                                 _1,
 -                                                                 scene,
 -                                                                 ob,
 -                                                                 psys),
 -                                 DEG_OPCODE_PSYS_EVAL,
 -                                 psys->name);
--      }
--
-       add_operation_node(&ob->id,
-                          DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_POST,
-                          NULL,
-                          DEG_OPCODE_POSE_DONE);
 -      /* pointcache */
 -      // TODO...
--}
--
  /* Shapekeys */
  void DepsgraphNodeBuilder::build_shapekeys(Key *key)
  {
@@@ -1033,33 -786,26 +735,26 @@@ void DepsgraphNodeBuilder::build_obdata
        // TODO: "Done" operation
  
        /* Modifiers */
-       if (ob->modifiers.first) {
-               for (ModifierData *md = (ModifierData *)ob->modifiers.first;
-                    md != NULL;
-                    md = md->next)
-               {
-                       add_operation_node(&ob->id,
-                                          DEPSNODE_TYPE_GEOMETRY,
-                                          DEPSOP_TYPE_EXEC,
-                                          function_bind(BKE_object_eval_modifier,
-                                                        _1,
-                                                        scene,
-                                                        ob,
-                                                        md),
-                                          DEG_OPCODE_GEOMETRY_MODIFIER,
-                                          md->name);
-               }
+       LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
+               add_operation_node(&ob->id,
+                                  DEPSNODE_TYPE_GEOMETRY,
+                                  DEPSOP_TYPE_EXEC,
+                                  function_bind(BKE_object_eval_modifier,
+                                                _1,
+                                                scene,
+                                                ob,
+                                                md),
+                                  DEG_OPCODE_GEOMETRY_MODIFIER,
+                                  md->name);
        }
  
        /* materials */
-       if (ob->totcol) {
-               for (int a = 1; a <= ob->totcol; a++) {
-                       Material *ma = give_current_material(ob, a);
-                       if (ma != NULL) {
-                               // XXX?!
-                               ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
-                               build_material(geom_node, ma);
-                       }
+       for (int a = 1; a <= ob->totcol; a++) {
+               Material *ma = give_current_material(ob, a);
+               if (ma != NULL) {
+                       // XXX?!
+                       ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+                       build_material(geom_node, ma);
                }
        }
  
                                build_object(scene, NULL, cu->bevobj);
                        }
                        if (cu->taperobj != NULL) {
-                               build_object(scene, NULL, cu->bevobj);
+                               build_object(scene, NULL, cu->taperobj);
                        }
                        if (ob->type == OB_FONT && cu->textoncurve != NULL) {
                                build_object(scene, NULL, cu->textoncurve);
@@@ -1253,7 -999,7 +948,7 @@@ void DepsgraphNodeBuilder::build_nodetr
                           DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
  
        /* nodetree's nodes... */
-       for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+       LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
                ID *id = bnode->id;
                if (id != NULL) {
                        short id_type = GS(id->name);
@@@ -1384,7 -1130,6 +1079,6 @@@ void DepsgraphNodeBuilder::build_cachef
        ID *cache_file_id = &cache_file->id;
  
        add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE);
        add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE,
                           DEPSOP_TYPE_EXEC, NULL,
                           DEG_OPCODE_PLACEHOLDER, "Cache File Update");
        build_animdata(cache_file_id);
  }
  
+ void DepsgraphNodeBuilder::build_mask(Mask *mask)
+ {
+       ID *mask_id = &mask->id;
+       add_id_node(mask_id);
+       build_animdata(mask_id);
+ }
+ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) {
+       ID *clip_id = &clip->id;
+       add_id_node(clip_id);
+       build_animdata(clip_id);
+ }
  }  // namespace DEG
index bd62833846172d4ebaa5745b93936687e01566df,dadb7f8917fe8ff3bf330103fe1345532d4e3ff4..dca1da0979b56216f3d7af225b72bc4cb5378e1c
@@@ -55,9 -55,12 +55,11 @@@ extern "C" 
  #include "DNA_key_types.h"
  #include "DNA_lamp_types.h"
  #include "DNA_material_types.h"
+ #include "DNA_mask_types.h"
  #include "DNA_mesh_types.h"
  #include "DNA_meta_types.h"
+ #include "DNA_movieclip_types.h"
  #include "DNA_node_types.h"
 -#include "DNA_particle_types.h"
  #include "DNA_object_types.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_scene_types.h"
@@@ -82,6 -85,7 +84,6 @@@
  #include "BKE_modifier.h"
  #include "BKE_node.h"
  #include "BKE_object.h"
 -#include "BKE_particle.h"
  #include "BKE_rigidbody.h"
  #include "BKE_sound.h"
  #include "BKE_texture.h"
@@@ -290,9 -294,9 +292,9 @@@ void DepsgraphRelationBuilder::add_coll
                MEM_freeN(collobjs);
  }
  
 -void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name)
 +void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, EffectorWeights *eff, bool add_absorption, const char *name)
  {
 -      ListBase *effectors = pdInitEffectors(scene, ob, psys, eff, false);
 +      ListBase *effectors = pdInitEffectors(scene, ob, eff, false);
  
        if (effectors) {
                for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
                                add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
                        }
  
 -                      if (eff->psys) {
 -                              if (eff->ob != ob) {
 -                                      ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
 -                                      add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
 -
 -                                      /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */
 -                                      ComponentKey mod_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY);
 -                                      add_relation(mod_key, key, DEPSREL_TYPE_STANDARD, name);
 -                              }
 -                              else if (eff->psys != psys) {
 -                                      OperationKey eff_key(&eff->ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, eff->psys->name);
 -                                      add_relation(eff_key, key, DEPSREL_TYPE_STANDARD, name);
 -                              }
 -                      }
 -
                        if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
                                ComponentKey trf_key(&eff->pd->f_source->id, DEPSNODE_TYPE_TRANSFORM);
                                add_relation(trf_key, key, DEPSREL_TYPE_STANDARD, "Smoke Force Domain");
  
  /* **** Functions to build relations between entities  **** */
  
- void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
- {
-       /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
-        * created or not.
-        */
-       BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
-       /* XXX nested node trees are not included in tag-clearing above,
-        * so we need to do this manually.
-        */
-       FOREACH_NODETREE(bmain, nodetree, id) {
-               if (id != (ID *)nodetree)
-                       nodetree->id.tag &= ~LIB_TAG_DOIT;
-       } FOREACH_NODETREE_END
-       if (scene->set) {
-               // TODO: link set to scene, especially our timesource...
-       }
-       /* scene objects */
-       for (Base *base = (Base *)scene->base.first; base; base = base->next) {
-               Object *ob = base->object;
-               /* object itself */
-               build_object(bmain, scene, ob);
-               /* object that this is a proxy for */
-               if (ob->proxy) {
-                       ob->proxy->proxy_from = ob;
-                       build_object(bmain, scene, ob->proxy);
-                       /* TODO(sergey): This is an inverted relation, matches old depsgraph
-                        * behavior and need to be investigated if it still need to be inverted.
-                        */
-                       ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
-                       ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE);
-                       add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy");
-               }
-               /* Object dupligroup. */
-               if (ob->dup_group) {
-                       build_group(bmain, scene, ob, ob->dup_group);
-               }
-       }
-       /* rigidbody */
-       if (scene->rigidbody_world) {
-               build_rigidbody(scene);
-       }
-       /* scene's animation and drivers */
-       if (scene->adt) {
-               build_animdata(&scene->id);
-       }
-       /* world */
-       if (scene->world) {
-               build_world(scene->world);
-       }
-       /* compo nodes */
-       if (scene->nodetree) {
-               build_compositor(scene);
-       }
-       /* grease pencil */
-       if (scene->gpd) {
-               build_gpencil(&scene->id, scene->gpd);
-       }
-       for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin();
-            it_op != m_graph->operations.end();
-            ++it_op)
-       {
-               OperationDepsNode *node = *it_op;
-               IDDepsNode *id_node = node->owner->owner;
-               ID *id = id_node->id;
-               if (GS(id->name) == ID_OB) {
-                       Object *object = (Object *)id;
-                       object->customdata_mask |= node->customdata_mask;
-               }
-       }
- }
  void DepsgraphRelationBuilder::build_group(Main *bmain,
                                             Scene *scene,
                                             Object *object,
        OperationKey object_local_transform_key(&object->id,
                                                DEPSNODE_TYPE_TRANSFORM,
                                                DEG_OPCODE_TRANSFORM_LOCAL);
-       for (GroupObject *go = (GroupObject *)group->gobject.first;
-            go != NULL;
-            go = go->next)
-       {
+       LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
                if (!group_done) {
                        build_object(bmain, scene, go->ob);
                }
@@@ -537,6 -471,11 +454,6 @@@ void DepsgraphRelationBuilder::build_ob
                }
        }
  
 -      /* particle systems */
 -      if (ob->particlesystem.first) {
 -              build_particles(scene, ob);
 -      }
 -
        /* grease pencil */
        if (ob->gpd) {
                build_gpencil(&ob->id, ob->gpd);
@@@ -687,9 -626,10 +604,10 @@@ void DepsgraphRelationBuilder::build_co
                        ListBase targets = {NULL, NULL};
                        cti->get_constraint_targets(con, &targets);
  
-                       for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
-                               if (!ct->tar)
+                       LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) {
+                               if (ct->tar == NULL) {
                                        continue;
+                               }
  
                                if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
                                        /* ignore IK constraints - these are handled separately (on pose level) */
@@@ -816,7 -756,7 +734,7 @@@ void DepsgraphRelationBuilder::build_an
        }
  
        /* drivers */
-       for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+       LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
                OperationKey driver_key(id,
                                        DEPSNODE_TYPE_PARAMETERS,
                                        DEG_OPCODE_DRIVER,
                 */
                if (fcu->array_index > 0) {
                        FCurve *fcu_prev = NULL;
-                       for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first;
-                            fcu_candidate != NULL;
-                            fcu_candidate = fcu_candidate->next)
-                       {
+                       LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) {
                                /* Writing to different RNA paths is  */
                                if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) {
                                        continue;
@@@ -1007,7 -944,7 +922,7 @@@ void DepsgraphRelationBuilder::build_dr
        // XXX: the data itself could also set this, if it were to be truly initialised later?
  
        /* loop over variables to get the target relationships */
-       for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) {
+       LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) {
                /* only used targets */
                DRIVER_TARGETS_USED_LOOPER(dvar)
                {
@@@ -1127,10 -1064,11 +1042,11 @@@ void DepsgraphRelationBuilder::build_ri
  
        /* objects - simulation participants */
        if (rbw->group) {
-               for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+               LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
                        Object *ob = go->ob;
-                       if (!ob || ob->type != OB_MESH)
+                       if (ob == NULL || ob->type != OB_MESH) {
                                continue;
+                       }
  
                        /* hook up evaluation order...
                         * 1) flushing rigidbody results follows base transforms being applied
  
        /* constraints */
        if (rbw->constraints) {
-               for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) {
+               LINKLIST_FOREACH (GroupObject *, go, &rbw->constraints->gobject) {
                        Object *ob = go->ob;
-                       if (!ob || !ob->rigidbody_constraint)
+                       if (ob == NULL || !ob->rigidbody_constraint) {
                                continue;
+                       }
  
                        RigidBodyCon *rbc = ob->rigidbody_constraint;
  
        }
  }
  
- /* IK Solver Eval Steps */
- void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
-                                              bPoseChannel *pchan,
-                                              bConstraint *con,
-                                              RootPChanMap *root_map)
 -void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
--{
-       bKinematicConstraint *data = (bKinematicConstraint *)con->data;
-       /* attach owner to IK Solver too
-        * - assume that owner is always part of chain
-        * - see notes on direction of rel below...
-        */
-       bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
-       OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
-       /* IK target */
-       // XXX: this should get handled as part of the constraint code
-       if (data->tar != NULL) {
-               /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
-                * we create dependency between target object and pose eval component.
-                *
-                * This way we ensuring the whole subtree is updated from scratch without
-                * need of intermediate matricies. This is an overkill, but good enough for
-                * testing IK solver.
-                */
-               // FIXME: geometry targets...
-               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
-               if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
-                       /* TODO(sergey): This is only for until granular update stores intermediate result. */
-                       if (data->tar != ob) {
-                               /* different armature - can just read the results */
-                               ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
-                               add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
-                       }
-                       else {
-                               /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
-                               OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
-                               add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
-                       }
-               }
-               else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
-                       /* vertex group target */
-                       /* NOTE: for now, we don't need to represent vertex groups separately... */
-                       ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
-                       if (data->tar->type == OB_MESH) {
-                               OperationDepsNode *node2 = find_operation_node(target_key);
-                               if (node2 != NULL) {
-                                       node2->customdata_mask |= CD_MASK_MDEFORMVERT;
-                               }
-                       }
-               }
-               else {
-                       /* Standard Object Target */
-                       ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
-                       add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
-               }
-               if ((data->tar == ob) && (data->subtarget[0])) {
-                       /* Prevent target's constraints from linking to anything from same
-                        * chain that it controls.
-                        */
-                       root_map->add_bone(data->subtarget, rootchan->name);
-               }
-       }
-       /* Pole Target */
-       // XXX: this should get handled as part of the constraint code
-       if (data->poletar != NULL) {
-               if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
-                       // XXX: same armature issues - ready vs done?
-                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
-               }
-               else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
-                       /* vertex group target */
-                       /* NOTE: for now, we don't need to represent vertex groups separately... */
-                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
-                       if (data->poletar->type == OB_MESH) {
-                               OperationDepsNode *node2 = find_operation_node(target_key);
-                               if (node2 != NULL) {
-                                       node2->customdata_mask |= CD_MASK_MDEFORMVERT;
-                               }
-                       }
-               }
-               else {
-                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
-               }
-       }
-       DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
-                        pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
-       bPoseChannel *parchan = pchan;
-       /* exclude tip from chain? */
-       if (!(data->flag & CONSTRAINT_IK_TIP)) {
-               OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
-                                               parchan->name, DEG_OPCODE_BONE_LOCAL);
-               add_relation(solver_key, tip_transforms_key,
-                            DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
-               parchan = pchan->parent;
-       }
-       root_map->add_bone(parchan->name, rootchan->name);
-       OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
-                                           parchan->name, DEG_OPCODE_BONE_READY);
-       add_relation(parchan_transforms_key, solver_key,
-                    DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
-       /* Walk to the chain's root */
-       //size_t segcount = 0;
-       int segcount = 0;
-       while (parchan) {
-               /* Make IK-solver dependent on this bone's result,
-                * since it can only run after the standard results
-                * of the bone are know. Validate links step on the
-                * bone will ensure that users of this bone only
-                * grab the result with IK solver results...
-                */
-               if (parchan != pchan) {
-                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
-                       add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
-                       OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-                       add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
-               }
-               else {
-                       OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-                       add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
-               }
-               parchan->flag |= POSE_DONE;
-               root_map->add_bone(parchan->name, rootchan->name);
-               /* continue up chain, until we reach target number of items... */
-               DEG_DEBUG_PRINTF("  %d = %s\n", segcount, parchan->name);
-               segcount++;
-               if ((segcount == data->rootbone) || (segcount > 255)) break;  /* 255 is weak */
 -      TimeSourceKey time_src_key;
 -      OperationKey obdata_ubereval_key(&ob->id,
 -                                       DEPSNODE_TYPE_GEOMETRY,
 -                                       DEG_OPCODE_GEOMETRY_UBEREVAL);
--
-               parchan  = parchan->parent;
-       }
 -      /* particle systems */
 -      LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
 -              ParticleSettings *part = psys->part;
--
-       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-       add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
- }
 -              /* particle settings */
 -              build_animdata(&part->id);
--
- /* Spline IK Eval Steps */
- void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
-                                                    bPoseChannel *pchan,
-                                                    bConstraint *con,
-                                                    RootPChanMap *root_map)
- {
-       bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
-       bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
-       OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
-       OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
 -              /* this particle system */
 -              OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
--
-       /* attach owner to IK Solver too
-        * - assume that owner is always part of chain
-        * - see notes on direction of rel below...
-        */
-       add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
 -              /* XXX: if particle system is later re-enabled, we must do full rebuild? */
 -              if (!psys_check_enabled(ob, psys, G.is_rendering))
 -                      continue;
--
-       /* attach path dependency to solver */
-       if (data->tar) {
-               /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
-                * we create dependency between target object and pose eval component.
-                * See IK pose for a bit more information.
 -              /* TODO(sergey): Are all particle systems depends on time?
 -               * Hair without dynamics i.e.
--               */
-               // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
-               ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
-               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
-               add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
-       }
-       pchan->flag |= POSE_DONE;
-       OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-       add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
-       root_map->add_bone(pchan->name, rootchan->name);
-       /* Walk to the chain's root */
-       //size_t segcount = 0;
-       int segcount = 0;
 -              add_relation(time_src_key, psys_key,
 -                           DEPSREL_TYPE_TIME,
 -                           "TimeSrc -> PSys");
--
-       for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
-               /* Make Spline IK solver dependent on this bone's result,
-                * since it can only run after the standard results
-                * of the bone are know. Validate links step on the
-                * bone will ensure that users of this bone only
-                * grab the result with IK solver results...
 -              /* TODO(sergey): Currently particle update is just a placeholder,
 -               * hook it to the ubereval node so particle system is getting updated
 -               * on playback.
--               */
-               if (parchan != pchan) {
-                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
-                       add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
 -              add_relation(psys_key,
 -                           obdata_ubereval_key,
 -                           DEPSREL_TYPE_OPERATION,
 -                           "PSys -> UberEval");
--
-                       OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-                       add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
 -#if 0
 -              if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
 -                      LINKLIST_FOREACH (ParticleTarget *, pt, &psys->targets) {
 -                              if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) {
 -                                      node2 = dag_get_node(dag, pt->ob);
 -                                      dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets");
 -                              }
 -                      }
--              }
-               parchan->flag |= POSE_DONE;
-               OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-               add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
-               root_map->add_bone(parchan->name, rootchan->name);
-               /* continue up chain, until we reach target number of items... */
-               segcount++;
-               if ((segcount == data->chainlen) || (segcount > 255)) break;  /* 255 is weak */
-       }
-       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-       add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
- }
- /* Pose/Armature Bones Graph */
- void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
- {
-       /* Armature-Data */
-       bArmature *arm = (bArmature *)ob->data;
-       // TODO: selection status?
-       /* attach links between pose operations */
-       OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
-       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-       add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
-       /* Make sure pose is up-to-date with armature updates. */
-       OperationKey armature_key(&arm->id,
-                                 DEPSNODE_TYPE_PARAMETERS,
-                                 DEG_OPCODE_PLACEHOLDER,
-                                 "Armature Eval");
-       add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
-       if (needs_animdata_node(&ob->id)) {
-               ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
-               add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
-       }
-       /* IK Solvers...
-        * - These require separate processing steps are pose-level
-        *   to be executed between chains of bones (i.e. once the
-        *   base transforms of a bunch of bones is done)
-        *
-        * - We build relations for these before the dependencies
-        *   between ops in the same component as it is necessary
-        *   to check whether such bones are in the same IK chain
-        *   (or else we get weird issues with either in-chain
-        *   references, or with bones being parented to IK'd bones)
-        *
-        * Unsolved Issues:
-        * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
-        * - Animated chain-lengths are a problem...
-        */
-       RootPChanMap root_map;
-       bool pose_depends_on_local_transform = false;
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
-                       switch (con->type) {
-                               case CONSTRAINT_TYPE_KINEMATIC:
-                                       build_ik_pose(ob, pchan, con, &root_map);
-                                       pose_depends_on_local_transform = true;
-                                       break;
-                               case CONSTRAINT_TYPE_SPLINEIK:
-                                       build_splineik_pose(ob, pchan, con, &root_map);
-                                       pose_depends_on_local_transform = true;
-                                       break;
--
-                               /* Constraints which needs world's matrix for transform.
-                                * TODO(sergey): More constraints here?
-                                */
-                               case CONSTRAINT_TYPE_ROTLIKE:
-                               case CONSTRAINT_TYPE_SIZELIKE:
-                               case CONSTRAINT_TYPE_LOCLIKE:
-                               case CONSTRAINT_TYPE_TRANSLIKE:
-                                       /* TODO(sergey): Add used space check. */
-                                       pose_depends_on_local_transform = true;
-                                       break;
 -              if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
 -                      node2 = dag_get_node(dag, part->dup_ob);
 -                      /* note that this relation actually runs in the wrong direction, the problem
 -                       * is that dupli system all have this (due to parenting), and the render
 -                       * engine instancing assumes particular ordering of objects in list */
 -                      dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization");
 -                      if (part->dup_ob->type == OB_MBALL)
 -                              dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization");
 -              }
--
-                               default:
-                                       break;
 -              if (part->ren_as == PART_DRAW_GR && part->dup_group) {
 -                      LINKLIST_FOREACH (GroupObject *, go, &part->dup_group->gobject) {
 -                              node2 = dag_get_node(dag, go->ob);
 -                              dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
--                      }
--              }
-       }
-       //root_map.print_debug();
-       if (pose_depends_on_local_transform) {
-               /* TODO(sergey): Once partial updates are possible use relation between
-                * object transform and solver itself in it's build function.
-                */
-               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
-               ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
-               add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
-       }
-       /* links between operations for each bone */
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
-               OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
-               OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
-               OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-               pchan->flag &= ~POSE_DONE;
 -#endif
--
-               /* pose init to bone local */
-               add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
 -              /* collisions */
 -              if (part->type != PART_HAIR) {
 -                      add_collision_relations(psys_key, scene, ob, part->collision_group, ob->lay, true, "Particle Collision");
 -              }
--
-               /* local to pose parenting operation */
-               add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
 -              /* effectors */
 -              add_forcefield_relations(psys_key, scene, ob, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field");
--
-               /* parent relation */
-               if (pchan->parent != NULL) {
-                       eDepsOperation_Code parent_key_opcode;
 -              /* boids */
 -              if (part->boids) {
 -                      LINKLIST_FOREACH (BoidState *, state, &part->boids->states) {
 -                              LINKLIST_FOREACH (BoidRule *, rule, &state->rules) {
 -                                      Object *ruleob = NULL;
 -                                      if (rule->type == eBoidRuleType_Avoid)
 -                                              ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
 -                                      else if (rule->type == eBoidRuleType_FollowLeader)
 -                                              ruleob = ((BoidRuleFollowLeader *)rule)->ob;
--
-                       /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
-                       if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
-                               parent_key_opcode = DEG_OPCODE_BONE_READY;
-                       }
-                       else {
-                               parent_key_opcode = DEG_OPCODE_BONE_DONE;
 -                                      if (ruleob) {
 -                                              ComponentKey ruleob_key(&ruleob->id, DEPSNODE_TYPE_TRANSFORM);
 -                                              add_relation(ruleob_key, psys_key, DEPSREL_TYPE_TRANSFORM, "Boid Rule");
 -                                      }
 -                              }
--                      }
-                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
-                       add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
--              }
-               /* constraints */
-               if (pchan->constraints.first != NULL) {
-                       /* constraints stack and constraint dependencies */
-                       build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
-                       /* pose -> constraints */
-                       OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
-                       add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
--
-                       /* constraints -> ready */
-                       // TODO: when constraint stack is exploded, this step should occur before the first IK solver
-                       add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
-               }
-               else {
-                       /* pose -> ready */
-                       add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
 -              if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
 -                      ComponentKey dup_ob_key(&part->dup_ob->id, DEPSNODE_TYPE_TRANSFORM);
 -                      add_relation(dup_ob_key,
 -                                   psys_key,
 -                                   DEPSREL_TYPE_TRANSFORM,
 -                                   "Particle Object Visualization");
--              }
-               /* bone ready -> done
-                * NOTE: For bones without IK, this is all that's needed.
-                *       For IK chains however, an additional rel is created from IK to done,
-                *       with transitive reduction removing this one...
-                */
-               add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
-               /* assume that all bones must be done for the pose to be ready (for deformers) */
-               add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
--      }
- }
--
- void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
- {
-       OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
-       OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
-            pchan != NULL;
-            pchan = pchan->next)
-       {
-               OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
-               OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
-               OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-               add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
-               add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
-               add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
-               add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
-       }
 -      /* Particle depends on the object transform, so that channel is to be ready
 -       * first.
 -       *
 -       * TODO(sergey): This relation should be altered once real granular update
 -       * is implemented.
 -       */
 -      ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
 -      add_relation(transform_key,
 -                   obdata_ubereval_key,
 -                   DEPSREL_TYPE_GEOMETRY_EVAL,
 -                   "Partcile Eval");
 -
 -      /* pointcache */
 -      // TODO...
--}
--
  /* Shapekeys */
  void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
  {
@@@ -1647,10 -1317,9 +1179,9 @@@ void DepsgraphRelationBuilder::build_ob
  
        /* Modifiers */
        if (ob->modifiers.first) {
-               ModifierData *md;
                OperationKey prev_mod_key;
  
-               for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
+               LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) {
                        const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
                        OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
  
@@@ -1885,7 -1554,7 +1416,7 @@@ void DepsgraphRelationBuilder::build_no
                                    "Parameters Eval");
  
        /* nodetree's nodes... */
-       for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+       LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) {
                if (bnode->id) {
                        if (GS(bnode->id->name) == ID_MA) {
                                build_material(owner, (Material *)bnode->id);
@@@ -1989,4 -1658,21 +1520,21 @@@ bool DepsgraphRelationBuilder::needs_an
        return false;
  }
  
+ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) {
+       /* Animation. */
+       build_animdata(&cache_file->id);
+ }
+ void DepsgraphRelationBuilder::build_mask(Mask *mask)
+ {
+       /* Animation. */
+       build_animdata(&mask->id);
+ }
+ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
+ {
+       /* Animation. */
+       build_animdata(&clip->id);
+ }
  }  // namespace DEG
index 28dd63a7c1772393a9a8f7bd8d9fc296da367c8e,6e8485bee309af42fd435dabe5f22e340c94fc69..2326e212feb4c9227c4a9e4fc50989ceb19a9049
@@@ -47,6 -47,7 +47,7 @@@
  
  struct Base;
  struct bGPdata;
+ struct CacheFile;
  struct ListBase;
  struct GHash;
  struct ID;
@@@ -54,8 -55,10 +55,10 @@@ struct FCurve
  struct Group;
  struct Key;
  struct Main;
+ struct Mask;
  struct Material;
  struct MTex;
+ struct MovieClip;
  struct bNodeTree;
  struct Object;
  struct bPoseChannel;
@@@ -220,9 -223,12 +223,12 @@@ struct DepsgraphRelationBuilde
        void build_texture_stack(ID *owner, MTex **texture_stack);
        void build_compositor(Scene *scene);
        void build_gpencil(ID *owner, bGPdata *gpd);
+       void build_cachefile(CacheFile *cache_file);
+       void build_mask(Mask *mask);
+       void build_movieclip(MovieClip *clip);
  
        void add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, int layer, bool dupli, const char *name);
 -      void add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name);
 +      void add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, EffectorWeights *eff, bool add_absorption, const char *name);
  
        template <typename KeyType>
        OperationDepsNode *find_operation_node(const KeyType &key);
index 4ae5bdff5086a95b759f8344bb188f074b3e51ca,90d33dc59957e41d866e455b9fc8bcdaf2a11e80..45041620fea64ea866bbe0f73b4216e5acdb987f
@@@ -37,7 -37,6 +37,7 @@@
  #include "DNA_material_types.h"
  #include "DNA_mesh_types.h"
  #include "DNA_meta_types.h"
 +#include "DNA_object_force.h"
  #include "DNA_rigidbody_types.h"
  #include "DNA_scene_types.h"
  #include "DNA_smoke_types.h"
@@@ -72,6 -71,8 +72,6 @@@
  #include "BKE_movieclip.h"
  #include "BKE_object.h"
  #include "BKE_paint.h"
 -#include "BKE_particle.h"
 -#include "BKE_pointcache.h"
  #include "BKE_scene.h"
  #include "BKE_subsurf.h"
  #include "BKE_unit.h"
  #include "GPU_select.h"
  #include "GPU_basic_shader.h"
  #include "GPU_shader.h"
 +#include "GPU_immediate.h"
 +#include "GPU_batch.h"
 +#include "GPU_matrix.h"
  
  #include "ED_mesh.h"
 -#include "ED_particle.h"
  #include "ED_screen.h"
  #include "ED_sculpt.h"
  #include "ED_types.h"
  
  #include "view3d_intern.h"  /* bad level include */
  
 +/* 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
@@@ -212,337 -208,12 +212,337 @@@ typedef struct drawBMSelect_userData 
        bool select;
  } drawBMSelect_userData;
  
 -static void draw_bounding_volume(Object *ob, char type);
 +typedef struct {
 +      VertexBuffer *pos_in_order;
 +      ElementList *edges_in_order;
 +      ElementList *triangles_in_order;
 +
 +      Batch *all_verts;
 +      Batch *all_edges;
 +      Batch *all_triangles;
 +
 +      Batch *fancy_edges; /* owns its vertex buffer (not shared) */
 +      Batch *overlay_edges; /* owns its vertex buffer */
 +} MeshBatchCache;
 +
 +static MeshBatchCache *MBC_get(DerivedMesh *dm)
 +{
 +      if (dm->batchCache == NULL) {
 +              /* create cache */
 +              dm->batchCache = MEM_callocN(sizeof(MeshBatchCache), "MeshBatchCache");
 +              /* init everything to 0 is ok for now */
 +      }
 +
 +      return dm->batchCache;
 +}
 +
 +static void MBC_discard(MeshBatchCache *cache)
 +{
 +      if (cache->all_verts) Batch_discard(cache->all_verts);
 +      if (cache->all_edges) Batch_discard(cache->all_edges);
 +      if (cache->all_triangles) Batch_discard(cache->all_triangles);
 +
 +      if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order);
 +      if (cache->edges_in_order) ElementList_discard(cache->edges_in_order);
 +      if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order);
 +
 +      if (cache->fancy_edges) {
 +              Batch_discard_all(cache->fancy_edges);
 +      }
 +
 +      if (cache->overlay_edges) {
 +              Batch_discard_all(cache->overlay_edges);
 +      }
 +}
 +/* need to set this as DM callback:
 + * DM_set_batch_cleanup_callback((DMCleanupBatchCache)MBC_discard);
 + */
 +
 +static VertexBuffer *MBC_get_pos_in_order(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->pos_in_order == NULL) {
 +              static VertexFormat format = { 0 };
 +              static unsigned pos_id;
 +              if (format.attrib_ct == 0) {
 +                      /* initialize vertex format */
 +                      pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
 +              }
 +
 +              const int vertex_ct = dm->getNumVerts(dm);
 +              const MVert *verts = dm->getVertArray(dm);
 +              const unsigned stride = (verts + 1) - verts; /* or sizeof(MVert) */
 +
 +              cache->pos_in_order = VertexBuffer_create_with_format(&format);
 +              VertexBuffer_allocate_data(cache->pos_in_order, vertex_ct);
 +#if 0
 +              fillAttribStride(cache->pos_in_order, pos_id, stride, &verts[0].co);
 +#else
 +              for (int i = 0; i < vertex_ct; ++i) {
 +                      setAttrib(cache->pos_in_order, pos_id, i, &verts[i].co);
 +              }
 +#endif
 +      }
 +
 +      return cache->pos_in_order;
 +}
 +
 +static Batch *MBC_get_all_verts(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->all_verts == NULL) {
 +              /* create batch from DM */
 +              cache->all_verts = Batch_create(GL_POINTS, MBC_get_pos_in_order(dm), NULL);
 +              Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
 +      }
 +
 +      return cache->all_verts;
 +}
 +
 +static ElementList *MBC_get_edges_in_order(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->edges_in_order == NULL) {
 +              const int vertex_ct = dm->getNumVerts(dm);
 +              const int edge_ct = dm->getNumEdges(dm);
 +              const MEdge *edges = dm->getEdgeArray(dm);
 +              ElementListBuilder elb;
 +              ElementListBuilder_init(&elb, GL_LINES, edge_ct, vertex_ct);
 +              for (int i = 0; i < edge_ct; ++i) {
 +                      const MEdge *edge = edges + i;
 +                      add_line_vertices(&elb, edge->v1, edge->v2);
 +              }
 +              cache->edges_in_order = ElementList_build(&elb);
 +      }
 +
 +      return cache->edges_in_order;
 +}
 +
 +static ElementList *MBC_get_triangles_in_order(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->triangles_in_order == NULL) {
 +              const int vertex_ct = dm->getNumVerts(dm);
 +              const int tessface_ct = dm->getNumTessFaces(dm);
 +              const MFace *tessfaces = dm->getTessFaceArray(dm);
 +              ElementListBuilder elb;
 +              ElementListBuilder_init(&elb, GL_TRIANGLES, tessface_ct, vertex_ct);
 +              for (int i = 0; i < tessface_ct; ++i) {
 +                      const MFace *tess = tessfaces + i;
 +                      add_triangle_vertices(&elb, tess->v1, tess->v2, tess->v3);
 +                      /* tessface can be triangle or quad */
 +                      if (tess->v4) {
 +                              add_triangle_vertices(&elb, tess->v3, tess->v2, tess->v4);
 +                      }
 +              }
 +              cache->triangles_in_order = ElementList_build(&elb);
 +      }
 +
 +      return cache->triangles_in_order;
 +}
 +
 +static Batch *MBC_get_all_edges(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->all_edges == NULL) {
 +              /* create batch from DM */
 +              cache->all_edges = Batch_create(GL_LINES, MBC_get_pos_in_order(dm), MBC_get_edges_in_order(dm));
 +      }
 +
 +      return cache->all_edges;
 +}
 +
 +static Batch *MBC_get_all_triangles(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->all_triangles == NULL) {
 +              /* create batch from DM */
 +              cache->all_triangles = Batch_create(GL_TRIANGLES, MBC_get_pos_in_order(dm), MBC_get_triangles_in_order(dm));
 +      }
 +
 +      return cache->all_triangles;
 +}
 +
 +static Batch *MBC_get_fancy_edges(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->fancy_edges == NULL) {
 +              /* create batch from DM */
 +              static VertexFormat format = { 0 };
 +              static unsigned pos_id, n1_id, n2_id;
 +              if (format.attrib_ct == 0) {
 +                      /* initialize vertex format */
 +                      pos_id = add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
 +
 +#if USE_10_10_10 /* takes 1/3 the space */
 +                      n1_id = add_attrib(&format, "N1", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT);
 +                      n2_id = add_attrib(&format, "N2", COMP_I10, 3, NORMALIZE_INT_TO_FLOAT);
 +#else
 +                      n1_id = add_attrib(&format, "N1", COMP_F32, 3, KEEP_FLOAT);
 +                      n2_id = add_attrib(&format, "N2", COMP_F32, 3, KEEP_FLOAT);
 +#endif
 +              }
 +              VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
 +
 +              const MVert *verts = dm->getVertArray(dm);
 +              const MEdge *edges = dm->getEdgeArray(dm);
 +              const MPoly *polys = dm->getPolyArray(dm);
 +              const MLoop *loops = dm->getLoopArray(dm);
 +              const int edge_ct = dm->getNumEdges(dm);
 +              const int poly_ct = dm->getNumPolys(dm);
 +
 +              /* need normal of each face, and which faces are adjacent to each edge */
 +              typedef struct {
 +                      int count;
 +                      int face_index[2];
 +              } AdjacentFaces;
 +
 +              float (*face_normal)[3] = MEM_mallocN(poly_ct * 3 * sizeof(float), "face_normal");
 +              AdjacentFaces *adj_faces = MEM_callocN(edge_ct * sizeof(AdjacentFaces), "adj_faces");
 +
 +              for (int i = 0; i < poly_ct; ++i) {
 +                      const MPoly *poly = polys + i;
 +
 +                      BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, verts, face_normal[i]);
 +
 +                      for (int j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) {
 +                              AdjacentFaces *adj = adj_faces + loops[j].e;
 +                              if (adj->count < 2)
 +                                      adj->face_index[adj->count] = i;
 +                              adj->count++;
 +                      }
 +              }
 +
 +              const int vertex_ct = edge_ct * 2; /* these are GL_LINE verts, not mesh verts */
 +              VertexBuffer_allocate_data(vbo, vertex_ct);
 +              for (int i = 0; i < edge_ct; ++i) {
 +                      const MEdge *edge = edges + i;
 +                      const AdjacentFaces *adj = adj_faces + i;
 +
 +#if USE_10_10_10
 +                      PackedNormal n1value = { .x = 0, .y = 0, .z = +511 };
 +                      PackedNormal n2value = { .x = 0, .y = 0, .z = -511 };
 +
 +                      if (adj->count == 2) {
 +                              n1value = convert_i10_v3(face_normal[adj->face_index[0]]);
 +                              n2value = convert_i10_v3(face_normal[adj->face_index[1]]);
 +                      }
 +
 +                      const PackedNormal *n1 = &n1value;
 +                      const PackedNormal *n2 = &n2value;
 +#else
 +                      const float dummy1[3] = { 0.0f, 0.0f, +1.0f };
 +                      const float dummy2[3] = { 0.0f, 0.0f, -1.0f };
 +
 +                      const float *n1 = (adj->count == 2) ? face_normal[adj->face_index[0]] : dummy1;
 +                      const float *n2 = (adj->count == 2) ? face_normal[adj->face_index[1]] : dummy2;
 +#endif
 +
 +                      setAttrib(vbo, pos_id, 2 * i, &verts[edge->v1].co);
 +                      setAttrib(vbo, n1_id, 2 * i, n1);
 +                      setAttrib(vbo, n2_id, 2 * i, n2);
 +
 +                      setAttrib(vbo, pos_id, 2 * i + 1, &verts[edge->v2].co);
 +                      setAttrib(vbo, n1_id, 2 * i + 1, n1);
 +                      setAttrib(vbo, n2_id, 2 * i + 1, n2);
 +              }
 +
 +              MEM_freeN(adj_faces);
 +              MEM_freeN(face_normal);
 +
 +              cache->fancy_edges = Batch_create(GL_LINES, vbo, NULL);
 +      }
 +
 +      return cache->fancy_edges;
 +}
 +
 +static bool edge_is_real(const MEdge *edges, int edge_ct, int v1, int v2)
 +{
 +      /* TODO: same thing, except not ridiculously slow */
 +
 +      for (int e = 0; e < edge_ct; ++e) {
 +              const MEdge *edge = edges + e;
 +              if ((edge->v1 == v1 && edge->v2 == v2) || (edge->v1 == v2 && edge->v2 == v1)) {
 +                      return true;
 +              }
 +      }
 +
 +      return false;
 +}
 +
 +static void add_overlay_tri(VertexBuffer *vbo, unsigned pos_id, unsigned edgeMod_id, const MVert *verts, const MEdge *edges, int edge_ct, int v1, int v2, int v3, int base_vert_idx)
 +{
 +      const float edgeMods[2] = { 0.0f, 1.0f };
 +
 +      const float *pos = verts[v1].co;
 +      setAttrib(vbo, pos_id, base_vert_idx + 0, pos);
 +      setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (edge_is_real(edges, edge_ct, v2, v3) ? 1 : 0));
 +
 +      pos = verts[v2].co;
 +      setAttrib(vbo, pos_id, base_vert_idx + 1, pos);
 +      setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (edge_is_real(edges, edge_ct, v3, v1) ? 1 : 0));
 +
 +      pos = verts[v3].co;
 +      setAttrib(vbo, pos_id, base_vert_idx + 2, pos);
 +      setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (edge_is_real(edges, edge_ct, v1, v2) ? 1 : 0));
 +}
 +
 +static Batch *MBC_get_overlay_edges(DerivedMesh *dm)
 +{
 +      MeshBatchCache *cache = MBC_get(dm);
 +
 +      if (cache->overlay_edges == NULL) {
 +              /* create batch from DM */
 +              static VertexFormat format = { 0 };
 +              static unsigned pos_id, edgeMod_id;
 +              if (format.attrib_ct == 0) {
 +                      /* initialize vertex format */
 +                      pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
 +                      edgeMod_id = add_attrib(&format, "edgeWidthModulator", GL_FLOAT, 1, KEEP_FLOAT);
 +              }
 +              VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
 +
 +              const int vertex_ct = dm->getNumVerts(dm);
 +              const int edge_ct = dm->getNumEdges(dm);
 +              const int tessface_ct = dm->getNumTessFaces(dm);
 +              const MVert *verts = dm->getVertArray(dm);
 +              const MEdge *edges = dm->getEdgeArray(dm);
 +              const MFace *tessfaces = dm->getTessFaceArray(dm);
 +
 +              VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */
 +
 +              int gpu_vert_idx = 0;
 +              for (int i = 0; i < tessface_ct; ++i) {
 +                      const MFace *tess = tessfaces + i;
 +                      add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v1, tess->v2, tess->v3, gpu_vert_idx);
 +                      gpu_vert_idx += 3;
 +                      /* tessface can be triangle or quad */
 +                      if (tess->v4) {
 +                              add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v3, tess->v2, tess->v4, gpu_vert_idx);
 +                              gpu_vert_idx += 3;
 +                      }
 +              }
 +
 +              VertexBuffer_resize_data(vbo, gpu_vert_idx);
 +
 +              cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL);
 +      }
 +
 +      return cache->overlay_edges;
 +}
 +
 +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 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 ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
@@@ -743,7 -414,7 +743,7 @@@ 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;
        float buffer[4][3];
                        return;
        }
  
 +      immBegin(line_type, n);
        for (int i = 0; i < n; i++) {
                mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
                add_v3_v3(buffer[i], c);
 +              immVertex3fv(pos, buffer[i]);
        }
 +      immEnd();
  
 +      /* TODO: recode this function for clarity once we're not in a hurry to modernize GL usage */
 +
 +#if 0
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, buffer);
        glDrawArrays(line_type, 0, n);
        glDisableClientState(GL_VERTEX_ARRAY);
 +#endif
  }
  
 -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};
  
        glLineWidth(1);
  
 -      switch (drawtype) {
 +      unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT);
 +      if (color) {
 +              immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +              immUniformColor4ubv(color);
 +      }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_3D_DEPTH_ONLY);
 +      }
  
 +      switch (drawtype) {
                case OB_PLAINAXES:
 +                      immBegin(GL_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(GL_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(GL_TRIANGLES, 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(GL_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();
  }
  
  
  /* Function to draw an Image on an empty Object */
- static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
+ 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 width, height;
  
 -      ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
 +      int bindcode = 0;
  
 -      if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
 -              IMB_rect_from_float(ibuf);
 -      }
 +      if (ima) {
++              ImageUser iuser = *ob->iuser;
++
++              /* Support multi-view */
++              if (ima && (sview == STEREO_RIGHT_ID)) {
++                      iuser.multiview_eye = sview;
++                      iuser.flag |= IMA_SHOW_STEREO;
++                      BKE_image_multiview_index(ima, &iuser);
++              }
 -      int ima_x, ima_y;
 +              if (ob_alpha > 0.0f) {
-                       bindcode = GPU_verify_image(ima, ob->iuser, GL_TEXTURE_2D, 0, false, false, false);
++                      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, ob->iuser, &w, &h);
++              BKE_image_get_size(ima, &iuser, &w, &h);
 +              width = w;
 +              height = h;
        }
        else {
 -              ima_x = 1;
 -              ima_y = 1;
 +              /* if no image, make it a 1x1 empty square, honor scale & offset */
 +              width = height = 1.0f;
        }
  
 -      float sca_x = 1.0f;
 -      float sca_y = 1.0f;
 +      const float aspect = height / width;
  
 -      /* Get the image aspect even if the buffer is invalid */
 -      if (ima) {
 -              if (ima->aspx > ima->aspy) {
 -                      sca_y = ima->aspy / ima->aspx;
 -              }
 -              else if (ima->aspx < ima->aspy) {
 -                      sca_x = ima->aspx / ima->aspy;
 -              }
 -      }
 +      float left = ob->ima_ofs[0];
 +      float right = ob->ima_ofs[0] + ob->empty_drawsize;
 +      float top = ob->ima_ofs[1] + ob->empty_drawsize * aspect;
 +      float bottom = ob->ima_ofs[1];
  
 -      /* 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;
 +      bool use_blend = false;
  
 -      glMatrixMode(GL_MODELVIEW);
 -      glPushMatrix();
 +      if (bindcode) {
 +              use_blend = ob_alpha < 1.0f || BKE_image_has_alpha(ima);
  
 -      /* Calculate Image scale */
 -      float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
 +              if (use_blend) {
 +                      glEnable(GL_BLEND);
 +                      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +              }
  
 -      /* Set the object scale */
 -      glScalef(scale * sca_x, scale * sca_y, 1.0f);
 +              VertexFormat *format = immVertexFormat();
 +              unsigned pos = add_attrib(format, "pos", GL_FLOAT, 2, KEEP_FLOAT);
 +              unsigned texCoord = add_attrib(format, "texCoord", GL_FLOAT, 2, KEEP_FLOAT);
 +              immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
 +              immUniform1f("alpha", ob_alpha);
 +              immUniform1i("image", 0); /* default GL_TEXTURE0 unit */
  
 -      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);
 +              immBegin(GL_TRIANGLE_FAN, 4);
 +              immAttrib2f(texCoord, 0.0f, 0.0f);
 +              immVertex2f(pos, left, bottom);
  
 -              if (use_clip) {
 -                      glEnable(GL_ALPHA_TEST);
 -                      glAlphaFunc(GL_GREATER, U.glalphaclip);
 -              }
 +              immAttrib2f(texCoord, 1.0f, 0.0f);
 +              immVertex2f(pos, right, bottom);
  
 -              /* Use the object color and alpha */
 -              glColor4fv(ob->col);
 +              immAttrib2f(texCoord, 1.0f, 1.0f);
 +              immVertex2f(pos, right, top);
  
 -              /* Draw the Image on the screen */
 -              glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
 +              immAttrib2f(texCoord, 0.0f, 1.0f);
 +              immVertex2f(pos, left, top);
 +              immEnd();
  
 -              glDisable(GL_BLEND);
 +              immUnbindProgram();
  
 -              if (use_clip) {
 -                      glDisable(GL_ALPHA_TEST);
 -                      glAlphaFunc(GL_ALWAYS, 0.0f);
 -              }
 +              glBindTexture(GL_TEXTURE_2D, 0); /* necessary? */
        }
  
 -      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -              glColor3ubv(ob_wire_col);
 +      /* Draw the image outline */
 +      glLineWidth(1.5f);
 +      unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 2, KEEP_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, left, bottom, right, top);
        }
 +      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, left, bottom, right, top);
 +
 +              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])
@@@ -1100,65 -759,50 +1109,65 @@@ void drawcircball(int mode, const floa
        glDisableClientState(GL_VERTEX_ARRAY);
  }
  
 +static 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);
 +
 +      immBegin(GL_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)
  {
 -      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 pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_SMOOTH);
 +      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(GL_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 ************* */
@@@ -1330,9 -974,9 +1339,9 @@@ void view3d_cached_text_draw_end(View3
  /* 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 GLfloat 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(GL_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(GL_LINES, 2);
 +      immVertex3fv(pos, sta);
 +      immVertex3fv(pos, end);
 +      immEnd();
  
        glPointSize(3.0);
 -      glBegin(GL_POINTS);
 -      glVertex3fv(sta);
 -      glVertex3fv(end);
 -      glEnd();
 +      immBegin(GL_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);
 +
 +      immBegin(GL_TRIANGLE_FAN, square ? 6 : 34);
 +      immVertex3f(pos, 0.0f, 0.0f, -x);
  
 -      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);
 +      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);
        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);
 +      immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f);
  
 -      draw_spot_cone(la, x, z);
 +      draw_spot_cone(la, x, z, pos);
  
        /* restore state */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  }
  
  #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);
        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);
 +      immUniformColor4f(0.2f, 0.2f, 0.2f, 1.0f);
  
 -      draw_box(box, true);
 +      imm_draw_box(box, true, pos);
  
        /* restore state */
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  }
  #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);
  
        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);
 +      gpuMatrixBegin3D_legacy();
 +      gpuPushMatrix();
 +      gpuLoadMatrix3D(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 pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_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);
 +      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);
 +                                      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_SMOOTH);
 +                      immUniform1f("size", lampdot_size);
 +                      immUniform1f("outlineWidth", outlineWidth);
 +                      immUniformColor3fvAlpha(color, 0.3f);
 +                      immUniform4fv("outlineColor", color);
 +
 +                      immBegin(GL_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(GL_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);
 +              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(GL_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(GL_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(GL_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_lined_circle_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_lined_circle_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(GL_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(GL_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(GL_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(GL_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();
 +      gpuLoadMatrix3D(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(GL_LINES, 2);
 +      immVertex3fv(pos, vec);
        vec[2] = 0;
 -      glVertex3fv(vec);
 -      glEnd();
 -      
 +      immVertex3fv(pos, vec);
 +      immEnd();
 +
        glPointSize(2.0);
 -      glBegin(GL_POINTS);
 -      glVertex3fv(vec);
 -      glEnd();
 -      
 +      immBegin(GL_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();
 +      gpuMatrixEnd();
  }
  
 -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(GL_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);
 +              /* 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(GL_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(GL_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
@@@ -2070,19 -1679,16 +2079,19 @@@ static void draw_viewport_object_recons
  
                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) {
                                draw_bundle_sphere();
                        }
                        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);
                        }
                }
  
@@@ -2204,68 -1806,59 +2213,68 @@@ static void draw_viewport_reconstructio
                GPU_select_load_id(base->selcol);
  }
  
 -static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode)
 -{
 -      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(near_plane[1]);
 -      glVertex3fv(far_plane[1]);
 -      glVertex3fv(far_plane[2]);
 -      glEnd();
 -
 -      glBegin(mode);
 -      glVertex3fv(far_plane[0]);
 -      glVertex3fv(near_plane[0]);
 -      glVertex3fv(near_plane[3]);
 -      glVertex3fv(far_plane[3]);
 -      glEnd();
 -}
 -
  /* camera frame */
 -static void drawcamera_frame(float vec[4][3], const GLenum mode)
 +static void drawcamera_frame(float vec[4][3], bool filled, unsigned pos)
  {
 -      glBegin(mode);
 -      glVertex3fv(vec[0]);
 -      glVertex3fv(vec[1]);
 -      glVertex3fv(vec[2]);
 -      glVertex3fv(vec[3]);
 -      glEnd();
 +      immBegin(filled ? GL_QUADS : GL_LINE_LOOP, 4);
 +      immVertex3fv(pos, vec[0]);
 +      immVertex3fv(pos, vec[1]);
 +      immVertex3fv(pos, vec[2]);
 +      immVertex3fv(pos, vec[3]);
 +      immEnd();
  }
  
  /* center point to camera frame */
 -static void drawcamera_framelines(float vec[4][3], float origin[3])
 -{
 -      glBegin(GL_LINE_STRIP);
 -      glVertex3fv(vec[1]);
 -      glVertex3fv(origin);
 -      glVertex3fv(vec[0]);
 -      glVertex3fv(vec[3]);
 -      glVertex3fv(origin);
 -      glVertex3fv(vec[2]);
 -      glEnd();
 +static void drawcamera_framelines(float vec[4][3], float origin[3], unsigned pos)
 +{
 +      immBegin(GL_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();
 +}
 +
 +static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], bool filled, unsigned pos)
 +{
 +      drawcamera_frame(near_plane, filled, pos);
 +      drawcamera_frame(far_plane, filled, pos);
 +
 +      if (filled) {
 +              immBegin(GL_QUADS, 16); /* TODO(merwin): use GL_TRIANGLE_STRIP here */
 +              immVertex3fv(pos, near_plane[0]);
 +              immVertex3fv(pos, far_plane[0]);
 +              immVertex3fv(pos, far_plane[1]);
 +              immVertex3fv(pos, near_plane[1]);
 +
 +              immVertex3fv(pos, near_plane[1]);
 +              immVertex3fv(pos, far_plane[1]);
 +              immVertex3fv(pos, far_plane[2]);
 +              immVertex3fv(pos, near_plane[2]);
 +
 +              immVertex3fv(pos, near_plane[2]);
 +              immVertex3fv(pos, near_plane[1]);
 +              immVertex3fv(pos, far_plane[1]);
 +              immVertex3fv(pos, far_plane[2]);
 +
 +              immVertex3fv(pos, far_plane[0]);
 +              immVertex3fv(pos, near_plane[0]);
 +              immVertex3fv(pos, near_plane[3]);
 +              immVertex3fv(pos, far_plane[3]);
 +              immEnd();
 +      }
 +      else {
 +              immBegin(GL_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);
 +              gpuLoadMatrix3D(rv3d->viewmat);
                BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat);
 -              glMultMatrixf(obmat);
 +              gpuMultMatrix3D(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);
 +      gpuLoadMatrix3D(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);
 +              glPushAttrib(GL_ENABLE_BIT); /* TODO(merwin): new state tracking! */
 +              glLineStipple(2, 0xAAAA);
 +              glEnable(GL_LINE_STIPPLE);
  
 -              glBegin(GL_LINES);
 -              glVertex3fv(origin[0]);
 -              glVertex3fv(origin[1]);
 -              glEnd();
 +              immBegin(GL_LINES, 2);
 +              immVertex3fv(pos, origin[0]);
 +              immVertex3fv(pos, origin[1]);
 +              immEnd();
  
 -              GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
 +              glPopAttrib();
        }
  
        /* 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 */
  
 -                      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 */
                        }
  
                        /* 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 */
  
                                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 */
                        }
                }
        }
 -
 -      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);
 +      gpuMatrixBegin3D_legacy();
 +
 +      unsigned pos = add_attrib(immVertexFormat(), "pos", GL_FLOAT, 3, KEEP_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +      if (ob_wire_col) {
 +              immUniformColor3ubv(ob_wire_col);
 +      }
        glLineWidth(1);
  
        /* camera frame */
                        float obmat[4][4];
                        bool is_left = v3d->multiview_eye == STEREO_LEFT_ID;
  
 -                      glPushMatrix();
 -                      glLoadMatrixf(rv3d->viewmat);
 +                      gpuPushMatrix();
 +                      gpuLoadMatrix3D(rv3d->viewmat);
                        BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat);
 -                      glMultMatrixf(obmat);
 +                      gpuMultMatrix3D(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();
 +              gpuMatrixEnd();
                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(GL_LINE_LOOP, 3);
 +              else if (i == 1 && is_active) {
 +                      glDisable(GL_CULL_FACE); /* TODO: declarative state tracking */
 +                      immBegin(GL_TRIANGLES, 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);
 +                      gpuLoadMatrix3D(rv3d->viewmat);
 +                      gpuMultMatrix3D(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();
 +      gpuMatrixEnd();
  }
  
  /* 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];
 +      VertexFormat *format = immVertexFormat();
 +      unsigned int pos = add_attrib(format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
 +
 +      immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
 +
 +      if (ob_wire_col) {
 +              immUniformColor3ubv(ob_wire_col);
 +      }
  
 -      glEnable(GL_BLEND);
        glLineWidth(1);
  
 +      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(GL_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(GL_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)
@@@ -4351,88 -3930,9 +4360,88 @@@ static void draw_em_fancy(Scene *scene
  #endif
  }
  
 +static void draw_em_fancy_new(Scene *scene, ARegion *ar, View3D *v3d,
 +                              Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt)
 +{
 +      /* for now... something simple! */
 +
 +      Batch *surface = MBC_get_all_triangles(cageDM);
 +
 +      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);
 +      Batch_Uniform4f(surface, "color", 1.0f, 0.5f, 0.0f, 0.5f);
 +      Batch_draw(surface);
 +
 +#if 0 /* until I understand finalDM better */
 +      if (finalDM != cageDM) {
 +              puts("finalDM != cageDM");
 +              Batch *finalSurface = MBC_get_all_triangles(finalDM);
 +              Batch_set_builtin_program(finalSurface, GPU_SHADER_3D_UNIFORM_COLOR);
 +              Batch_Uniform4f(finalSurface, "color", 0.0f, 0.0f, 0.0f, 0.05f);
 +              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);
 +      Batch_draw(surface);
 +
 +      if (GLEW_VERSION_3_2) {
 +              Batch *overlay = MBC_get_overlay_edges(cageDM);
 +              Batch_set_builtin_program(overlay, GPU_SHADER_EDGES_OVERLAY);
 +              Batch_Uniform2f(overlay, "viewportSize", ar->winx, ar->winy);
 +              Batch_draw(overlay);
 +
 +#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 };
 +               * Batch_Uniform4f(surface, "fillColor", edgeColor[0], edgeColor[1], edgeColor[2], 0.0f);
 +               * Batch_Uniform4fv(surface, "outlineColor", edgeColor);
 +               * Batch_Uniform1f(surface, "outlineWidth", 1.0f);
 +               */
 +              Batch_Uniform2f(surface, "viewportSize", ar->winx, ar->winy);
 +              Batch_draw(surface);
 +#endif
 +      }
 +      else {
 +              Batch *edges = MBC_get_all_edges(cageDM);
 +              Batch_set_builtin_program(edges, GPU_SHADER_3D_UNIFORM_COLOR);
 +              Batch_Uniform4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f);
 +              glEnable(GL_LINE_SMOOTH);
 +              glLineWidth(1.5f);
 +              Batch_draw(edges);
 +              glDisable(GL_LINE_SMOOTH);
 +      }
 +
 +#if 0 /* looks good even without points */
 +      Batch *verts = MBC_get_all_verts(cageDM);
 +      glEnable(GL_BLEND);
 +
 +      Batch_set_builtin_program(verts, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_SMOOTH);
 +      Batch_Uniform4f(verts, "color", 0.0f, 0.0f, 0.0f, 1.0f);
 +      Batch_Uniform1f(verts, "size", UI_GetThemeValuef(TH_VERTEX_SIZE) * 1.5f);
 +      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) /* 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 */
        }
  }
  
 +static void draw_mesh_object_outline_new(View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, 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 */
 +              Batch *fancy_edges = MBC_get_fancy_edges(dm);
 +
 +              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);
 +                      Batch_Uniform3fv(fancy_edges, "eye", eye);
 +              }
 +              else {
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
 +              }
 +
 +              Batch_Uniform1b(fancy_edges, "drawFront", false);
 +              Batch_Uniform1b(fancy_edges, "drawBack", false);
 +              Batch_Uniform1b(fancy_edges, "drawSilhouette", true);
 +              Batch_Uniform4fv(fancy_edges, "silhouetteColor", outline_color);
 +
 +              Batch_draw(fancy_edges);
 +#else /* alternate version that matches look of old viewport (but more efficient) */
 +              Batch *batch = MBC_get_all_edges(dm);
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
 +              Batch_Uniform4fv(batch, "color", outline_color);
 +              Batch_draw(batch);
 +#endif
 +
 +              glDepthMask(GL_TRUE);
 +      }
 +}
 +
  static bool object_is_halo(Scene *scene, Object *ob)
  {
        const Material *ma = give_current_material(ob, 1);
@@@ -4721,7 -4179,12 +4730,7 @@@ static void draw_mesh_fancy(Scene *scen
                 * with the background. */
  
                if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                      if (is_obact && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
 -                              ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f);
 -                      }
 -                      else {
 -                              glColor3ubv(ob_wire_col);
 -                      }
 +                      glColor3ubv(ob_wire_col);
                }
  
                /* If drawing wire and drawtype is not OB_WIRE then we are
@@@ -4774,7 -4237,7 +4783,7 @@@ static bool draw_mesh_object(Scene *sce
        /* 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;
        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);
 -
 -      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;
 +      /* original idea: nice variations (lighter & darker shades) of base color
 +       * current implementation uses input color as high; med & low get closer to background color
 +       */
  
 -              switch (dl->type) {
 -                      case DL_SEGM:
 +      float bg[3];
 +      UI_GetThemeColor3fv(TH_BACK, bg);
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +      float base[4];
 +      rgba_uchar_to_float(base, base_ubyte);
  
 -                              for (parts = 0; parts < dl->parts; parts++)
 -                                      glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
 -                              
 -                              break;
 -                      case DL_POLY:
 +      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_LOOP, parts * dl->nr, dl->nr);
 +static void draw_mesh_fancy_new(Scene *scene, 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, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
 +              return;
 +      }
  
 -                              break;
 -                      case DL_SURF:
 +#ifdef WITH_GAMEENGINE
 +      Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : 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);
 +      int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0;
  
 -                              glVertexPointer(3, GL_FLOAT, 0, data);
 +      if (!dm)
 +              return;
  
 -                              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);
 -                              }
 +      const bool solid = dt >= OB_SOLID;
 +      if (solid) {
 +              DM_update_materials(dm, ob);
 +      }
  
 -                              for (int nr = 0; nr < dl->nr; nr++) {
 -                                      int ofs = 3 * dl->nr;
 +      /* 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;
  
 -                                      data = (dl->verts) + 3 * nr;
 -                                      parts = dl->parts;
 +      /* Unwanted combination */
 +      if (draw_flags & DRAW_FACE_SELECT) {
 +              draw_wire = OBDRAW_WIRE_OFF;
 +      }
 +      else if (ob->dtx & OB_DRAWWIRE) {
 +              draw_wire = OBDRAW_WIRE_ON;
 +      }
  
 -                                      if (dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP);
 -                                      else glBegin(GL_LINE_STRIP);
 -
 -                                      while (parts--) {
 -                                              glVertex3fv(data);
 -                                              data += ofs;
 -                                      }
 -                                      glEnd();
 -
 -#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;
 -
 -                      case DL_INDEX3:
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              break;
 -
 -                      case DL_INDEX4:
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                              glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -                              break;
 -              }
 -      }
 -      
 -      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;
 -
 -      /* 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);
 -}
 -
 -static bool index3_nors_incr = true;
 -
 -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;
 -
 -      glEnableClientState(GL_VERTEX_ARRAY);
 -
 -      /* track current material, -1 for none (needed for lines) */
 -      short col = -1;
 -      
 -      DispList *dl = lb->first;
 -      while (dl) {
 -              const float *data = dl->verts;
 -              const float *ndata = dl->nors;
 -
 -              switch (dl->type) {
 -                      case DL_SEGM:
 -                              if (ob->type == OB_SURF) {
 -                                      if (col != -1) {
 -                                              GPU_object_material_unbind();
 -                                              col = -1;
 -                                      }
 -
 -                                      if ((dflag & DRAW_CONSTCOLOR) == 0)
 -                                              glColor3ubv(ob_wire_col);
 -
 -                                      // glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -                                      // glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
 -                                      glBegin(GL_LINE_STRIP);
 -                                      for (int nr = dl->nr; nr; nr--, data += 3)
 -                                              glVertex3fv(data);
 -                                      glEnd();
 -                              }
 -                              break;
 -                      case DL_POLY:
 -                              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);
 -
 -                                      glBegin(GL_LINE_LOOP);
 -                                      for (int nr = dl->nr; nr; nr--, data += 3)
 -                                              glVertex3fv(data);
 -                                      glEnd();
 -                              }
 -                              break;
 -                      case DL_SURF:
 -
 -                              if (dl->index) {
 -                                      if (col != dl->col) {
 -                                              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);
 -
 -                                      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);
 -                              }
 -                              break;
 -
 -                      case DL_INDEX3:
 -                              if (col != dl->col) {
 -                                      GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
 -                                      col = dl->col;
 -                              }
 -
 -                              glVertexPointer(3, GL_FLOAT, 0, dl->verts);
 -
 -                              /* for polys only one normal needed */
 -                              if (index3_nors_incr) {
 -                                      glEnableClientState(GL_NORMAL_ARRAY);
 -                                      glNormalPointer(GL_FLOAT, 0, dl->nors);
 -                              }
 -                              else
 -                                      glNormal3fv(ndata);
 -
 -                              glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
 -
 -                              if (index3_nors_incr)
 -                                      glDisableClientState(GL_NORMAL_ARRAY);
 -
 -                              break;
 -
 -                      case DL_INDEX4:
 -                              if (col != dl->col) {
 -                                      GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
 -                                      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);
 -
 -                              break;
 -              }
 -              dl = dl->next;
 -      }
 -
 -      glDisableClientState(GL_VERTEX_ARRAY);
 -      glFrontFace(GL_CCW);
 -
 -      if (col != -1) {
 -              GPU_object_material_unbind();
 -      }
 -}
 -
 -static void drawCurveDMWired(Object *ob)
 -{
 -      DerivedMesh *dm = ob->derivedFinal;
 -      dm->drawEdges(dm, 1, 0);
 -}
 -
 -/* return true when nothing was drawn */
 -static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt)
 -{
 -      Object *ob = base->object;
 -      DerivedMesh *dm = ob->derivedFinal;
 -
 -      if (!dm) {
 -              return true;
 -      }
 -
 -      DM_update_materials(dm, ob);
 -
 -      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);
 -
 -              if (!glsl)
 -                      dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
 -              else
 -                      dm->drawFacesGLSL(dm, GPU_object_material_bind);
 -
 -              GPU_end_object_materials();
 -      }
 -      else {
 -              if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)
 -                      drawCurveDMWired(ob);
 -      }
 -
 -      return false;
 -}
 -
 -/**
 - * Only called by #drawDispList
 - * \return true when nothing was drawn
 - */
 -static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 -                                    const char dt, const short dflag, const unsigned char ob_wire_col[4])
 -{
 -      Object *ob = base->object;
 -      ListBase *lb = NULL;
 -      DispList *dl;
 -      Curve *cu;
 -      const bool render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
 -      const bool solid = (dt > OB_WIRE);
 -
 -      switch (ob->type) {
 -              case OB_FONT:
 -              case OB_CURVE:
 -                      cu = ob->data;
 -
 -                      lb = &ob->curve_cache->disp;
 -
 -                      if (solid) {
 -                              const bool has_faces = BKE_displist_has_faces(lb);
 -                              dl = lb->first;
 -                              if (dl == NULL) {
 -                                      return true;
 -                              }
 -
 -                              if (dl->nors == NULL) BKE_displist_normals_add(lb);
 -                              index3_nors_incr = false;
 -
 -                              if (!render_only) {
 -                                      /* when we have faces, only draw loose-wire */
 -                                      if (has_faces) {
 -                                              drawDispListwire_ex(lb, (1 << DL_SEGM));
 -                                      }
 -                                      else {
 -                                              drawDispListwire(lb, ob->type);
 -                                      }
 -                              }
 -
 -                              if (has_faces == false) {
 -                                      /* pass */
 -                              }
 -                              else {
 -                                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, 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);
 -                                              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);
 -                                      }
 -                              }
 -                              index3_nors_incr = true;
 -                      }
 -                      else {
 -                              if (!render_only || BKE_displist_has_faces(lb)) {
 -                                      return drawDispListwire(lb, ob->type);
 -                              }
 -                      }
 -                      break;
 -              case OB_SURF:
 -
 -                      lb = &ob->curve_cache->disp;
 -
 -                      if (solid) {
 -                              dl = lb->first;
 -                              if (dl == NULL) {
 -                                      return true;
 -                              }
 -
 -                              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);
 -                                      drawDispListsolid(lb, ob, dflag, ob_wire_col, true);
 -                                      GPU_end_object_materials();
 -                              }
 -                              else {
 -                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL);
 -                                      drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
 -                                      GPU_end_object_materials();
 -                              }
 -                      }
 -                      else {
 -                              return drawDispListwire(lb, ob->type);
 -                      }
 -                      break;
 -              case OB_MBALL:
 -
 -                      if (BKE_mball_is_basis(ob)) {
 -                              lb = &ob->curve_cache->disp;
 -                              if (BLI_listbase_is_empty(lb)) {
 -                                      return true;
 -                              }
 +      /* 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);
 +      }
  
 -                              if (solid) {
 +      if (solid) {
 +              /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
 +              glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
 +      }
  
 -                                      if (draw_glsl_material(scene, ob, v3d, dt)) {
 -                                              GPU_begin_object_materials(v3d, rv3d, scene, 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);
 -                                              drawDispListsolid(lb, ob, dflag, ob_wire_col, false);
 -                                              GPU_end_object_materials();
 -                                      }
 -                              }
 -                              else {
 -                                      return drawDispListwire(lb, ob->type);
 -                              }
 -                      }
 -                      break;
 +      if (dt == OB_BOUNDBOX) {
 +              if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0)
 +                      draw_bounding_volume(ob, ob->boundtype);
        }
 +      else if ((no_faces && no_edges) ||
 +               ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob)))
 +      {
 +              glPointSize(1.5);
 +              // dm->drawVerts(dm);
 +              // TODO: draw smooth round points as a batch
 +      }
 +      else if ((dt == OB_WIRE) || no_faces) {
 +              draw_wire = OBDRAW_WIRE_ON;
  
 -      return false;
 -}
 -static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
 -                         const char dt, const short dflag, const unsigned char ob_wire_col[4])
 -{
 -      bool retval;
 +              /* enable depth for wireframes */
 +              glEnable(GL_DEPTH_TEST);
 +              glDepthFunc(GL_LESS);
  
 -      /* backface culling */
 -      if (v3d->flag2 & V3D_BACKFACE_CULLING) {
 -              /* not all displists use same in/out normal direction convention */
 -              glEnable(GL_CULL_FACE);
 -              glCullFace(GL_BACK);
 -      }
 +              glLineWidth(1.0f);
  
 -#ifdef SEQUENCER_DAG_WORKAROUND
 -      ensure_curve_cache(scene, base->object);
 -#endif
 +#if 1 /* fancy wireframes */
  
 -      if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
 -              retval = false;
 -      }
 -      else {
 -              Object *ob = base->object;
 -              GLenum mode;
 +              Batch *fancy_edges = MBC_get_fancy_edges(dm);
  
 -              if (ob->type == OB_MBALL) {
 -                      mode = (ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW;
 +              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);
 +                      Batch_Uniform3fv(fancy_edges, "eye", eye);
                }
                else {
 -                      mode = (ob->transflag & OB_NEG_SCALE) ? GL_CCW : GL_CW;
 +                      Batch_set_builtin_program(fancy_edges, GPU_SHADER_EDGES_FRONT_BACK_PERSP);
                }
  
 -              glFrontFace(mode);
 +              float frontColor[4];
 +              float backColor[4];
 +              float outlineColor[4];
 +              make_color_variations(ob_wire_col, backColor, frontColor, outlineColor, other_obedit);
  
 -              retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
 +              Batch_Uniform4fv(fancy_edges, "frontColor", frontColor);
 +              Batch_Uniform4fv(fancy_edges, "backColor", backColor);
 +              Batch_Uniform1b(fancy_edges, "drawFront", true);
 +              Batch_Uniform1b(fancy_edges, "drawBack", true); /* false here = backface cull */
 +              Batch_Uniform1b(fancy_edges, "drawSilhouette", false);
  
 -              if (mode != GL_CCW) {
 -                      glFrontFace(GL_CCW);
 -              }
 -      }
 +              Batch_draw(fancy_edges);
  
 -      if (v3d->flag2 & V3D_BACKFACE_CULLING) {
 -              glDisable(GL_CULL_FACE);
 -      }
 +              /* extra oomph for the silhouette contours */
 +              glLineWidth(2.0f);
 +              Batch_use_program(fancy_edges); /* hack to make the following uniforms stick */
 +              Batch_Uniform1b(fancy_edges, "drawFront", false);
 +              Batch_Uniform1b(fancy_edges, "drawBack", false);
 +              Batch_Uniform1b(fancy_edges, "drawSilhouette", true);
 +              Batch_Uniform4fv(fancy_edges, "silhouetteColor", outlineColor);
  
 -      return retval;
 -}
 +              Batch_draw(fancy_edges);
  
 -/* *********** drawing for particles ************* */
 -static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select)
 -{
 -      /* draw created data arrays */
 -      switch (draw_as) {
 -              case PART_DRAW_AXIS:
 -              case PART_DRAW_CROSS:
 -                      glDrawArrays(GL_LINES, 0, 6 * totpoint);
 -                      break;
 -              case PART_DRAW_LINE:
 -                      glDrawArrays(GL_LINES, 0, 2 * totpoint);
 -                      break;
 -              case PART_DRAW_BB:
 -                      if (ob_dt <= OB_WIRE || select)
 -                              glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -                      else
 -                              glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 +#else /* simple wireframes */
  
 -                      glDrawArrays(GL_QUADS, 0, 4 * totpoint);
 -                      break;
 -              default:
 -                      glDrawArrays(GL_POINTS, 0, totpoint);
 -                      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 vec[3], vec2[3];
 -      float *vd = NULL;
 -      float *cd = NULL;
 -      float ma_col[3] = {0.0f, 0.0f, 0.0f};
 +              Batch *batch = MBC_get_all_edges(dm);
 +              Batch_set_builtin_program(batch, GPU_SHADER_3D_UNIFORM_COLOR);
  
 -      /* null only for PART_DRAW_CIRC */
 -      if (pdd) {
 -              vd = pdd->vd;
 -              cd = pdd->cd;
 +              float color[4];
 +              rgba_uchar_to_float(color, ob_wire_col);
  
 -              if (pdd->ma_col) {
 -                      copy_v3_v3(ma_col, pdd->ma_col);
 -              }
 +              Batch_Uniform4fv(batch, "color", color);
 +
 +              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;
  
 -      switch (draw_as) {
 -              case PART_DRAW_DOT:
 +              if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                  ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                  (base->flag & SELECT) &&
 +                  !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) &&
 +                  (draw_wire == OBDRAW_WIRE_OFF))
                {
 -                      if (vd) {
 -                              copy_v3_v3(vd, state->co); pdd->vd += 3;
 -                      }
 -                      if (cd) {
 -                              copy_v3_v3(cd, pdd->ma_col);
 -                              pdd->cd += 3;
 -                      }
 -                      break;
 +                      draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT));
                }
 -              case PART_DRAW_CROSS:
 -              case PART_DRAW_AXIS:
 -              {
 -                      vec[0] = 2.0f * pixsize;
 -                      vec[1] = vec[2] = 0.0;
 -                      mul_qt_v3(state->rot, vec);
 -                      if (draw_as == PART_DRAW_AXIS) {
 -                              if (cd) {
 -                                      cd[1] = cd[2] = cd[4] = cd[5] = 0.0;
 -                                      cd[0] = cd[3] = 1.0;
 -                                      cd[6] = cd[8] = cd[9] = cd[11] = 0.0;
 -                                      cd[7] = cd[10] = 1.0;
 -                                      cd[13] = cd[12] = cd[15] = cd[16] = 0.0;
 -                                      cd[14] = cd[17] = 1.0;
 -                                      pdd->cd += 18;
 -                              }
 -
 -                              copy_v3_v3(vec2, state->co);
 -                      }
 -                      else {
 -                              if (cd) {
 -                                      cd[0] = cd[3] = cd[6] = cd[9] = cd[12] = cd[15] = ma_col[0];
 -                                      cd[1] = cd[4] = cd[7] = cd[10] = cd[13] = cd[16] = ma_col[1];
 -                                      cd[2] = cd[5] = cd[8] = cd[11] = cd[14] = cd[17] = ma_col[2];
 -                                      pdd->cd += 18;
 -                              }
 -                              sub_v3_v3v3(vec2, state->co, vec);
 -                      }
  
 -                      add_v3_v3(vec, state->co);
 -                      copy_v3_v3(pdd->vd, vec); pdd->vd += 3;
 -                      copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
 -
 -                      vec[1] = 2.0f * pixsize;
 -                      vec[0] = vec[2] = 0.0;
 -                      mul_qt_v3(state->rot, vec);
 -                      if (draw_as == PART_DRAW_AXIS) {
 -                              copy_v3_v3(vec2, state->co);
 -                      }
 -                      else {
 -                              sub_v3_v3v3(vec2, state->co, vec);
 -                      }
 +              if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) {
 +                      Paint *p;
  
 -                      add_v3_v3(vec, state->co);
 -                      copy_v3_v3(pdd->vd, vec); pdd->vd += 3;
 -                      copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
 +                      glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
 -                      vec[2] = 2.0f * pixsize;
 -                      vec[0] = vec[1] = 0.0f;
 -                      mul_qt_v3(state->rot, vec);
 -                      if (draw_as == PART_DRAW_AXIS) {
 -                              copy_v3_v3(vec2, state->co);
 -                      }
 -                      else {
 -                              sub_v3_v3v3(vec2, state->co, vec);
 -                      }
 +                      if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) {
 +                              GPUVertexAttribs gattribs;
 +                              float planes[4][4];
 +                              float (*fpl)[4] = NULL;
 +                              const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
  
 -                      add_v3_v3(vec, state->co);
 +                              if (ob->sculpt->partial_redraw) {
 +                                      if (ar->do_draw & RGN_DRAW_PARTIAL) {
 +                                              ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
 +                                              fpl = planes;
 +                                              ob->sculpt->partial_redraw = 0;
 +                                      }
 +                              }
  
 -                      copy_v3_v3(pdd->vd, vec); pdd->vd += 3;
 -                      copy_v3_v3(pdd->vd, vec2); pdd->vd += 3;
 -                      break;
 -              }
 -              case PART_DRAW_LINE:
 -              {
 -                      copy_v3_v3(vec, state->vel);
 -                      normalize_v3(vec);
 -                      if (draw & PART_DRAW_VEL_LENGTH)
 -                              mul_v3_fl(vec, len_v3(state->vel));
 -                      madd_v3_v3v3fl(pdd->vd, state->co, vec, -draw_line[0]); pdd->vd += 3;
 -                      madd_v3_v3v3fl(pdd->vd, state->co, vec,  draw_line[1]); pdd->vd += 3;
 -                      if (cd) {
 -                              cd[0] = cd[3] = ma_col[0];
 -                              cd[1] = cd[4] = ma_col[1];
 -                              cd[2] = cd[5] = ma_col[2];
 -                              pdd->cd += 6;
 -                      }
 -                      break;
 -              }
 -              case PART_DRAW_CIRC:
 -              {
 -                      drawcircball(GL_LINE_LOOP, state->co, pixsize, imat);
 -                      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;
 +                              GPU_object_material_bind(1, &gattribs);
 +                              dm->drawFacesSolid(dm, fpl, fast, NULL);
 +                              draw_loose = false;
                        }
 +                      else
 +                              dm->drawFacesGLSL(dm, GPU_object_material_bind);
  
 -                      copy_v3_v3(bb->vec, state->co);
 -                      copy_v3_v3(bb->vel, state->vel);
 -
 -                      psys_make_billboard(bb, xvec, yvec, zvec, bb_center);
 -                      
 -                      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);
 -                      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;
 -                      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)
 -{
 -      ParticleSettings *part = psys->part;
 -      float pixsize;
 +                      GPU_object_material_unbind();
  
 -      if (psys->parent)
 -              mul_m4_v3(psys->parent->obmat, state->co);
 +                      glFrontFace(GL_CCW);
  
 -      /* create actual particle data */
 -      if (draw_as == PART_DRAW_BB) {
 -              bb->offset[0] = part->bb_offset[0];
 -              bb->offset[1] = part->bb_offset[1];
 -              bb->size[0] = part->bb_size[0] * pa_size;
 -              if (part->bb_align == PART_BB_VEL) {
 -                      float pa_vel = len_v3(state->vel);
 -                      float head = part->bb_vel_head * pa_vel;
 -                      float tail = part->bb_vel_tail * pa_vel;
 -                      bb->size[1] = part->bb_size[1] * pa_size + head + tail;
 -                      /* use offset to adjust the particle center. this is relative to size, so need to divide! */
 -                      if (bb->size[1] > 0.0f)
 -                              bb->offset[1] += (head - tail) / bb->size[1];
 +                      if (draw_flags & DRAW_FACE_SELECT)
 +                              draw_mesh_face_select(rv3d, me, dm, false);
                }
                else {
 -                      bb->size[1] = part->bb_size[1] * pa_size;
 +                      draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags);
                }
 -              bb->tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
 -              bb->time = ct;
 -      }
 -
 -      pixsize = ED_view3d_pixel_size(rv3d, state->co) * pixsize_scale;
 -
 -      draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd);
 -}
 -/* unified drawing of all new particle systems draw types except dupli ob & group
 - * mostly tries to use vertex arrays for speed
 - *
 - * 1. check that everything is ok & updated
 - * 2. start initializing things
 - * 3. initialize according to draw type
 - * 4. allocate drawing data arrays
 - * 5. start filling the arrays
 - * 6. draw the arrays
 - * 7. clean up
 - */
 -static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d,
 -                                     Base *base, ParticleSystem *psys,
 -                                     const char ob_dt, const short dflag)
 -{
 -      Object *ob = base->object;
 -      ParticleEditSettings *pset = PE_settings(scene);
 -      ParticleSettings *part = psys->part;
 -      ParticleData *pars = psys->particles;
 -      ParticleData *pa;
 -      ParticleKey state, *states = NULL;
 -      ParticleBillboardData bb;
 -      ParticleSimulationData sim = {NULL};
 -      ParticleDrawData *pdd = psys->pdd;
 -      Material *ma;
 -      float vel[3], imat[4][4];
 -      float timestep, pixsize_scale = 1.0f, pa_size, r_tilt, r_length;
 -      float pa_time, pa_birthtime, pa_dietime, pa_health, intensity;
 -      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;
 -      GLint polygonmode[2];
 -      char numstr[32];
 -      unsigned char tcol[4] = {0, 0, 0, 255};
 -
 -/* 1. */
 -      if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering))
 -              return;
 -
 -      if (pars == NULL) return;
 -
 -      /* don't draw normal paths in edit mode */
 -      if (psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART) == 0)
 -              return;
 -
 -      if (part->draw_as == PART_DRAW_REND)
 -              draw_as = part->ren_as;
 -      else
 -              draw_as = part->draw_as;
 -
 -      if (draw_as == PART_DRAW_NOT)
 -              return;
  
 -      /* prepare curvemapping tables */
 -      if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve)
 -              curvemapping_changed_all(psys->part->clumpcurve);
 -      if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve)
 -              curvemapping_changed_all(psys->part->roughcurve);
 -
 -/* 2. */
 -      sim.scene = scene;
 -      sim.ob = ob;
 -      sim.psys = psys;
 -      sim.psmd = psys_get_modifier(ob, psys);
 -
 -      if (part->phystype == PART_PHYS_KEYED) {
 -              if (psys->flag & PSYS_KEYED) {
 -                      psys_count_keyed_targets(&sim);
 -                      if (psys->totkeyed == 0)
 -                              return;
 +              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};
  
 -      if (select) {
 -              select = false;
 -              if (psys_get_current(ob) == psys)
 -                      select = true;
 -      }
 -
 -      psys->flag |= PSYS_DRAWING;
 -
 -      if (part->type == PART_HAIR && !psys->childcache)
 -              totchild = 0;
 -      else
 -              totchild = psys->totchild * part->disp / 100;
 -
 -      ma = give_current_material(ob, part->omat);
 -
 -      if (v3d->zbuf) glDepthMask(1);
 -
 -      if ((ma) && (part->draw_col == PART_DRAW_COL_MAT)) {
 -              rgb_float_to_uchar(tcol, &(ma->r));
 -              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)) {
 -              float mat[4][4];
 -              mul_m4_m4m4(mat, ob->obmat, psys->imat);
 -              glMultMatrixf(mat);
 -      }
 +                              /* draw outline */
 +                              /* TODO: move this into a separate pass */
 +                              if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                                  ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                                  (base->flag & SELECT) &&
 +                                  (draw_wire == OBDRAW_WIRE_OFF) &&
 +                                  (ob->sculpt == NULL))
 +                              {
 +                                      draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT));
 +                              }
  
 -      /* needed for text display */
 -      invert_m4_m4(ob->imat, ob->obmat);
 +                              /* materials arent compatible with vertex colors */
 +                              GPU_end_object_materials();
  
 -      totpart = psys->totpart;
 +                              /* set default specular */
 +                              GPU_basic_shader_colors(NULL, specular, 35, 1.0f);
 +                              GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
  
 -      cfra = BKE_scene_frame_get(scene);
 +                              dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS);
  
 -      if (draw_as == PART_DRAW_PATH && psys->pathcache == NULL && psys->childcache == NULL)
 -              draw_as = PART_DRAW_DOT;
 +                              GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
 +                      }
 +              }
 +              else {
 +                      Paint *p;
  
 -/* 3. */
 -      glLineWidth(1.0f);
 +                      if ((v3d->flag & V3D_SELECT_OUTLINE) &&
 +                          ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) &&
 +                          (base->flag & SELECT) &&
 +                          (draw_wire == OBDRAW_WIRE_OFF) &&
 +                          (ob->sculpt == NULL))
 +                      {
 +                              /* TODO: move this into a separate pass */
 +                              draw_mesh_object_outline_new(v3d, rv3d, ob, dm, (ob == OBACT));
 +                      }
  
 -      switch (draw_as) {
 -              case PART_DRAW_DOT:
 -                      if (part->draw_size)
 -                              glPointSize(part->draw_size);
 -                      else
 -                              glPointSize(2.0);  /* default dot size */
 -                      break;
 -              case PART_DRAW_CIRC:
 -                      /* calculate view aligned matrix: */
 -                      copy_m4_m4(imat, rv3d->viewinv);
 -                      normalize_v3(imat[0]);
 -                      normalize_v3(imat[1]);
 -                      /* fall-through */
 -              case PART_DRAW_CROSS:
 -              case PART_DRAW_AXIS:
 -                      /* lets calculate the scale: */
 -                      
 -                      if (part->draw_size == 0.0)
 -                              pixsize_scale = 2.0f;
 -                      else
 -                              pixsize_scale = part->draw_size;
 +                      glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
  
 -                      if (draw_as == PART_DRAW_AXIS)
 -                              create_cdata = 1;
 -                      break;
 -              case PART_DRAW_OB:
 -                      if (part->dup_ob == NULL)
 -                              draw_as = PART_DRAW_DOT;
 -                      else
 -                              draw_as = 0;
 -                      break;
 -              case PART_DRAW_GR:
 -                      if (part->dup_group == NULL)
 -                              draw_as = PART_DRAW_DOT;
 -                      else
 -                              draw_as = 0;
 -                      break;
 -              case PART_DRAW_BB:
 -                      if (v3d->camera == NULL && part->bb_ob == NULL) {
 -                              printf("Billboards need an active camera or a target object!\n");
 +                      if (ob->sculpt && (p = BKE_paint_get_active(scene))) {
 +                              float planes[4][4];
 +                              float (*fpl)[4] = NULL;
 +                              const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
  
 -                              draw_as = part->draw_as = PART_DRAW_DOT;
 +                              if (ob->sculpt->partial_redraw) {
 +                                      if (ar->do_draw & RGN_DRAW_PARTIAL) {
 +                                              ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
 +                                              fpl = planes;
 +                                              ob->sculpt->partial_redraw = 0;
 +                                      }
 +                              }
  
 -                              if (part->draw_size)
 -                                      glPointSize(part->draw_size);
 -                              else
 -                                      glPointSize(2.0);  /* default dot size */
 +                              dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind);
                        }
 -                      else if (part->bb_ob)
 -                              bb.ob = part->bb_ob;
                        else
 -                              bb.ob = v3d->camera;
 +                              dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
  
 -                      bb.align = part->bb_align;
 -                      bb.anim = part->bb_anim;
 -                      bb.lock = part->draw & PART_DRAW_BB_LOCK;
 -                      break;
 -              case PART_DRAW_PATH:
 -                      break;
 -              case PART_DRAW_LINE:
 -                      need_v = 1;
 -                      break;
 -      }
 -      if (part->draw & PART_DRAW_SIZE && part->draw_as != PART_DRAW_CIRC) {
 -              copy_m4_m4(imat, rv3d->viewinv);
 -              normalize_v3(imat[0]);
 -              normalize_v3(imat[1]);
 -      }
 +                      glFrontFace(GL_CCW);
  
 -      if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) &&
 -          (part->draw_col > PART_DRAW_COL_MAT))
 -      {
 -              create_cdata = 1;
 -      }
 +                      GPU_object_material_unbind();
  
 -      if (!create_cdata && pdd && pdd->cdata) {
 -              MEM_freeN(pdd->cdata);
 -              pdd->cdata = pdd->cd = NULL;
 +                      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);
  
 -/* 4. */
 -      if (draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC) == 0) {
 -              int tot_vec_size = (totpart + totchild) * 3 * sizeof(float);
 -              int create_ndata = 0;
 -
 -              if (!pdd)
 -                      pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData");
 +              /* since we already draw wire as wp guide, don't draw over the top */
 +              draw_wire = OBDRAW_WIRE_OFF;
 +      }
  
 -              if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
 -                      tot_vec_size *= part->trail_count;
 -                      psys_make_temp_pointcache(ob, psys);
 -              }
 +      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. */
  
 -              switch (draw_as) {
 -                      case PART_DRAW_AXIS:
 -                      case PART_DRAW_CROSS:
 -                              tot_vec_size *= 6;
 -                              if (draw_as != PART_DRAW_CROSS)
 -                                      create_cdata = 1;
 -                              break;
 -                      case PART_DRAW_LINE:
 -                              tot_vec_size *= 2;
 -                              break;
 -                      case PART_DRAW_BB:
 -                              tot_vec_size *= 4;
 -                              create_ndata = 1;
 -                              break;
 +              if ((dflag & DRAW_CONSTCOLOR) == 0) {
 +                      /* TODO:
 +                       * Batch_UniformColor4ubv(ob_wire_col);
 +                       */
                }
  
 -              if (pdd->tot_vec_size != tot_vec_size)
 -                      psys_free_pdd(psys);
 +              /* 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;
 +              glColor3f(0.0f, 0.0f, 0.0f);
 +              glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
  
 -              if (!pdd->vdata)
 -                      pdd->vdata = MEM_callocN(tot_vec_size, "particle_vdata");
 -              if (create_cdata && !pdd->cdata)
 -                      pdd->cdata = MEM_callocN(tot_vec_size, "particle_cdata");
 -              if (create_ndata && !pdd->ndata)
 -                      pdd->ndata = MEM_callocN(tot_vec_size, "particle_ndata");
 +              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
  
 -              if (part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) {
 -                      if (!pdd->vedata)
 -                              pdd->vedata = MEM_callocN(2 * (totpart + totchild) * 3 * sizeof(float), "particle_vedata");
 +      dm->release(dm);
 +}
  
 -                      need_v = 1;
 -              }
 -              else if (pdd->vedata) {
 -                      /* velocity data not needed, so free it */
 -                      MEM_freeN(pdd->vedata);
 -                      pdd->vedata = NULL;
 -              }
 +static bool draw_mesh_object_new(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base,
 +                                 const char dt, const unsigned char ob_wire_col[4], const short dflag)
 +{
 +      Object *ob = base->object;
 +      Object *obedit = scene->obedit;
 +      Mesh *me = ob->data;
 +      BMEditMesh *em = me->edit_btmesh;
 +      bool do_alpha_after = false, drawlinked = false, retval = false;
  
 -              pdd->vd = pdd->vdata;
 -              pdd->ved = pdd->vedata;
 -              pdd->cd = pdd->cdata;
 -              pdd->nd = pdd->ndata;
 -              pdd->tot_vec_size = tot_vec_size;
 +      if (v3d->flag2 & V3D_RENDER_SHADOW) {
 +              /* TODO: handle shadow pass separately */
 +              return true;
        }
 -      else if (psys->pdd) {
 -              psys_free_pdd(psys);
 -              MEM_freeN(psys->pdd);
 -              pdd = psys->pdd = NULL;
 +      
 +      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;
        }
  
 -      if (pdd) {
 -              pdd->ma_col = ma_col;
 +      /* 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);
        }
  
 -      psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
 +      if (ob == obedit || drawlinked) {
 +              DerivedMesh *finalDM, *cageDM;
  
 -      /* circles don't use drawdata, so have to add a special case here */
 -      if ((pdd || draw_as == PART_DRAW_CIRC) && draw_as != PART_DRAW_PATH) {
 -              /* 5. */
 -              if (pdd && (pdd->flag & PARTICLE_DRAW_DATA_UPDATED) &&
 -                  (pdd->vedata || part->draw & (PART_DRAW_SIZE | PART_DRAW_NUM | PART_DRAW_HEALTH)) == 0)
 -              {
 -                      totpoint = pdd->totpoint; /* draw data is up to date */
 +              if (obedit != ob) {
 +                      /* linked to the edit object */
 +                      finalDM = cageDM = editbmesh_get_derived_base(
 +                              ob, em, scene->customdata_mask);
                }
                else {
 -                      for (a = 0, pa = pars; a < totpart + totchild; a++, pa++) {
 -                              /* setup per particle individual stuff */
 -                              if (a < totpart) {
 -                                      if (totchild && (part->draw & PART_DRAW_PARENT) == 0) continue;
 -                                      if (pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue;
 -
 -                                      pa_time = (cfra - pa->time) / pa->lifetime;
 -                                      pa_birthtime = pa->time;
 -                                      pa_dietime = pa->dietime;
 -                                      pa_size = pa->size;
 -                                      if (part->phystype == PART_PHYS_BOIDS)
 -                                              pa_health = pa->boid->data.health;
 -                                      else
 -                                              pa_health = -1.0;
 -
 -                                      r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f);
 -                                      r_length = psys_frand(psys, a + 22);
 -
 -                                      if (part->draw_col > PART_DRAW_COL_MAT) {
 -                                              switch (part->draw_col) {
 -                                                      case PART_DRAW_COL_VEL:
 -                                                              intensity = len_v3(pa->state.vel) / part->color_vec_max;
 -                                                              break;
 -                                                      case PART_DRAW_COL_ACC:
 -                                                              intensity = len_v3v3(pa->state.vel, pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * part->color_vec_max);
 -                                                              break;
 -                                                      default:
 -                                                              intensity = 1.0f; /* should never happen */
 -                                                              BLI_assert(0);
 -                                                              break;
 -                                              }
 -                                              CLAMP(intensity, 0.0f, 1.0f);
 -                                              weight_to_rgb(ma_col, intensity);
 -                                      }
 -                              }
 -                              else {
 -                                      ChildParticle *cpa = &psys->child[a - totpart];
 +                      cageDM = editbmesh_get_derived_cage_and_final(
 +                              scene, ob, em, scene->customdata_mask,
 +                              &finalDM);
 +              }
  
 -                                      pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
 -                                      pa_size = psys_get_child_size(psys, cpa, cfra, NULL);
 +              const bool use_material = solid && ((me->drawflag & ME_DRAWEIGHT) == 0);
  
 -                                      pa_health = -1.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
  
 -                                      r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f);
 -                                      r_length = psys_frand(psys, a + 22);
 -                              }
 +              if (use_material) {
 +                      DM_update_materials(finalDM, ob);
 +                      if (cageDM != finalDM) {
 +                              DM_update_materials(cageDM, ob);
 +                      }
  
 -                              drawn = 0;
 -                              if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
 -                                      float length = part->path_end * (1.0f - part->randlength * r_length);
 -                                      int trail_count = part->trail_count * (1.0f - part->randlength * r_length);
 -                                      float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length;
 -                                      float dt = length / (trail_count ? (float)trail_count : 1.0f);
 -                                      int i = 0;
 +                      const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
  
 -                                      ct += dt;
 -                                      for (i = 0; i < trail_count; i++, ct += dt) {
 +                      GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
 +              }
  
 -                                              if (part->draw & PART_ABS_PATH_TIME) {
 -                                                      if (ct < pa_birthtime || ct > pa_dietime)
 -                                                              continue;
 -                                              }
 -                                              else if (ct < 0.0f || ct > 1.0f)
 -                                                      continue;
 +              draw_em_fancy_new(scene, ar, v3d, ob, em, cageDM, finalDM, dt);
  
 -                                              state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime));
 -                                              psys_get_particle_on_path(&sim, a, &state, need_v);
 +              if (use_material) {
 +                      GPU_end_object_materials();
 +              }
  
 -                                              draw_particle_data(psys, rv3d,
 -                                                                 &state, draw_as, imat, &bb, psys->pdd,
 -                                                                 ct, pa_size, r_tilt, pixsize_scale);
 +              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, ob, v3d, dt);
  
 -                                              totpoint++;
 -                                              drawn = 1;
 -                                      }
 +                              if (dt == OB_SOLID || glsl) {
 +                                      const bool check_alpha = check_alpha_pass(base);
 +                                      GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
 +                                                                 (check_alpha) ? &do_alpha_after : NULL);
                                }
 -                              else {
 -                                      state.time = cfra;
 -                                      if (psys_get_particle_state(&sim, a, &state, 0)) {
 +                      }
  
 -                                              draw_particle_data(psys, rv3d,
 -                                                                 &state, draw_as, imat, &bb, psys->pdd,
 -                                                                 pa_time, pa_size, r_tilt, pixsize_scale);
 +                      const bool other_obedit = obedit && (obedit != ob);
  
 -                                              totpoint++;
 -                                              drawn = 1;
 -                                      }
 -                              }
 +                      draw_mesh_fancy_new(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag, other_obedit);
  
 -                              if (drawn) {
 -                                      /* additional things to draw for each particle
 -                                       * (velocity, size and number) */
 -                                      if ((part->draw & PART_DRAW_VEL) && pdd && pdd->vedata) {
 -                                              copy_v3_v3(pdd->ved, state.co);
 -                                              pdd->ved += 3;
 -                                              mul_v3_v3fl(vel, state.vel, timestep);
 -                                              add_v3_v3v3(pdd->ved, state.co, vel);
 -                                              pdd->ved += 3;
 -
 -                                              totve++;
 -                                      }
 +                      GPU_end_object_materials();
  
 -                                      if (part->draw & PART_DRAW_SIZE) {
 -                                              setlinestyle(3);
 -                                              drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
 -                                              setlinestyle(0);
 -                                      }
 +                      if (me->totvert == 0) retval = true;
 +              }
 +      }
  
 +      if (cullBackface)
 +              glDisable(GL_CULL_FACE);
  
 -                                      if ((part->draw & PART_DRAW_NUM || part->draw & PART_DRAW_HEALTH) &&
 -                                          (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0)
 -                                      {
 -                                              size_t numstr_len;
 -                                              float vec_txt[3];
 -                                              char *val_pos = numstr;
 -                                              numstr[0] = '\0';
 -
 -                                              if (part->draw & PART_DRAW_NUM) {
 -                                                      if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
 -                                                              numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health);
 -                                                      }
 -                                                      else {
 -                                                              numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d", a);
 -                                                      }
 -                                              }
 -                                              else {
 -                                                      if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) {
 -                                                              numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%.2f", pa_health);
 -                                                      }
 -                                              }
 +      return retval;
 +}
  
 -                                              if (numstr[0]) {
 -                                                      /* in path drawing state.co is the end point
 -                                                       * use worldspace because object matrix is already applied */
 -                                                      mul_v3_m4v3(vec_txt, ob->imat, state.co);
 -                                                      view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
 -                                                                                  10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol);
 -                                              }
 -                                      }
 -                              }
 -                      }
 -              }
 -      }
 -/* 6. */
 +/* ************** DRAW DISPLIST ****************** */
  
 -      glGetIntegerv(GL_POLYGON_MODE, polygonmode);
 +
 +/**
 + * \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)
 +{
 +      if (dlbase == NULL) return true;
 +      
        glEnableClientState(GL_VERTEX_ARRAY);
 +      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  
 -      if (draw_as == PART_DRAW_PATH) {
 -              ParticleCacheKey **cache, *path;
 -              float *cdata2 = NULL;
 +      for (DispList *dl = dlbase->first; dl; dl = dl->next) {
 +              if (dl->parts == 0 || dl->nr == 0) {
 +                      continue;
 +              }
  
 -              /* setup gl flags */
 -              if (1) { //ob_dt > OB_WIRE) {
 -                      glEnableClientState(GL_NORMAL_ARRAY);
 +              if ((dl_type_mask & (1 << dl->type)) == 0) {
 +                      continue;
 +              }
 +              
 +              const float *data = dl->verts;
 +              int parts;
  
 -                      if ((dflag & DRAW_CONSTCOLOR) == 0) {
 -                              if (part->draw_col == PART_DRAW_COL_MAT)
 -                                      glEnableClientState(GL_COLOR_ARRAY);
 -                      }
 +              switch (dl->type) {
 +                      case DL_SEGM:
  
 -                      // XXX test
 -                      GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
 -                      GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
 -              }
 +                              glVertexPointer(3, GL_FLOAT, 0, data);
  
 -              if (totchild && (part->draw & PART_DRAW_PARENT) == 0)
 -                      totpart = 0;
 -              else if (psys->pathcache == NULL)
 -                      totpart = 0;
 +                              for (parts = 0; parts < dl->parts; parts++)
 +                                      glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
 +                              
 +                              break;
 +                      case DL_POLY:
  
 -              /* draw actual/parent particles */
 -              cache = psys->pathcache;
 -              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);
 +                              glVertexPointer(3, GL_FLOAT, 0, data);
  
 -                              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);
 -                                              }
 -                                      }
 -                              }
 +                              for (parts = 0; parts < dl->parts; parts++)
 +                                      glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr);
  
 -                              glDrawAr