Object Overlay: Add dupli fast path
authorClément Foucault <foucault.clem@gmail.com>
Tue, 7 May 2019 20:09:28 +0000 (22:09 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Wed, 8 May 2019 15:52:48 +0000 (17:52 +0200)
source/blender/draw/modes/object_mode.c

index ee2c660..970ee02 100644 (file)
@@ -316,6 +316,13 @@ typedef struct OBJECT_PrivateData {
   bool xray_enabled_and_not_wire;
 } OBJECT_PrivateData; /* Transient data */
 
+typedef struct OBJECT_DupliData {
+  DRWShadingGroup *outline_shgrp;
+  GPUBatch *outline_geom;
+  DRWShadingGroup *extra_shgrp;
+  GPUBatch *extra_geom;
+} OBJECT_DupliData;
+
 static struct {
   /* Instance Data format */
   struct GPUVertFormat *particle_format;
@@ -3096,6 +3103,24 @@ static void OBJECT_gpencil_color_names(Object *ob, struct DRWTextStore *dt, ucha
   }
 }
 
+BLI_INLINE OBJECT_DupliData *OBJECT_duplidata_get(Object *ob, void *vedata, bool *init)
+{
+  OBJECT_DupliData **dupli_data = (OBJECT_DupliData **)DRW_duplidata_get(vedata);
+  *init = false;
+  if (!ELEM(ob->type, OB_MESH, OB_SURF, OB_LATTICE, OB_CURVE, OB_FONT)) {
+    return NULL;
+  }
+
+  if (dupli_data) {
+    if (*dupli_data == NULL) {
+      *dupli_data = MEM_callocN(sizeof(OBJECT_DupliData), "OBJECT_DupliData");
+      *init = true;
+    }
+    return *dupli_data;
+  }
+  return NULL;
+}
+
 static void OBJECT_cache_populate(void *vedata, Object *ob)
 {
   OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
@@ -3132,10 +3157,15 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
        /* Show if this is the camera we're looking through since it's useful for selecting. */
        (((rv3d->persp == RV3D_CAMOB) && ((ID *)v3d->camera == ob->id.orig_id)) == 0));
 
+  /* Fast path for duplis. */
+  bool init_duplidata;
+  OBJECT_DupliData *dupli_data = OBJECT_duplidata_get(ob, vedata, &init_duplidata);
+
   if (do_outlines) {
     if (!BKE_object_is_in_editmode(ob) &&
         !((ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT))) {
       struct GPUBatch *geom;
+      DRWShadingGroup *shgroup = NULL;
 
       /* This fixes only the biggest case which is a plane in ortho view. */
       int flat_axis = 0;
@@ -3143,185 +3173,211 @@ static void OBJECT_cache_populate(void *vedata, Object *ob)
                                               DRW_object_is_flat(ob, &flat_axis) &&
                                               DRW_object_axis_orthogonal_to_view(ob, flat_axis));
 
-      if (stl->g_data->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
-        geom = DRW_cache_object_edge_detection_get(ob, NULL);
+      if (dupli_data && !init_duplidata) {
+        geom = dupli_data->outline_geom;
+        shgroup = dupli_data->outline_shgrp;
       }
       else {
-        geom = DRW_cache_object_surface_get(ob);
-      }
+        if (stl->g_data->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
+          geom = DRW_cache_object_edge_detection_get(ob, NULL);
+        }
+        else {
+          geom = DRW_cache_object_surface_get(ob);
+        }
 
-      if (geom) {
-        theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
-        DRWShadingGroup *shgroup = shgroup_theme_id_to_outline_or_null(
-            stl, theme_id, ob->base_flag);
-        if (shgroup != NULL) {
-          DRW_shgroup_call_object_add(shgroup, geom, ob);
+        if (geom) {
+          theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+          shgroup = shgroup_theme_id_to_outline_or_null(stl, theme_id, ob->base_flag);
         }
       }
-    }
-  }
 
-  switch (ob->type) {
-    case OB_MESH: {
-      if (hide_object_extra) {
-        break;
+      if (shgroup && geom) {
+        DRW_shgroup_call_object_add(shgroup, geom, ob);
       }
-      Mesh *me = ob->data;
-      if (!is_edit_mode && me->totedge == 0) {
-        struct GPUBatch *geom = DRW_cache_mesh_all_verts_get(ob);
-        if (geom) {
-          if (theme_id == TH_UNDEFINED) {
-            theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
-          }
-          DRWShadingGroup *shgroup = shgroup_theme_id_to_point(sgl, theme_id, ob->base_flag);
-          DRW_shgroup_call_object_add(shgroup, geom, ob);
-        }
+
+      if (init_duplidata) {
+        dupli_data->outline_shgrp = shgroup;
+        dupli_data->outline_geom = geom;
       }
-      else {
-        bool has_edit_mesh_cage = false;
-        /* TODO: Should be its own function. */
-        if (is_edit_mode) {
-          BMEditMesh *embm = me->edit_mesh;
-          has_edit_mesh_cage = embm->mesh_eval_cage &&
-                               (embm->mesh_eval_cage != embm->mesh_eval_final);
+    }
+  }
+
+  if (dupli_data && !init_duplidata) {
+    if (dupli_data->extra_shgrp && dupli_data->extra_geom) {
+      DRW_shgroup_call_object_add(dupli_data->extra_shgrp, dupli_data->extra_geom, ob);
+    }
+  }
+  else {
+    struct GPUBatch *geom = NULL;
+    DRWShadingGroup *shgroup = NULL;
+    switch (ob->type) {
+      case OB_MESH: {
+        if (hide_object_extra) {
+          break;
         }
-        if ((!is_edit_mode && me->totedge > 0) || has_edit_mesh_cage) {
-          struct GPUBatch *geom = DRW_cache_mesh_loose_edges_get(ob);
+        Mesh *me = ob->data;
+        if (!is_edit_mode && me->totedge == 0) {
+          geom = DRW_cache_mesh_all_verts_get(ob);
           if (geom) {
             if (theme_id == TH_UNDEFINED) {
               theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
             }
-            DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
+            shgroup = shgroup_theme_id_to_point(sgl, theme_id, ob->base_flag);
             DRW_shgroup_call_object_add(shgroup, geom, ob);
           }
         }
-      }
-      break;
-    }
-    case OB_SURF: {
-      if (hide_object_extra) {
-        break;
-      }
-      struct GPUBatch *geom = DRW_cache_surf_edge_wire_get(ob);
-      if (geom == NULL) {
+        else {
+          bool has_edit_mesh_cage = false;
+          /* TODO: Should be its own function. */
+          if (is_edit_mode) {
+            BMEditMesh *embm = me->edit_mesh;
+            has_edit_mesh_cage = embm->mesh_eval_cage &&
+                                 (embm->mesh_eval_cage != embm->mesh_eval_final);
+          }
+          if ((!is_edit_mode && me->totedge > 0) || has_edit_mesh_cage) {
+            geom = DRW_cache_mesh_loose_edges_get(ob);
+            if (geom) {
+              if (theme_id == TH_UNDEFINED) {
+                theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+              }
+              shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
+              DRW_shgroup_call_object_add(shgroup, geom, ob);
+            }
+          }
+        }
         break;
       }
-      if (theme_id == TH_UNDEFINED) {
-        theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
-      }
-      DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
-      DRW_shgroup_call_object_add(shgroup, geom, ob);
-      break;
-    }
-    case OB_LATTICE: {
-      if (!is_edit_mode) {
+      case OB_SURF: {
         if (hide_object_extra) {
           break;
         }
-        struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false);
-        if (theme_id == TH_UNDEFINED) {
-          theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
-        }
-
-        DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
-        DRW_shgroup_call_object_add(shgroup, geom, ob);
-      }
-      break;
-    }
-    case OB_CURVE: {
-      if (!is_edit_mode) {
-        if (hide_object_extra) {
+        geom = DRW_cache_surf_edge_wire_get(ob);
+        if (geom == NULL) {
           break;
         }
-        struct GPUBatch *geom = DRW_cache_curve_edge_wire_get(ob);
         if (theme_id == TH_UNDEFINED) {
           theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
         }
-        DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
+        shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
         DRW_shgroup_call_object_add(shgroup, geom, ob);
-      }
-      break;
-    }
-    case OB_MBALL: {
-      if (!is_edit_mode) {
-        DRW_shgroup_mball_handles(sgl, ob, view_layer);
-      }
-      break;
-    }
-    case OB_LAMP:
-      if (hide_object_extra) {
         break;
       }
-      DRW_shgroup_light(sgl, ob, view_layer);
-      break;
-    case OB_CAMERA:
-      if (hide_object_extra) {
+      case OB_LATTICE: {
+        if (!is_edit_mode) {
+          if (hide_object_extra) {
+            break;
+          }
+          geom = DRW_cache_lattice_wire_get(ob, false);
+          if (theme_id == TH_UNDEFINED) {
+            theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+          }
+
+          shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
+          DRW_shgroup_call_object_add(shgroup, geom, ob);
+        }
         break;
       }
-      DRW_shgroup_camera(sgl, ob, view_layer);
-      break;
-    case OB_EMPTY:
-      if (hide_object_extra) {
+      case OB_CURVE: {
+        if (!is_edit_mode) {
+          if (hide_object_extra) {
+            break;
+          }
+          geom = DRW_cache_curve_edge_wire_get(ob);
+          if (theme_id == TH_UNDEFINED) {
+            theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+          }
+          shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
+          DRW_shgroup_call_object_add(shgroup, geom, ob);
+        }
         break;
       }
-      DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg);
-      break;
-    case OB_SPEAKER:
-      if (hide_object_extra) {
+      case OB_MBALL: {
+        if (!is_edit_mode) {
+          DRW_shgroup_mball_handles(sgl, ob, view_layer);
+        }
         break;
       }
-      DRW_shgroup_speaker(sgl, ob, view_layer);
-      break;
-    case OB_LIGHTPROBE:
-      if (hide_object_extra) {
+      case OB_LAMP:
+        if (hide_object_extra) {
+          break;
+        }
+        DRW_shgroup_light(sgl, ob, view_layer);
         break;
-      }
-      DRW_shgroup_lightprobe(sh_data, stl, psl, ob, view_layer);
-      break;
-    case OB_ARMATURE: {
-      if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) ||
-          ((ob->dt < OB_WIRE) && !DRW_state_is_select())) {
+      case OB_CAMERA:
+        if (hide_object_extra) {
+          break;
+        }
+        DRW_shgroup_camera(sgl, ob, view_layer);
         break;
-      }
-      bArmature *arm = ob->data;
-      if (arm->edbo == NULL) {
-        if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) {
-          bool is_wire = (v3d->shading.type == OB_WIRE) || (ob->dt <= OB_WIRE) ||
-                         XRAY_FLAG_ENABLED(v3d);
-          DRWArmaturePasses passes = {
-              .bone_solid = (is_wire) ? NULL : sgl->bone_solid,
-              .bone_outline = sgl->bone_outline,
-              .bone_wire = sgl->bone_wire,
-              .bone_envelope = sgl->bone_envelope,
-              .bone_axes = sgl->bone_axes,
-              .relationship_lines = NULL, /* Don't draw relationship lines */
-              .custom_shapes = stl->g_data->custom_shapes,
-          };
-          DRW_shgroup_armature_object(ob, view_layer, passes, is_wire);
+      case OB_EMPTY:
+        if (hide_object_extra) {
+          break;
+        }
+        DRW_shgroup_empty(sh_data, sgl, ob, view_layer, rv3d, draw_ctx->sh_cfg);
+        break;
+      case OB_SPEAKER:
+        if (hide_object_extra) {
+          break;
+        }
+        DRW_shgroup_speaker(sgl, ob, view_layer);
+        break;
+      case OB_LIGHTPROBE:
+        if (hide_object_extra) {
+          break;
+        }
+        DRW_shgroup_lightprobe(sh_data, stl, psl, ob, view_layer);
+        break;
+      case OB_ARMATURE: {
+        if ((v3d->flag2 & V3D_HIDE_OVERLAYS) || (v3d->overlay.flag & V3D_OVERLAY_HIDE_BONES) ||
+            ((ob->dt < OB_WIRE) && !DRW_state_is_select())) {
+          break;
+        }
+        bArmature *arm = ob->data;
+        if (arm->edbo == NULL) {
+          if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+            bool is_wire = (v3d->shading.type == OB_WIRE) || (ob->dt <= OB_WIRE) ||
+                           XRAY_FLAG_ENABLED(v3d);
+            DRWArmaturePasses passes = {
+                .bone_solid = (is_wire) ? NULL : sgl->bone_solid,
+                .bone_outline = sgl->bone_outline,
+                .bone_wire = sgl->bone_wire,
+                .bone_envelope = sgl->bone_envelope,
+                .bone_axes = sgl->bone_axes,
+                .relationship_lines = NULL, /* Don't draw relationship lines */
+                .custom_shapes = stl->g_data->custom_shapes,
+            };
+            DRW_shgroup_armature_object(ob, view_layer, passes, is_wire);
+          }
         }
-      }
-      break;
-    }
-    case OB_FONT: {
-      if (hide_object_extra) {
         break;
       }
-      Curve *cu = (Curve *)ob->data;
-      bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f;
-      if (!has_surface) {
-        struct GPUBatch *geom = DRW_cache_text_edge_wire_get(ob);
-        if (geom) {
-          if (theme_id == TH_UNDEFINED) {
-            theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+      case OB_FONT: {
+        if (hide_object_extra) {
+          break;
+        }
+        Curve *cu = (Curve *)ob->data;
+        bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f ||
+                           cu->ext2 != 0.0f;
+        if (!has_surface) {
+          geom = DRW_cache_text_edge_wire_get(ob);
+          if (geom) {
+            if (theme_id == TH_UNDEFINED) {
+              theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+            }
+            shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
+            DRW_shgroup_call_object_add(shgroup, geom, ob);
           }
-          DRWShadingGroup *shgroup = shgroup_theme_id_to_wire(sgl, theme_id, ob->base_flag);
-          DRW_shgroup_call_object_add(shgroup, geom, ob);
         }
+        break;
       }
-      break;
+      default:
+        break;
+    }
+
+    if (init_duplidata) {
+      dupli_data->extra_shgrp = shgroup;
+      dupli_data->extra_geom = geom;
     }
-    default:
-      break;
   }
 
   if (ob->pd && ob->pd->forcefield) {