Overlay Engine: Refactor & Cleanup
authorClément Foucault <foucault.clem@gmail.com>
Mon, 2 Dec 2019 00:40:58 +0000 (01:40 +0100)
committerClément Foucault <foucault.clem@gmail.com>
Mon, 2 Dec 2019 12:15:52 +0000 (13:15 +0100)
This is the unification of all overlays into one overlay engine as described in T65347.

I went over all the code making it more future proof with less hacks and removing old / not relevent parts.

Goals / Acheivements:
- Remove internal shader usage (only drw shaders)
- Remove viewportSize and viewportSizeInv and put them in gloabl ubo
- Fixed some drawing issues: Missing probe option and Missing Alt+B clipping of some shader
- Remove old (legacy) shaders dependancy (not using view UBO).
- Less shader variation (less compilation time at first load and less patching needed for vulkan)
- removed some geom shaders when I could
- Remove static e_data (except shaders storage where it is OK)
- Clear the way to fix some anoying limitations (dithered transparency, background image compositing etc...)
- Wireframe drawing now uses the same batching capabilities as workbench & eevee (indirect drawing).
- Reduced complexity, removed ~3000 Lines of code in draw (also removed a lot of unused shader in GPU).
- Post AA to avoid complexity and cost of MSAA.

Remaining issues:
- ~~Armature edits, overlay toggles, (... others?) are not refreshing viewport after AA is complete~~
- FXAA is not the best for wires, maybe investigate SMAA
- Maybe do something more temporally stable for AA.
- ~~Paint overlays are not working with AA.~~
- ~~infront objects are difficult to select.~~
- ~~the infront wires sometimes goes through they solid counterpart (missing clear maybe?) (toggle overlays on-off when using infront+wireframe overlay in solid shading)~~

Note: I made some decision to change slightly the appearance of some objects to simplify their drawing. Namely the empty arrows end (which is now hollow/wire) and distance points of the cameras/spots being done by lines.

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D6296

217 files changed:
release/scripts/startup/bl_ui/properties_data_lightprobe.py
source/blender/blenfont/intern/blf_font.c
source/blender/draw/CMakeLists.txt
source/blender/draw/DRW_engine.h
source/blender/draw/engines/basic/basic_engine.c
source/blender/draw/engines/gpencil/gpencil_engine.c
source/blender/draw/engines/gpencil/gpencil_engine.h
source/blender/draw/engines/gpencil/gpencil_render.c
source/blender/draw/engines/overlay/overlay_antialiasing.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_armature.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_edit_curve.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_edit_mesh.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_edit_text.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_engine.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_engine.h [moved from source/blender/draw/modes/edit_mesh_mode_intern.h with 60% similarity]
source/blender/draw/engines/overlay/overlay_extra.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_facing.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_grid.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_image.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_lattice.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_metaball.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_motion_path.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_outline.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_paint.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_particle.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_private.h [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_sculpt.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_shader.c [new file with mode: 0644]
source/blender/draw/engines/overlay/overlay_wireframe.c [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl [moved from source/blender/draw/modes/shaders/armature_dof_vert.glsl with 62% similarity]
source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl [moved from source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl with 93% similarity]
source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl [moved from source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl with 93% similarity]
source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl [moved from source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl with 96% similarity]
source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl [moved from source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl with 71% similarity]
source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl [moved from source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl [moved from source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl with 72% similarity]
source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl [moved from source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl with 85% similarity]
source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl [moved from source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl with 95% similarity]
source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl [moved from source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl with 88% similarity]
source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl [moved from source/blender/draw/modes/shaders/armature_stick_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl [moved from source/blender/draw/modes/shaders/armature_stick_vert.glsl with 89% similarity]
source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl [moved from source/blender/draw/modes/shaders/pose_selection_vert.glsl with 84% similarity]
source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl [moved from source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl with 94% similarity]
source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl [moved from source/blender/draw/modes/shaders/edit_curve_overlay_handle_vert.glsl with 92% similarity]
source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl [moved from source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl with 90% similarity]
source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl [moved from source/blender/draw/modes/shaders/edit_curve_overlay_normals_vert.glsl with 89% similarity]
source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_frag.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/edit_mesh_facefill_vert.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl with 86% similarity]
source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_geom.glsl with 93% similarity]
source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl [moved from source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl with 82% similarity]
source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/extra_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl [moved from source/blender/draw/modes/shaders/object_loose_points_frag.glsl with 77% similarity]
source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/extra_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/facing_frag.glsl [moved from source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/facing_vert.glsl [moved from source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/grid_frag.glsl [moved from source/blender/draw/modes/shaders/object_grid_frag.glsl with 99% similarity]
source/blender/draw/engines/overlay/shaders/grid_vert.glsl [moved from source/blender/draw/modes/shaders/object_grid_vert.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/image_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/image_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl [moved from source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl with 61% similarity]
source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl [moved from source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl with 82% similarity]
source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl [moved from source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl with 72% similarity]
source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl [moved from source/blender/draw/modes/shaders/object_outline_detect_frag.glsl with 98% similarity]
source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl [moved from source/blender/draw/modes/shaders/object_outline_expand_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/outline_lightprobe_grid_vert.glsl [moved from source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl [moved from source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl [moved from source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl [moved from source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl [moved from source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl [moved from source/blender/draw/modes/shaders/paint_face_selection_vert.glsl with 63% similarity]
source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl [moved from source/blender/draw/modes/shaders/paint_texture_vert.glsl with 76% similarity]
source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl [moved from source/blender/draw/modes/shaders/paint_vertex_frag.glsl with 56% similarity]
source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl [moved from source/blender/draw/modes/shaders/paint_vertex_vert.glsl with 92% similarity]
source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl [moved from source/blender/draw/modes/shaders/paint_weight_frag.glsl with 91% similarity]
source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl [moved from source/blender/draw/modes/shaders/paint_weight_vert.glsl with 91% similarity]
source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl [moved from source/blender/draw/modes/shaders/paint_wire_vert.glsl with 51% similarity]
source/blender/draw/engines/overlay/shaders/particle_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/particle_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl [moved from source/blender/draw/modes/shaders/sculpt_mask_vert.glsl with 64% similarity]
source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl [moved from source/blender/draw/modes/shaders/volume_velocity_vert.glsl with 100% similarity]
source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl [new file with mode: 0644]
source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl [moved from source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl with 78% similarity]
source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl [new file with mode: 0644]
source/blender/draw/engines/select/select_engine.c
source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl
source/blender/draw/engines/workbench/workbench_deferred.c
source/blender/draw/intern/DRW_render.h
source/blender/draw/intern/draw_anim_viz.c [deleted file]
source/blender/draw/intern/draw_armature.c [deleted file]
source/blender/draw/intern/draw_cache.c
source/blender/draw/intern/draw_cache.h
source/blender/draw/intern/draw_cache_extract_mesh.c
source/blender/draw/intern/draw_cache_impl_lattice.c
source/blender/draw/intern/draw_cache_impl_mesh.c
source/blender/draw/intern/draw_cache_impl_particles.c
source/blender/draw/intern/draw_common.c
source/blender/draw/intern/draw_common.h
source/blender/draw/intern/draw_instance_data.c
source/blender/draw/intern/draw_instance_data.h
source/blender/draw/intern/draw_manager.c
source/blender/draw/intern/draw_manager.h
source/blender/draw/intern/draw_manager_data.c
source/blender/draw/intern/draw_manager_exec.c
source/blender/draw/intern/draw_manager_text.c
source/blender/draw/intern/draw_manager_text.h
source/blender/draw/intern/shaders/common_colormanagement_lib.glsl [moved from source/blender/draw/modes/shaders/common_colormanagement_lib.glsl with 100% similarity]
source/blender/draw/intern/shaders/common_fullscreen_vert.glsl [moved from source/blender/draw/modes/shaders/common_fullscreen_vert.glsl with 100% similarity]
source/blender/draw/intern/shaders/common_fxaa_lib.glsl [moved from source/blender/draw/modes/shaders/common_fxaa_lib.glsl with 99% similarity]
source/blender/draw/intern/shaders/common_globals_lib.glsl [moved from source/blender/draw/modes/shaders/common_globals_lib.glsl with 87% similarity]
source/blender/draw/intern/shaders/common_hair_lib.glsl [moved from source/blender/draw/modes/shaders/common_hair_lib.glsl with 100% similarity]
source/blender/draw/intern/shaders/common_hair_refine_vert.glsl [moved from source/blender/draw/modes/shaders/common_hair_refine_vert.glsl with 100% similarity]
source/blender/draw/intern/shaders/common_smaa_lib.glsl [new file with mode: 0644]
source/blender/draw/intern/shaders/common_view_lib.glsl [moved from source/blender/draw/modes/shaders/common_view_lib.glsl with 74% similarity]
source/blender/draw/intern/smaa_textures.h [new file with mode: 0644]
source/blender/draw/modes/draw_mode_engines.h [deleted file]
source/blender/draw/modes/edit_armature_mode.c [deleted file]
source/blender/draw/modes/edit_curve_mode.c [deleted file]
source/blender/draw/modes/edit_lattice_mode.c [deleted file]
source/blender/draw/modes/edit_mesh_mode.c [deleted file]
source/blender/draw/modes/edit_mesh_mode_text.c [deleted file]
source/blender/draw/modes/edit_metaball_mode.c [deleted file]
source/blender/draw/modes/edit_text_mode.c [deleted file]
source/blender/draw/modes/object_mode.c [deleted file]
source/blender/draw/modes/overlay_mode.c [deleted file]
source/blender/draw/modes/paint_texture_mode.c [deleted file]
source/blender/draw/modes/paint_vertex_mode.c [deleted file]
source/blender/draw/modes/particle_mode.c [deleted file]
source/blender/draw/modes/pose_mode.c [deleted file]
source/blender/draw/modes/sculpt_mode.c [deleted file]
source/blender/draw/modes/shaders/armature_axes_vert.glsl [deleted file]
source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl [deleted file]
source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl [deleted file]
source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl [deleted file]
source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl [deleted file]
source/blender/draw/modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl [deleted file]
source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl [deleted file]
source/blender/draw/modes/shaders/edit_mesh_skin_root_vert.glsl [deleted file]
source/blender/draw/modes/shaders/edit_normals_geom.glsl [deleted file]
source/blender/draw/modes/shaders/edit_normals_vert.glsl [deleted file]
source/blender/draw/modes/shaders/object_camera_image_frag.glsl [deleted file]
source/blender/draw/modes/shaders/object_camera_image_vert.glsl [deleted file]
source/blender/draw/modes/shaders/object_color_axes_vert.glsl [deleted file]
source/blender/draw/modes/shaders/object_empty_axes_vert.glsl [deleted file]
source/blender/draw/modes/shaders/object_empty_image_frag.glsl [deleted file]
source/blender/draw/modes/shaders/object_empty_image_vert.glsl [deleted file]
source/blender/draw/modes/shaders/object_mball_handles_vert.glsl [deleted file]
source/blender/draw/modes/shaders/object_particle_dot_frag.glsl [deleted file]
source/blender/draw/modes/shaders/object_particle_dot_vert.glsl [deleted file]
source/blender/draw/modes/shaders/object_particle_prim_vert.glsl [deleted file]
source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl [deleted file]
source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl [deleted file]
source/blender/draw/modes/shaders/paint_face_vert.glsl [deleted file]
source/blender/draw/modes/shaders/paint_texture_frag.glsl [deleted file]
source/blender/draw/modes/shaders/paint_vert_frag.glsl [deleted file]
source/blender/draw/modes/shaders/paint_wire_frag.glsl [deleted file]
source/blender/draw/modes/shaders/particle_strand_frag.glsl [deleted file]
source/blender/draw/modes/shaders/particle_strand_vert.glsl [deleted file]
source/blender/editors/armature/armature_add.c
source/blender/editors/armature/armature_edit.c
source/blender/editors/armature/armature_relations.c
source/blender/editors/armature/armature_select.c
source/blender/editors/space_sequencer/sequencer_draw.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_snap.c
source/blender/gpu/CMakeLists.txt
source/blender/gpu/GPU_batch.h
source/blender/gpu/GPU_shader.h
source/blender/gpu/GPU_vertex_buffer.h
source/blender/gpu/intern/gpu_batch.c
source/blender/gpu/intern/gpu_shader.c
source/blender/gpu/intern/gpu_vertex_buffer.c
source/blender/gpu/intern/gpu_viewport.c
source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl
source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_instance_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_text_frag.glsl
source/blender/gpu/shaders/gpu_shader_text_geom.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl [deleted file]
source/blender/gpu/shaders/gpu_shader_text_vert.glsl
source/blender/gpu/shaders/material/gpu_shader_material_normal_map.glsl
source/blender/makesdna/DNA_world_types.h

index d6fd0cb6ec2e424a6e8df233d06fec0bacbe1720..e8244c9c1076f4609388b7f49c83aed83d2c85ea 100644 (file)
@@ -168,6 +168,7 @@ class DATA_PT_lightprobe_display(DataButtonsPanel, Panel):
 
         if probe.type == 'PLANAR':
             col.prop(ob, "empty_display_size", text="Arrow Size")
+            col.prop(probe, "show_influence")
             col.prop(probe, "show_data")
 
         if probe.type in {'GRID', 'CUBEMAP'}:
index 1c06dfd3f70611a6094881b23b01fa4b3ec8ad03..25ea0770f8b06bf3765039a9c11bb5bb7afed88a 100644 (file)
@@ -96,7 +96,13 @@ static void blf_batch_draw_init(void)
   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
   g_batch.glyph_len = 0;
 
-  g_batch.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, g_batch.verts, NULL, GPU_BATCH_OWNS_VBO);
+  /* A dummy vbo containing 4 points, attribs are not used.  */
+  GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+  GPU_vertbuf_data_alloc(vbo, 4);
+
+  /* We render a quad as a triangle strip and instance it for each glyph. */
+  g_batch.batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+  GPU_batch_instbuf_set(g_batch.batch, g_batch.verts, true);
 }
 
 static void blf_batch_draw_exit(void)
@@ -188,8 +194,7 @@ void blf_batch_draw(void)
   GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len);
   GPU_vertbuf_use(g_batch.verts); /* send data */
 
-  eGPUBuiltinShader shader = (g_batch.simple_shader) ? GPU_SHADER_TEXT_SIMPLE : GPU_SHADER_TEXT;
-  GPU_batch_program_set_builtin(g_batch.batch, shader);
+  GPU_batch_program_set_builtin(g_batch.batch, GPU_SHADER_TEXT);
   GPU_batch_uniform_1i(g_batch.batch, "glyph", 0);
   GPU_batch_draw(g_batch.batch);
 
index dc5508340deb78b604e0ff1c502f0635497c5c55..7d996f3c53588d481c0020cafbeb4c890fc3c646 100644 (file)
@@ -21,7 +21,6 @@
 set(INC
   .
   intern
-  modes
 
   ../blenfont
   ../blenkernel
@@ -49,8 +48,6 @@ set(INC_SYS
 )
 
 set(SRC
-  intern/draw_anim_viz.c
-  intern/draw_armature.c
   intern/draw_cache.c
   intern/draw_cache_extract_mesh.c
   intern/draw_cache_impl_curve.c
@@ -72,20 +69,6 @@ set(SRC
   intern/draw_manager_texture.c
   intern/draw_select_buffer.c
   intern/draw_view.c
-  modes/edit_armature_mode.c
-  modes/edit_curve_mode.c
-  modes/edit_lattice_mode.c
-  modes/edit_mesh_mode.c
-  modes/edit_mesh_mode_text.c
-  modes/edit_metaball_mode.c
-  modes/edit_text_mode.c
-  modes/object_mode.c
-  modes/overlay_mode.c
-  modes/paint_texture_mode.c
-  modes/paint_vertex_mode.c
-  modes/particle_mode.c
-  modes/pose_mode.c
-  modes/sculpt_mode.c
   engines/basic/basic_engine.c
   engines/eevee/eevee_bloom.c
   engines/eevee/eevee_data.c
@@ -136,6 +119,25 @@ set(SRC
   engines/gpencil/gpencil_shader_fx.c
   engines/select/select_draw_utils.c
   engines/select/select_engine.c
+  engines/overlay/overlay_antialiasing.c
+  engines/overlay/overlay_armature.c
+  engines/overlay/overlay_engine.c
+  engines/overlay/overlay_edit_curve.c
+  engines/overlay/overlay_edit_text.c
+  engines/overlay/overlay_edit_mesh.c
+  engines/overlay/overlay_extra.c
+  engines/overlay/overlay_facing.c
+  engines/overlay/overlay_grid.c
+  engines/overlay/overlay_image.c
+  engines/overlay/overlay_lattice.c
+  engines/overlay/overlay_metaball.c
+  engines/overlay/overlay_motion_path.c
+  engines/overlay/overlay_outline.c
+  engines/overlay/overlay_paint.c
+  engines/overlay/overlay_particle.c
+  engines/overlay/overlay_shader.c
+  engines/overlay/overlay_sculpt.c
+  engines/overlay/overlay_wireframe.c
 
   DRW_engine.h
   DRW_select_buffer.h
@@ -152,8 +154,7 @@ set(SRC
   intern/draw_manager_profiling.h
   intern/draw_manager_text.h
   intern/draw_view.h
-  modes/draw_mode_engines.h
-  modes/edit_mesh_mode_intern.h
+  intern/smaa_textures.h
   engines/basic/basic_engine.h
   engines/eevee/eevee_engine.h
   engines/eevee/eevee_lightcache.h
@@ -164,6 +165,8 @@ set(SRC
   engines/workbench/workbench_private.h
   engines/select/select_engine.h
   engines/select/select_private.h
+  engines/overlay/overlay_engine.h
+  engines/overlay/overlay_private.h
 )
 
 set(LIB
@@ -261,90 +264,14 @@ data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
 data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
 
-data_to_c_simple(modes/shaders/common_colormanagement_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_hair_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_hair_refine_vert.glsl SRC)
-data_to_c_simple(modes/shaders/common_view_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_fxaa_lib.glsl SRC)
-data_to_c_simple(modes/shaders/common_fullscreen_vert.glsl SRC)
-data_to_c_simple(modes/shaders/animviz_mpath_lines_vert.glsl SRC)
-data_to_c_simple(modes/shaders/animviz_mpath_lines_geom.glsl SRC)
-data_to_c_simple(modes/shaders/animviz_mpath_points_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_axes_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_sphere_solid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_sphere_solid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_sphere_outline_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_solid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_solid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_outline_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_envelope_distance_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_solid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_solid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_outline_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_shape_outline_geom.glsl SRC)
-data_to_c_simple(modes/shaders/armature_stick_vert.glsl SRC)
-data_to_c_simple(modes/shaders/armature_stick_frag.glsl SRC)
-data_to_c_simple(modes/shaders/armature_dof_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_common_lib.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_geom.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_overlay_mesh_analysis_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_mesh_skin_root_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_handle_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_curve_overlay_normals_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC)
-data_to_c_simple(modes/shaders/edit_lattice_overlay_loosevert_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_normals_vert.glsl SRC)
-data_to_c_simple(modes/shaders/edit_normals_geom.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_orientation_frag.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_orientation_vert.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_wireframe_vert.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_wireframe_geom.glsl SRC)
-data_to_c_simple(modes/shaders/overlay_face_wireframe_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_camera_image_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_camera_image_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_color_axes_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_empty_axes_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_empty_image_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_empty_image_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_resolve_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_expand_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_detect_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_prepass_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_prepass_geom.glsl SRC)
-data_to_c_simple(modes/shaders/object_outline_prepass_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_grid_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_grid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_lightprobe_grid_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_mball_handles_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_particle_dot_vert.glsl SRC)
-data_to_c_simple(modes/shaders/object_particle_dot_frag.glsl SRC)
-data_to_c_simple(modes/shaders/object_loose_points_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_texture_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_vertex_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_vertex_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_weight_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_weight_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_face_selection_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_face_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_wire_frag.glsl SRC)
-data_to_c_simple(modes/shaders/paint_wire_vert.glsl SRC)
-data_to_c_simple(modes/shaders/paint_vert_frag.glsl SRC)
-data_to_c_simple(modes/shaders/particle_strand_frag.glsl SRC)
-data_to_c_simple(modes/shaders/particle_strand_vert.glsl SRC)
-data_to_c_simple(modes/shaders/pose_selection_vert.glsl SRC)
-data_to_c_simple(modes/shaders/sculpt_mask_vert.glsl SRC)
-data_to_c_simple(modes/shaders/volume_velocity_vert.glsl SRC)
+data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC)
+data_to_c_simple(intern/shaders/common_view_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC)
 
 data_to_c_simple(engines/gpencil/shaders/gpencil_fill_vert.glsl SRC)
 data_to_c_simple(engines/gpencil/shaders/gpencil_fill_frag.glsl SRC)
@@ -380,6 +307,81 @@ data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl SRC)
 data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC)
 data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC)
 
+data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_envelope_outline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_outline_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_outline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_solid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_shape_solid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_sphere_outline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_stick_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_stick_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/armature_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/depth_only_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_handle_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_curve_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_lattice_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_lattice_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_common_lib.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_normal_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_skin_root_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_mesh_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_particle_strand_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_particle_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_groundline_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_loose_point_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_loose_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_wire_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/extra_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/facing_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/facing_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/grid_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/grid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/image_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/image_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/motion_path_line_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/motion_path_line_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/motion_path_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_detect_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_expand_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_prepass_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_prepass_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_prepass_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_lightprobe_grid_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/outline_resolve_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_face_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_point_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_texture_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_texture_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_vertcol_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_vertcol_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_weight_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_weight_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/paint_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/particle_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/particle_frag.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/sculpt_mask_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/volume_velocity_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/wireframe_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/wireframe_geom.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/wireframe_frag.glsl SRC)
 
 list(APPEND INC
 )
index e959d0c49eeecc3fb21bcaacd141b777ed9920eb..5edfadd7f417936f9ecf252de57d7612fef39043 100644 (file)
@@ -52,6 +52,7 @@ struct rcti;
 /* Buffer and textures used by the viewport by default */
 typedef struct DefaultFramebufferList {
   struct GPUFrameBuffer *default_fb;
+  struct GPUFrameBuffer *in_front_fb;
   struct GPUFrameBuffer *color_only_fb;
   struct GPUFrameBuffer *depth_only_fb;
   struct GPUFrameBuffer *multisample_fb;
@@ -60,6 +61,7 @@ typedef struct DefaultFramebufferList {
 typedef struct DefaultTextureList {
   struct GPUTexture *color;
   struct GPUTexture *depth;
+  struct GPUTexture *depth_in_front;
   struct GPUTexture *multisample_color;
   struct GPUTexture *multisample_depth;
 } DefaultTextureList;
index 0dd1a4fd6861badf3a7fc2090624d8c11a66ebaa..fcbe227ca1b26013be9b1d5a6eed956bed870d53 100644 (file)
@@ -46,8 +46,8 @@ typedef struct BASIC_StorageList {
 } BASIC_StorageList;
 
 typedef struct BASIC_PassList {
-  struct DRWPass *depth_pass;
-  struct DRWPass *depth_pass_cull;
+  struct DRWPass *depth_pass[2];
+  struct DRWPass *depth_pass_cull[2];
 } BASIC_PassList;
 
 typedef struct BASIC_Data {
@@ -70,8 +70,8 @@ static struct {
 } e_data = {{{NULL}}}; /* Engine data */
 
 typedef struct BASIC_PrivateData {
-  DRWShadingGroup *depth_shgrp;
-  DRWShadingGroup *depth_shgrp_cull;
+  DRWShadingGroup *depth_shgrp[2];
+  DRWShadingGroup *depth_shgrp_cull[2];
 } BASIC_PrivateData; /* Transient data */
 
 /* Functions */
@@ -97,24 +97,21 @@ static void basic_cache_init(void *vedata)
 
   if (!stl->g_data) {
     /* Alloc transient pointers */
-    stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+    stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
   }
 
-  {
-    psl->depth_pass = DRW_pass_create("Depth Pass",
-                                      DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
-    stl->g_data->depth_shgrp = DRW_shgroup_create(sh_data->depth, psl->depth_pass);
-    if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
-      DRW_shgroup_state_enable(stl->g_data->depth_shgrp, DRW_STATE_CLIP_PLANES);
-    }
+  /* Twice for normal and infront objects. */
+  for (int i = 0; i < 2; i++) {
+    DRWState clip_state = (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? DRW_STATE_CLIP_PLANES : 0;
+    DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+    DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
 
-    psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull",
-                                           DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
-                                               DRW_STATE_CULL_BACK);
-    stl->g_data->depth_shgrp_cull = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull);
-    if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) {
-      DRW_shgroup_state_enable(stl->g_data->depth_shgrp_cull, DRW_STATE_CLIP_PLANES);
-    }
+    DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state);
+    stl->g_data->depth_shgrp[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass[i]);
+
+    state |= DRW_STATE_CULL_BACK;
+    DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state);
+    stl->g_data->depth_shgrp_cull[i] = DRW_shgroup_create(sh_data->depth, psl->depth_pass_cull[i]);
   }
 }
 
@@ -128,6 +125,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
     return;
   }
 
+  bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+
   const DRWContextState *draw_ctx = DRW_context_state_get();
   if (ob != draw_ctx->object_edit) {
     for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
@@ -138,7 +137,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
       const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
       if (draw_as == PART_DRAW_PATH) {
         struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
-        DRW_shgroup_call(stl->g_data->depth_shgrp, hairs, NULL);
+        DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], hairs, NULL);
       }
     }
   }
@@ -155,7 +154,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
       /* Avoid losing flat objects when in ortho views (see T56549) */
       struct GPUBatch *geom = DRW_cache_object_all_edges_get(ob);
       if (geom) {
-        DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob);
+        DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], geom, ob);
       }
       return;
     }
@@ -165,7 +164,8 @@ static void basic_cache_populate(void *vedata, Object *ob)
                                !DRW_state_is_image_render();
   const bool do_cull = (draw_ctx->v3d &&
                         (draw_ctx->v3d->shading.flag & V3D_SHADING_BACKFACE_CULLING));
-  DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
+  DRWShadingGroup *shgrp = (do_cull) ? stl->g_data->depth_shgrp_cull[do_in_front] :
+                                       stl->g_data->depth_shgrp[do_in_front];
 
   if (use_sculpt_pbvh) {
     DRW_shgroup_call_sculpt(shgrp, ob, false, false, false);
@@ -189,8 +189,10 @@ static void basic_draw_scene(void *vedata)
 {
   BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
 
-  DRW_draw_pass(psl->depth_pass);
-  DRW_draw_pass(psl->depth_pass_cull);
+  DRW_draw_pass(psl->depth_pass[0]);
+  DRW_draw_pass(psl->depth_pass_cull[0]);
+  DRW_draw_pass(psl->depth_pass[1]);
+  DRW_draw_pass(psl->depth_pass_cull[1]);
 }
 
 static void basic_engine_free(void)
index 9554e9c02757c98b3d7c2e50241d091d1e3abd92..a1a1f7cc389222c7c8cbad69e582292a9fb3fea8 100644 (file)
@@ -33,8 +33,6 @@
 #include "DNA_screen_types.h"
 #include "DNA_view3d_types.h"
 
-#include "draw_mode_engines.h"
-
 #include "GPU_texture.h"
 
 #include "gpencil_engine.h"
index 36bc205f41ac40dd45d588ad85f1936641262f85..04ed19830ed969d9186665663d23349fbef9f445 100644 (file)
@@ -25,6 +25,8 @@
 
 #include "GPU_batch.h"
 
+extern DrawEngineType draw_engine_gpencil_type;
+
 struct GPENCIL_Data;
 struct GPENCIL_StorageList;
 struct MaterialGPencilStyle;
index 81e48eb05f21574de7b7af0965af7894d535d429..8c126310ea2d386f3d6e8153f153673b918d06a4 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "DEG_depsgraph_query.h"
 
-#include "draw_mode_engines.h"
-
 #include "RE_pipeline.h"
 
 #include "gpencil_engine.h"
diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c
new file mode 100644 (file)
index 0000000..54a5986
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Overlay antialiasing:
+ *
+ * Most of the overlays are wires which causes a lot of flickering in motions
+ * due to aliasing problems.
+ *
+ * Our goal is to have a technique that works with single sample per pixel
+ * to avoid extra cost of managing MSAA or additional texture buffers and jitters.
+ *
+ * To solve this we use a simple and effective post-process AA. The technique
+ * goes like this:
+ *
+ * - During wireframe rendering, we output the line color, the line direction
+ *   and the distance from the line for the pixel center.
+ *
+ * - Then, in a post process pass, for each pixels we gather all lines in a search area
+ *   that could cover (even partially) the center pixel.
+ *   We compute the coverage of each line and do a sorted alpha compositing of them.
+ *
+ * This technique has one major shortcoming compared to MSAA:
+ * - It handles (initial) partial visibility poorly (because of single sample). This makes
+ *   overlaping / crossing wires a bit too thin at their intersection.
+ *   Wireframe meshes overlaid over solid meshes can have half of the edge missing due to
+ *   z-fighting (this has workaround).
+ *   Another manifestation of this, is fickering of really dense wireframe if using small
+ *   line thickness (also has workaround).
+ *
+ * The pros of this approach are many:
+ *  - Works without geometry shader.
+ *  - Can inflate line thickness.
+ *  - Coverage is very close to perfect and can even be filtered (Blackman-Harris, gaussian).
+ *  - Wires can "bleed" / overlap non-line objects since the filter is in screenspace.
+ *  - Only uses one additional lightweight fullscreen buffer (compared to MSAA/SMAA).
+ *  - No convergence time (compared to TAA).
+ */
+
+#include "DRW_render.h"
+
+#include "ED_screen.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  pd->antialiasing.sample = 0;
+}
+
+void OVERLAY_antialiasing_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+  OVERLAY_TextureList *txl = vedata->txl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+  if (!DRW_state_is_fbo()) {
+    /* Use default view */
+    pd->view_default = (DRWView *)DRW_view_default_get();
+    pd->antialiasing.enabled = false;
+    return;
+  }
+
+  /* TODO Get real userpref option and remove MSAA buffer. */
+  pd->antialiasing.enabled = dtxl->multisample_color != NULL;
+
+  /* Use default view */
+  pd->view_default = (DRWView *)DRW_view_default_get();
+
+  if (pd->antialiasing.enabled) {
+    DRW_texture_ensure_fullscreen_2d(&txl->overlay_color_tx, GPU_RGBA8, DRW_TEX_FILTER);
+    DRW_texture_ensure_fullscreen_2d(&txl->overlay_line_tx, GPU_RGBA8, 0);
+
+    GPU_framebuffer_ensure_config(
+        &fbl->overlay_color_only_fb,
+        {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)});
+    GPU_framebuffer_ensure_config(
+        &fbl->overlay_default_fb,
+        {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)});
+    GPU_framebuffer_ensure_config(&fbl->overlay_line_fb,
+                                  {GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+                                   GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
+                                   GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)});
+  }
+  else {
+    /* Just a copy of the defaults framebuffers. */
+    GPU_framebuffer_ensure_config(&fbl->overlay_color_only_fb,
+                                  {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+    GPU_framebuffer_ensure_config(
+        &fbl->overlay_default_fb,
+        {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+    GPU_framebuffer_ensure_config(
+        &fbl->overlay_line_fb,
+        {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+  }
+}
+
+void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_TextureList *txl = vedata->txl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  OVERLAY_PassList *psl = vedata->psl;
+  DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+  struct GPUShader *sh;
+  DRWShadingGroup *grp;
+
+  if (pd->antialiasing.enabled) {
+    DRW_PASS_CREATE(psl->antialiasing_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL);
+
+    sh = OVERLAY_shader_antialiasing();
+    grp = DRW_shgroup_create(sh, psl->antialiasing_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_texture_ref(grp, "depthTex", &dtxl->depth);
+    DRW_shgroup_uniform_texture_ref(grp, "colorTex", &txl->overlay_color_tx);
+    DRW_shgroup_uniform_texture_ref(grp, "lineTex", &txl->overlay_line_tx);
+    DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+  }
+}
+
+void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata)
+{
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+  OVERLAY_TextureList *txl = vedata->txl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+  if (pd->antialiasing.enabled) {
+    GPU_framebuffer_ensure_config(&fbl->overlay_in_front_fb,
+                                  {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front),
+                                   GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)});
+  }
+  else {
+    GPU_framebuffer_ensure_config(
+        &fbl->overlay_in_front_fb,
+        {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+  }
+}
+
+void OVERLAY_antialiasing_start(OVERLAY_Data *vedata)
+{
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  if (pd->antialiasing.enabled) {
+    float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+    GPU_framebuffer_bind(fbl->overlay_line_fb);
+    GPU_framebuffer_clear_color(fbl->overlay_line_fb, clear_col);
+
+    GPU_framebuffer_bind(fbl->overlay_default_fb);
+  }
+}
+
+void OVERLAY_antialiasing_end(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+  if (pd->antialiasing.enabled) {
+    GPU_framebuffer_bind(dfbl->color_only_fb);
+    DRW_draw_pass(psl->antialiasing_ps);
+
+    GPU_framebuffer_bind(dfbl->default_fb);
+  }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
new file mode 100644 (file)
index 0000000..c749d90
--- /dev/null
@@ -0,0 +1,2338 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "DRW_render.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_armature.h"
+#include "BKE_modifier.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_armature.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+#define BONE_VAR(eBone, pchan, var) ((eBone) ? (eBone->var) : (pchan->var))
+#define BONE_FLAG(eBone, pchan) ((eBone) ? (eBone->flag) : (pchan->bone->flag))
+
+#define PT_DEFAULT_RAD 0.05f /* radius of the point batch. */
+
+typedef struct ArmatureDrawContext {
+  /* Current armature object */
+  Object *ob;
+  /* bArmature *arm; */ /* TODO */
+
+  union {
+    struct {
+      DRWCallBuffer *outline;
+      DRWCallBuffer *solid;
+      DRWCallBuffer *wire;
+    };
+    struct {
+      DRWCallBuffer *envelope_outline;
+      DRWCallBuffer *envelope_solid;
+      DRWCallBuffer *envelope_distance;
+    };
+    struct {
+      DRWCallBuffer *stick;
+    };
+  };
+
+  DRWCallBuffer *dof_lines;
+  DRWCallBuffer *dof_sphere;
+  DRWCallBuffer *point_solid;
+  DRWCallBuffer *point_outline;
+  DRWShadingGroup *custom_solid;
+  DRWShadingGroup *custom_outline;
+  DRWShadingGroup *custom_wire;
+  GHash *custom_shapes_ghash;
+
+  OVERLAY_ExtraCallBuffers *extras;
+
+  /**
+   * Follow `TH_*` naming except for mixed colors.
+   */
+  struct {
+    float select[4];
+    float edge_select[4];
+    float bone_select[4]; /* tint */
+    float wire[4];
+    float wire_edit[4];
+    float bone_solid[4];
+    float bone_active_unselect[4]; /* mix */
+    float bone_pose[4];
+    float bone_pose_active[4];
+    float bone_pose_active_unselect[4]; /* mix */
+    float text_hi[4];
+    float text[4];
+    float vertex_select[4];
+    float vertex[4];
+  } color;
+
+  /* not a theme, this is an override */
+  const float *const_color;
+  float const_wire;
+
+  bool do_relations;
+  bool transparent;
+  bool show_relations;
+
+  const ThemeWireColor *bcolor; /* pchan color */
+} ArmatureDrawContext;
+
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
+bool OVERLAY_armature_is_pose_mode(Object *ob, const DRWContextState *draw_ctx)
+{
+  Object *active_ob = draw_ctx->obact;
+
+  /* Pose armature is handled by pose mode engine. */
+  if (((ob == active_ob) || (ob->mode & OB_MODE_POSE)) &&
+      ((draw_ctx->object_mode & OB_MODE_POSE) != 0)) {
+    return true;
+  }
+
+  /* Armature parent is also handled by pose mode engine. */
+  if ((active_ob != NULL) && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) != 0)) {
+    if (ob == draw_ctx->object_pose) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  pd->armature.transparent = (draw_ctx->v3d->shading.type == OB_WIRE) ||
+                             XRAY_FLAG_ENABLED(draw_ctx->v3d);
+  pd->armature.show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
+  pd->armature.do_pose_fade_geom = (pd->overlay.flag & V3D_OVERLAY_BONE_SELECT) &&
+                                   ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) &&
+                                   draw_ctx->object_pose != NULL;
+
+  DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD;
+  DRW_PASS_CREATE(psl->armature_transp_ps, state | pd->clipping_state);
+
+  if (pd->armature.do_pose_fade_geom) {
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+    DRW_PASS_CREATE(psl->armature_bone_select_ps, state | pd->clipping_state);
+
+    float alpha = pd->overlay.xray_alpha_bone;
+    struct GPUShader *sh = OVERLAY_shader_uniform_color();
+    DRWShadingGroup *grp;
+
+    pd->armature_bone_select_act_grp = grp = DRW_shgroup_create(sh, psl->armature_bone_select_ps);
+    DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){0.0f, 0.0f, 0.0f, alpha});
+
+    pd->armature_bone_select_grp = grp = DRW_shgroup_create(sh, psl->armature_bone_select_ps);
+    DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){0.0f, 0.0f, 0.0f, pow(alpha, 4)});
+  }
+
+  for (int i = 0; i < 2; i++) {
+    struct GPUShader *sh;
+    struct GPUVertFormat *format;
+    DRWShadingGroup *grp = NULL;
+
+    OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+    OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i];
+    DRWPass **p_armature_ps = &psl->armature_ps[i];
+
+    cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
+
+    DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK |
+            (pd->armature.transparent ? DRW_STATE_BLEND_ALPHA : DRW_STATE_WRITE_DEPTH);
+    DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state);
+
+    DRWPass *armature_ps = *p_armature_ps;
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
+
+    {
+      format = formats->instance_bone;
+
+      sh = OVERLAY_shader_armature_sphere(false);
+      grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.4f : 1.0f);
+      cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
+
+      sh = OVERLAY_shader_armature_sphere(true);
+      grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+
+      sh = OVERLAY_shader_armature_shape(false);
+      cb->custom_solid = grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.6f : 1.0f);
+      cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
+      cb->octa_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
+
+      sh = OVERLAY_shader_armature_shape(true);
+      cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
+      cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+    }
+    {
+      format = formats->instance_extra;
+
+      sh = OVERLAY_shader_armature_degrees_of_freedom();
+      grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+
+      grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+    }
+    {
+      format = formats->instance_bone_stick;
+
+      sh = OVERLAY_shader_armature_stick();
+      grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+    }
+    {
+      format = formats->instance_bone_envelope;
+
+      sh = OVERLAY_shader_armature_envelope(false);
+      grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_uniform_bool_copy(grp, "isDistance", false);
+      DRW_shgroup_uniform_float_copy(grp, "alpha", pd->armature.transparent ? 0.6f : 1.0f);
+      cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+
+      format = formats->instance_bone_envelope_outline;
+
+      sh = OVERLAY_shader_armature_envelope(true);
+      grp = DRW_shgroup_create(sh, armature_ps);
+      DRW_shgroup_state_disable(grp, DRW_STATE_CULL_BACK);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get());
+
+      format = formats->instance_bone_envelope_distance;
+
+      sh = OVERLAY_shader_armature_envelope(false);
+      grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
+      DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
+      cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+    }
+    {
+      format = formats->pos_color;
+
+      sh = OVERLAY_shader_armature_wire();
+      grp = DRW_shgroup_create(sh, armature_ps);
+      cb->wire = BUF_LINE(grp, format);
+    }
+  }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Shader Groups (DRW_shgroup)
+ * \{ */
+
+static void bone_instance_data_set_angle_minmax(BoneInstanceData *data,
+                                                const float aminx,
+                                                const float aminz,
+                                                const float amaxx,
+                                                const float amaxz)
+{
+  data->amin_a = aminx;
+  data->amin_b = aminz;
+  data->amax_a = amaxx;
+  data->amax_b = amaxz;
+}
+
+/* Encode 2 units float with byte precision into a float. */
+static float encode_2f_to_float(float a, float b)
+{
+  CLAMP(a, 0.0f, 1.0f);
+  CLAMP(b, 0.0f, 2.0f); /* Can go up to 2. Needed for wire size. */
+  return (float)((int)(a * 255) | ((int)(b * 255) << 8));
+}
+
+void OVERLAY_bone_instance_data_set_color_hint(BoneInstanceData *data, const float hint_color[4])
+{
+  /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
+  data->color_hint_a = encode_2f_to_float(hint_color[0], hint_color[1]);
+  data->color_hint_b = encode_2f_to_float(hint_color[2], hint_color[3]);
+}
+
+void OVERLAY_bone_instance_data_set_color(BoneInstanceData *data, const float bone_color[4])
+{
+  /* Encoded color into 2 floats to be able to use the obmat to color the custom bones. */
+  data->color_a = encode_2f_to_float(bone_color[0], bone_color[1]);
+  data->color_b = encode_2f_to_float(bone_color[2], bone_color[3]);
+}
+
+/* Octahedral */
+static void drw_shgroup_bone_octahedral(ArmatureDrawContext *ctx,
+                                        const float (*bone_mat)[4],
+                                        const float bone_color[4],
+                                        const float hint_color[4],
+                                        const float outline_color[4])
+{
+  BoneInstanceData inst_data;
+  mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+  if (ctx->solid) {
+    OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+    OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+    DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
+  }
+  if (outline_color[3] > 0.0f) {
+    OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+    DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
+  }
+}
+
+/* Box / B-Bone */
+static void drw_shgroup_bone_box(ArmatureDrawContext *ctx,
+                                 const float (*bone_mat)[4],
+                                 const float bone_color[4],
+                                 const float hint_color[4],
+                                 const float outline_color[4])
+{
+  BoneInstanceData inst_data;
+  mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+  if (ctx->solid) {
+    OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+    OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+    DRW_buffer_add_entry_struct(ctx->solid, &inst_data);
+  }
+  if (outline_color[3] > 0.0f) {
+    OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+    DRW_buffer_add_entry_struct(ctx->outline, &inst_data);
+  }
+}
+
+/* Wire */
+static void drw_shgroup_bone_wire(ArmatureDrawContext *ctx,
+                                  const float (*bone_mat)[4],
+                                  const float color[4])
+{
+  float head[3], tail[3];
+  mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]);
+  add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
+  mul_m4_v3(ctx->ob->obmat, tail);
+
+  DRW_buffer_add_entry(ctx->wire, head, color);
+  DRW_buffer_add_entry(ctx->wire, tail, color);
+}
+
+/* Stick */
+static void drw_shgroup_bone_stick(ArmatureDrawContext *ctx,
+                                   const float (*bone_mat)[4],
+                                   const float col_wire[4],
+                                   const float col_bone[4],
+                                   const float col_head[4],
+                                   const float col_tail[4])
+{
+  float head[3], tail[3];
+  mul_v3_m4v3(head, ctx->ob->obmat, bone_mat[3]);
+  add_v3_v3v3(tail, bone_mat[3], bone_mat[1]);
+  mul_m4_v3(ctx->ob->obmat, tail);
+
+  DRW_buffer_add_entry(ctx->stick, head, tail, col_wire, col_bone, col_head, col_tail);
+}
+
+/* Envelope */
+static void drw_shgroup_bone_envelope_distance(ArmatureDrawContext *ctx,
+                                               const float (*bone_mat)[4],
+                                               const float *radius_head,
+                                               const float *radius_tail,
+                                               const float *distance)
+{
+  if (ctx->envelope_distance) {
+    float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+    float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+    /* Still less operation than m4 multiplication. */
+    mul_m4_v4(bone_mat, head_sph);
+    mul_m4_v4(bone_mat, tail_sph);
+    mul_m4_v4(bone_mat, xaxis);
+    mul_m4_v4(ctx->ob->obmat, head_sph);
+    mul_m4_v4(ctx->ob->obmat, tail_sph);
+    mul_m4_v4(ctx->ob->obmat, xaxis);
+    sub_v3_v3(xaxis, head_sph);
+    head_sph[3] = *radius_head;
+    head_sph[3] += *distance;
+    tail_sph[3] = *radius_tail;
+    tail_sph[3] += *distance;
+    DRW_buffer_add_entry(ctx->envelope_distance, head_sph, tail_sph, xaxis);
+  }
+}
+
+static void drw_shgroup_bone_envelope(ArmatureDrawContext *ctx,
+                                      const float (*bone_mat)[4],
+                                      const float bone_col[4],
+                                      const float hint_col[4],
+                                      const float outline_col[4],
+                                      const float *radius_head,
+                                      const float *radius_tail)
+{
+  float head_sph[4] = {0.0f, 0.0f, 0.0f, 1.0f}, tail_sph[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+  float xaxis[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+  /* Still less operation than m4 multiplication. */
+  mul_m4_v4(bone_mat, head_sph);
+  mul_m4_v4(bone_mat, tail_sph);
+  mul_m4_v4(bone_mat, xaxis);
+  mul_m4_v4(ctx->ob->obmat, head_sph);
+  mul_m4_v4(ctx->ob->obmat, tail_sph);
+  mul_m4_v4(ctx->ob->obmat, xaxis);
+  head_sph[3] = *radius_head;
+  tail_sph[3] = *radius_tail;
+
+  if (head_sph[3] < 0.0f || tail_sph[3] < 0.0f) {
+    BoneInstanceData inst_data;
+    if (head_sph[3] < 0.0f) {
+      /* Draw Tail only */
+      scale_m4_fl(inst_data.mat, tail_sph[3] / PT_DEFAULT_RAD);
+      copy_v3_v3(inst_data.mat[3], tail_sph);
+    }
+    else {
+      /* Draw Head only */
+      scale_m4_fl(inst_data.mat, head_sph[3] / PT_DEFAULT_RAD);
+      copy_v3_v3(inst_data.mat[3], head_sph);
+    }
+
+    if (ctx->point_solid) {
+      OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
+      OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
+      DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+    }
+    if (outline_col[3] > 0.0f) {
+      OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
+      DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+    }
+  }
+  else {
+    /* Draw Body */
+    float tmp_sph[4];
+    float len = len_v3v3(tail_sph, head_sph);
+    float fac_head = (len - head_sph[3]) / len;
+    float fac_tail = (len - tail_sph[3]) / len;
+    /* Small epsilon to avoid problem with float precision in shader. */
+    if (len > (tail_sph[3] + head_sph[3]) + 1e-8f) {
+      copy_v4_v4(tmp_sph, head_sph);
+      interp_v4_v4v4(head_sph, tail_sph, head_sph, fac_head);
+      interp_v4_v4v4(tail_sph, tmp_sph, tail_sph, fac_tail);
+      if (ctx->envelope_solid) {
+        DRW_buffer_add_entry(ctx->envelope_solid, head_sph, tail_sph, bone_col, hint_col, xaxis);
+      }
+      if (outline_col[3] > 0.0f) {
+        DRW_buffer_add_entry(ctx->envelope_outline, head_sph, tail_sph, outline_col, xaxis);
+      }
+    }
+    else {
+      /* Distance between endpoints is too small for a capsule. Draw a Sphere instead. */
+      float fac = max_ff(fac_head, 1.0f - fac_tail);
+      interp_v4_v4v4(tmp_sph, tail_sph, head_sph, clamp_f(fac, 0.0f, 1.0f));
+
+      BoneInstanceData inst_data;
+      scale_m4_fl(inst_data.mat, tmp_sph[3] / PT_DEFAULT_RAD);
+      copy_v3_v3(inst_data.mat[3], tmp_sph);
+      if (ctx->point_solid) {
+        OVERLAY_bone_instance_data_set_color(&inst_data, bone_col);
+        OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_col);
+        DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+      }
+      if (outline_col[3] > 0.0f) {
+        OVERLAY_bone_instance_data_set_color(&inst_data, outline_col);
+        DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+      }
+    }
+  }
+}
+
+/* Custom (geometry) */
+
+extern void drw_batch_cache_validate(Object *custom);
+extern void drw_batch_cache_generate_requested(Object *custom);
+
+BLI_INLINE DRWCallBuffer *custom_bone_instance_shgroup(ArmatureDrawContext *ctx,
+                                                       DRWShadingGroup *grp,
+                                                       struct GPUBatch *custom_geom)
+{
+  DRWCallBuffer *buf = BLI_ghash_lookup(ctx->custom_shapes_ghash, custom_geom);
+  if (buf == NULL) {
+    OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+    buf = DRW_shgroup_call_buffer_instance(grp, formats->instance_bone, custom_geom);
+    BLI_ghash_insert(ctx->custom_shapes_ghash, custom_geom, buf);
+  }
+  return buf;
+}
+
+static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx,
+                                          const float (*bone_mat)[4],
+                                          const float bone_color[4],
+                                          const float hint_color[4],
+                                          const float outline_color[4],
+                                          Object *custom)
+{
+  /* TODO(fclem) arg... less than ideal but we never iter on this object
+   * to assure batch cache is valid. */
+  drw_batch_cache_validate(custom);
+
+  struct GPUBatch *surf = DRW_cache_object_surface_get(custom);
+  struct GPUBatch *edges = DRW_cache_object_edge_detection_get(custom, NULL);
+  struct GPUBatch *ledges = DRW_cache_object_loose_edges_get(custom);
+  BoneInstanceData inst_data;
+  DRWCallBuffer *buf;
+
+  if (surf || edges || ledges) {
+    mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+  }
+
+  if (surf && ctx->custom_solid) {
+    buf = custom_bone_instance_shgroup(ctx, ctx->custom_solid, surf);
+    OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+    OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+    DRW_buffer_add_entry_struct(buf, inst_data.mat);
+  }
+
+  if (edges && ctx->custom_outline) {
+    buf = custom_bone_instance_shgroup(ctx, ctx->custom_outline, edges);
+    OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+    DRW_buffer_add_entry_struct(buf, inst_data.mat);
+  }
+
+  if (ledges) {
+    buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, ledges);
+    OVERLAY_bone_instance_data_set_color_hint(&inst_data, outline_color);
+    OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+    DRW_buffer_add_entry_struct(buf, inst_data.mat);
+  }
+
+  /* TODO(fclem) needs to be moved elsewhere. */
+  drw_batch_cache_generate_requested(custom);
+}
+
+static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
+                                         const float (*bone_mat)[4],
+                                         const float color[4],
+                                         Object *custom)
+{
+  /* TODO(fclem) arg... less than ideal but we never iter on this object
+   * to assure batch cache is valid. */
+  drw_batch_cache_validate(custom);
+
+  struct GPUBatch *geom = DRW_cache_object_all_edges_get(custom);
+
+  if (geom) {
+    DRWCallBuffer *buf = custom_bone_instance_shgroup(ctx, ctx->custom_wire, geom);
+    BoneInstanceData inst_data;
+    mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+    OVERLAY_bone_instance_data_set_color_hint(&inst_data, color);
+    OVERLAY_bone_instance_data_set_color(&inst_data, color);
+    DRW_buffer_add_entry_struct(buf, inst_data.mat);
+  }
+
+  /* TODO(fclem) needs to be moved elsewhere. */
+  drw_batch_cache_generate_requested(custom);
+}
+
+static void drw_shgroup_bone_custom_empty(ArmatureDrawContext *ctx,
+                                          const float (*bone_mat)[4],
+                                          const float color[4],
+                                          Object *custom)
+{
+  float final_color[4] = {color[0], color[1], color[2], 1.0f};
+  float mat[4][4];
+  mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat);
+
+  switch (custom->empty_drawtype) {
+    case OB_PLAINAXES:
+    case OB_SINGLE_ARROW:
+    case OB_CUBE:
+    case OB_CIRCLE:
+    case OB_EMPTY_SPHERE:
+    case OB_EMPTY_CONE:
+    case OB_ARROWS:
+      OVERLAY_empty_shape(
+          ctx->extras, mat, custom->empty_drawsize, custom->empty_drawtype, final_color);
+      break;
+    case OB_EMPTY_IMAGE:
+      break;
+  }
+}
+
+/* Head and tail sphere */
+static void drw_shgroup_bone_point(ArmatureDrawContext *ctx,
+                                   const float (*bone_mat)[4],
+                                   const float bone_color[4],
+                                   const float hint_color[4],
+                                   const float outline_color[4])
+{
+  BoneInstanceData inst_data;
+  mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, bone_mat);
+  if (ctx->point_solid) {
+    OVERLAY_bone_instance_data_set_color(&inst_data, bone_color);
+    OVERLAY_bone_instance_data_set_color_hint(&inst_data, hint_color);
+    DRW_buffer_add_entry_struct(ctx->point_solid, &inst_data);
+  }
+  if (outline_color[3] > 0.0f) {
+    OVERLAY_bone_instance_data_set_color(&inst_data, outline_color);
+    DRW_buffer_add_entry_struct(ctx->point_outline, &inst_data);
+  }
+}
+
+/* Axes */
+static void drw_shgroup_bone_axes(ArmatureDrawContext *ctx,
+                                  const float (*bone_mat)[4],
+                                  const float color[4])
+{
+  float mat[4][4];
+  mul_m4_m4m4(mat, ctx->ob->obmat, bone_mat);
+  /* Move to bone tail. */
+  add_v3_v3(mat[3], mat[1]);
+  OVERLAY_empty_shape(ctx->extras, mat, 0.25f, OB_ARROWS, color);
+}
+
+/* Relationship lines */
+static void drw_shgroup_bone_relationship_lines_ex(ArmatureDrawContext *ctx,
+                                                   const float start[3],
+                                                   const float end[3],
+                                                   const float color[4])
+{
+  float s[3], e[3];
+  mul_v3_m4v3(s, ctx->ob->obmat, start);
+  mul_v3_m4v3(e, ctx->ob->obmat, end);
+  /* reverse order to have less stipple overlap */
+  OVERLAY_extra_line_dashed(ctx->extras, s, e, color);
+}
+
+static void drw_shgroup_bone_relationship_lines(ArmatureDrawContext *ctx,
+                                                const float start[3],
+                                                const float end[3])
+{
+  drw_shgroup_bone_relationship_lines_ex(ctx, start, end, ctx->color.wire);
+}
+
+static void drw_shgroup_bone_ik_lines(ArmatureDrawContext *ctx,
+                                      const float start[3],
+                                      const float end[3])
+{
+  float fcolor[4] = {0.8f, 0.5f, 0.0f, 1.0f}; /* add theme! */
+  drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+static void drw_shgroup_bone_ik_no_target_lines(ArmatureDrawContext *ctx,
+                                                const float start[3],
+                                                const float end[3])
+{
+  float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+  drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+static void drw_shgroup_bone_ik_spline_lines(ArmatureDrawContext *ctx,
+                                             const float start[3],
+                                             const float end[3])
+{
+  float fcolor[4] = {0.8f, 0.8f, 0.2f, 1.0f}; /* add theme! */
+  drw_shgroup_bone_relationship_lines_ex(ctx, start, end, fcolor);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Theme Helpers
+ *
+ * Note, this section is duplicate of code in 'drawarmature.c'.
+ *
+ * \{ */
+
+/* values of colCode for set_pchan_color */
+enum {
+  PCHAN_COLOR_NORMAL = 0, /* normal drawing */
+  PCHAN_COLOR_SOLID,      /* specific case where "solid" color is needed */
+  PCHAN_COLOR_CONSTS,     /* "constraint" colors (which may/may-not be suppressed) */
+
+  PCHAN_COLOR_SPHEREBONE_BASE, /* for the 'stick' of sphere (envelope) bones */
+  PCHAN_COLOR_SPHEREBONE_END,  /* for the ends of sphere (envelope) bones */
+  PCHAN_COLOR_LINEBONE,        /* for the middle of line-bones */
+};
+
+/* This function sets the color-set for coloring a certain bone */
+static void set_pchan_colorset(ArmatureDrawContext *ctx, Object *ob, bPoseChannel *pchan)
+{
+  bPose *pose = (ob) ? ob->pose : NULL;
+  bArmature *arm = (ob) ? ob->data : NULL;
+  bActionGroup *grp = NULL;
+  short color_index = 0;
+
+  /* sanity check */
+  if (ELEM(NULL, ob, arm, pose, pchan)) {
+    ctx->bcolor = NULL;
+    return;
+  }
+
+  /* only try to set custom color if enabled for armature */
+  if (arm->flag & ARM_COL_CUSTOM) {
+    /* currently, a bone can only use a custom color set if it's group (if it has one),
+     * has been set to use one
+     */
+    if (pchan->agrp_index) {
+      grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
+      if (grp) {
+        color_index = grp->customCol;
+      }
+    }
+  }
+
+  /* bcolor is a pointer to the color set to use. If NULL, then the default
+   * color set (based on the theme colors for 3d-view) is used.
+   */
+  if (color_index > 0) {
+    bTheme *btheme = UI_GetTheme();
+    ctx->bcolor = &btheme->tarm[(color_index - 1)];
+  }
+  else if (color_index == -1) {
+    /* use the group's own custom color set (grp is always != NULL here) */
+    ctx->bcolor = &grp->cs;
+  }
+  else {
+    ctx->bcolor = NULL;
+  }
+}
+
+/* This function is for brightening/darkening a given color (like UI_GetThemeColorShade3ubv()) */
+static void cp_shade_color3ub(uchar cp[3], const int offset)
+{
+  int r, g, b;
+
+  r = offset + (int)cp[0];
+  CLAMP(r, 0, 255);
+  g = offset + (int)cp[1];
+  CLAMP(g, 0, 255);
+  b = offset + (int)cp[2];
+  CLAMP(b, 0, 255);
+
+  cp[0] = r;
+  cp[1] = g;
+  cp[2] = b;
+}
+
+static void cp_shade_color3f(float cp[3], const float offset)
+{
+  add_v3_fl(cp, offset);
+  CLAMP(cp[0], 0, 255);
+  CLAMP(cp[1], 0, 255);
+  CLAMP(cp[2], 0, 255);
+}
+
+/* This function sets the gl-color for coloring a certain bone (based on bcolor) */
+static bool set_pchan_color(const ArmatureDrawContext *ctx,
+                            short colCode,
+                            const int boneflag,
+                            const short constflag,
+                            float r_color[4])
+{
+  float *fcolor = r_color;
+  const ThemeWireColor *bcolor = ctx->bcolor;
+
+  switch (colCode) {
+    case PCHAN_COLOR_NORMAL: {
+      if (bcolor) {
+        uchar cp[4] = {255};
+
+        if (boneflag & BONE_DRAW_ACTIVE) {
+          copy_v3_v3_uchar(cp, bcolor->active);
+          if (!(boneflag & BONE_SELECTED)) {
+            cp_shade_color3ub(cp, -80);
+          }
+        }
+        else if (boneflag & BONE_SELECTED) {
+          copy_v3_v3_uchar(cp, bcolor->select);
+        }
+        else {
+          /* a bit darker than solid */
+          copy_v3_v3_uchar(cp, bcolor->solid);
+          cp_shade_color3ub(cp, -50);
+        }
+
+        rgb_uchar_to_float(fcolor, cp);
+      }
+      else {
+        if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) {
+          UI_GetThemeColor4fv(TH_BONE_POSE_ACTIVE, fcolor);
+        }
+        else if (boneflag & BONE_DRAW_ACTIVE) {
+          UI_GetThemeColorBlendShade4fv(TH_WIRE, TH_BONE_POSE, 0.15f, 0, fcolor);
+        }
+        else if (boneflag & BONE_SELECTED) {
+          UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+        }
+        else {
+          UI_GetThemeColor4fv(TH_WIRE, fcolor);
+        }
+      }
+
+      return true;
+    }
+    case PCHAN_COLOR_SOLID: {
+      UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+
+      if (bcolor) {
+        float solid_bcolor[3];
+        rgb_uchar_to_float(solid_bcolor, (uchar *)bcolor->solid);
+        interp_v3_v3v3(fcolor, fcolor, solid_bcolor, 1.0f);
+      }
+
+      return true;
+    }
+    case PCHAN_COLOR_CONSTS: {
+      if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) {
+        uchar cp[4];
+        if (constflag & PCHAN_HAS_TARGET) {
+          rgba_uchar_args_set(cp, 255, 150, 0, 80);
+        }
+        else if (constflag & PCHAN_HAS_IK) {
+          rgba_uchar_args_set(cp, 255, 255, 0, 80);
+        }
+        else if (constflag & PCHAN_HAS_SPLINEIK) {
+          rgba_uchar_args_set(cp, 200, 255, 0, 80);
+        }
+        else if (constflag & PCHAN_HAS_CONST) {
+          rgba_uchar_args_set(cp, 0, 255, 120, 80);
+        }
+        else {
+          return false;
+        }
+
+        rgba_uchar_to_float(fcolor, cp);
+
+        return true;
+      }
+      return false;
+    }
+    case PCHAN_COLOR_SPHEREBONE_BASE: {
+      if (bcolor) {
+        uchar cp[4] = {255};
+
+        if (boneflag & BONE_DRAW_ACTIVE) {
+          copy_v3_v3_uchar(cp, bcolor->active);
+        }
+        else if (boneflag & BONE_SELECTED) {
+          copy_v3_v3_uchar(cp, bcolor->select);
+        }
+        else {
+          copy_v3_v3_uchar(cp, bcolor->solid);
+        }
+
+        rgb_uchar_to_float(fcolor, cp);
+      }
+      else {
+        if (boneflag & BONE_DRAW_ACTIVE) {
+          UI_GetThemeColorShade4fv(TH_BONE_POSE, 40, fcolor);
+        }
+        else if (boneflag & BONE_SELECTED) {
+          UI_GetThemeColor4fv(TH_BONE_POSE, fcolor);
+        }
+        else {
+          UI_GetThemeColor4fv(TH_BONE_SOLID, fcolor);
+        }
+      }
+
+      return true;
+    }
+    case PCHAN_COLOR_SPHEREBONE_END: {
+      if (bcolor) {
+        uchar cp[4] = {255};
+
+        if (boneflag & BONE_DRAW_ACTIVE) {
+          copy_v3_v3_uchar(cp, bcolor->active);
+          cp_shade_color3ub(cp, 10);
+        }
+        else if (boneflag & BONE_SELECTED) {
+          copy_v3_v3_uchar(cp, bcolor->select);
+          cp_shade_color3ub(cp, -30);
+        }
+        else {
+          copy_v3_v3_uchar(cp, bcolor->solid);
+          cp_shade_color3ub(cp, -30);
+        }
+
+        rgb_uchar_to_float(fcolor, cp);
+      }
+      else {
+        if (boneflag & BONE_DRAW_ACTIVE) {
+          UI_GetThemeColorShade4fv(TH_BONE_POSE, 10, fcolor);
+        }
+        else if (boneflag & BONE_SELECTED) {
+          UI_GetThemeColorShade4fv(TH_BONE_POSE, -30, fcolor);
+        }
+        else {
+          UI_GetThemeColorShade4fv(TH_BONE_SOLID, -30, fcolor);
+        }
+      }
+      break;
+    }
+    case PCHAN_COLOR_LINEBONE: {
+      /* inner part in background color or constraint */
+      if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) {
+        uchar cp[4];
+        if (constflag & PCHAN_HAS_TARGET) {
+          rgba_uchar_args_set(cp, 255, 150, 0, 255);
+        }
+        else if (constflag & PCHAN_HAS_IK) {
+          rgba_uchar_args_set(cp, 255, 255, 0, 255);
+        }
+        else if (constflag & PCHAN_HAS_SPLINEIK) {
+          rgba_uchar_args_set(cp, 200, 255, 0, 255);
+        }
+        else if (constflag & PCHAN_HAS_CONST) {
+          rgba_uchar_args_set(cp, 0, 255, 120, 255);
+        }
+        else if (constflag) {
+          UI_GetThemeColor4ubv(TH_BONE_POSE, cp);
+        } /* PCHAN_HAS_ACTION */
+
+        rgb_uchar_to_float(fcolor, cp);
+      }
+      else {
+        if (bcolor) {
+          const uchar *cp = bcolor->solid;
+          rgb_uchar_to_float(fcolor, (uchar *)cp);
+          fcolor[3] = 204.f / 255.f;
+        }
+        else {
+          UI_GetThemeColorShade4fv(TH_BACK, -30, fcolor);
+        }
+      }
+
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Color Helpers
+ * \{ */
+
+static const float *get_bone_solid_color(const ArmatureDrawContext *ctx,
+                                         const EditBone *UNUSED(eBone),
+                                         const bPoseChannel *pchan,
+                                         const bArmature *arm,
+                                         const int boneflag,
+                                         const short constflag)
+{
+  if (ctx->const_color) {
+    return ctx->color.bone_solid;
+  }
+
+  if (arm->flag & ARM_POSEMODE) {
+    static float disp_color[4];
+    copy_v4_v4(disp_color, pchan->draw_data->solid_color);
+    set_pchan_color(ctx, PCHAN_COLOR_SOLID, boneflag, constflag, disp_color);
+    return disp_color;
+  }
+
+  return ctx->color.bone_solid;
+}
+
+static const float *get_bone_solid_with_consts_color(const ArmatureDrawContext *ctx,
+                                                     const EditBone *eBone,
+                                                     const bPoseChannel *pchan,
+                                                     const bArmature *arm,
+                                                     const int boneflag,
+                                                     const short constflag)
+{
+  if (ctx->const_color) {
+    return ctx->color.bone_solid;
+  }
+
+  const float *col = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+  static float consts_color[4];
+  if (set_pchan_color(ctx, PCHAN_COLOR_CONSTS, boneflag, constflag, consts_color)) {
+    interp_v3_v3v3(consts_color, col, consts_color, 0.5f);
+  }
+  else {
+    copy_v4_v4(consts_color, col);
+  }
+  return consts_color;
+}
+
+static float get_bone_wire_thickness(const ArmatureDrawContext *ctx, int boneflag)
+{
+  if (ctx->const_color) {
+    return ctx->const_wire;
+  }
+  else if (boneflag & (BONE_DRAW_ACTIVE | BONE_SELECTED)) {
+    return 2.0f;
+  }
+  else {
+    return 1.0f;
+  }
+}
+
+static const float *get_bone_wire_color(const ArmatureDrawContext *ctx,
+                                        const EditBone *eBone,
+                                        const bPoseChannel *pchan,
+                                        const bArmature *arm,
+                                        const int boneflag,
+                                        const short constflag)
+{
+  static float disp_color[4];
+
+  if (ctx->const_color) {
+    copy_v3_v3(disp_color, ctx->const_color);
+  }
+  else if (eBone) {
+    if (boneflag & BONE_SELECTED) {
+      if (boneflag & BONE_DRAW_ACTIVE) {
+        copy_v3_v3(disp_color, ctx->color.edge_select);
+      }
+      else {
+        copy_v3_v3(disp_color, ctx->color.bone_select);
+      }
+    }
+    else {
+      if (boneflag & BONE_DRAW_ACTIVE) {
+        copy_v3_v3(disp_color, ctx->color.bone_active_unselect);
+      }
+      else {
+        copy_v3_v3(disp_color, ctx->color.wire_edit);
+      }
+    }
+  }
+  else if (arm->flag & ARM_POSEMODE) {
+    copy_v4_v4(disp_color, pchan->draw_data->wire_color);
+    set_pchan_color(ctx, PCHAN_COLOR_NORMAL, boneflag, constflag, disp_color);
+  }
+  else {
+    copy_v3_v3(disp_color, ctx->color.vertex);
+  }
+
+  disp_color[3] = get_bone_wire_thickness(ctx, boneflag);
+
+  return disp_color;
+}
+
+#define HINT_MUL 0.5f
+#define HINT_SHADE 0.2f
+
+static void bone_hint_color_shade(float hint_color[4], const float color[4])
+{
+  mul_v3_v3fl(hint_color, color, HINT_MUL);
+  cp_shade_color3f(hint_color, -HINT_SHADE);
+  hint_color[3] = 1.0f;
+}
+
+static const float *get_bone_hint_color(const ArmatureDrawContext *ctx,
+                                        const EditBone *eBone,
+                                        const bPoseChannel *pchan,
+                                        const bArmature *arm,
+                                        const int boneflag,
+                                        const short constflag)
+{
+  static float hint_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+  if (ctx->const_color) {
+    bone_hint_color_shade(hint_color, ctx->color.bone_solid);
+  }
+  else {
+    const float *wire_color = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+    bone_hint_color_shade(hint_color, wire_color);
+  }
+
+  return hint_color;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper Utils
+ * \{ */
+
+static void pchan_draw_data_init(bPoseChannel *pchan)
+{
+  if (pchan->draw_data != NULL) {
+    if (pchan->draw_data->bbone_matrix_len != pchan->bone->segments) {
+      MEM_SAFE_FREE(pchan->draw_data);
+    }
+  }
+
+  if (pchan->draw_data == NULL) {
+    pchan->draw_data = MEM_mallocN(
+        sizeof(*pchan->draw_data) + sizeof(Mat4) * pchan->bone->segments, __func__);
+    pchan->draw_data->bbone_matrix_len = pchan->bone->segments;
+  }
+}
+
+static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *pchan)
+{
+  float s[4][4], ebmat[4][4];
+  float length;
+  float(*bone_mat)[4];
+  float(*disp_mat)[4];
+  float(*disp_tail_mat)[4];
+
+  /* TODO : This should be moved to depsgraph or armature refresh
+   * and not be tight to the draw pass creation.
+   * This would refresh armature without invalidating the draw cache */
+  if (pchan) {
+    length = pchan->bone->length;
+    bone_mat = pchan->pose_mat;
+    disp_mat = pchan->disp_mat;
+    disp_tail_mat = pchan->disp_tail_mat;
+  }
+  else {
+    eBone->length = len_v3v3(eBone->tail, eBone->head);
+    ED_armature_ebone_to_mat4(eBone, ebmat);
+
+    length = eBone->length;
+    bone_mat = ebmat;
+    disp_mat = eBone->disp_mat;
+    disp_tail_mat = eBone->disp_tail_mat;
+  }
+
+  scale_m4_fl(s, length);
+  mul_m4_m4m4(disp_mat, bone_mat, s);
+  copy_m4_m4(disp_tail_mat, disp_mat);
+  translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+/* compute connected child pointer for B-Bone drawing */
+static void edbo_compute_bbone_child(bArmature *arm)
+{
+  EditBone *eBone;
+
+  for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+    eBone->bbone_child = NULL;
+  }
+
+  for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+    if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+      eBone->parent->bbone_child = eBone;
+    }
+  }
+}
+
+/* A version of BKE_pchan_bbone_spline_setup() for previewing editmode curve settings. */
+static void ebone_spline_preview(EditBone *ebone, float result_array[MAX_BBONE_SUBDIV][4][4])
+{
+  BBoneSplineParameters param;
+  EditBone *prev, *next;
+  float imat[4][4], bonemat[4][4];
+  float tmp[3];
+
+  memset(&param, 0, sizeof(param));
+
+  param.segments = ebone->segments;
+  param.length = ebone->length;
+
+  /* Get "next" and "prev" bones - these are used for handle calculations. */
+  if (ebone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+    /* Use connected parent. */
+    if (ebone->flag & BONE_CONNECTED) {
+      prev = ebone->parent;
+    }
+    else {
+      prev = NULL;
+    }
+  }
+  else {
+    prev = ebone->bbone_prev;
+  }
+
+  if (ebone->bbone_next_type == BBONE_HANDLE_AUTO) {
+    /* Use connected child. */
+    next = ebone->bbone_child;
+  }
+  else {
+    next = ebone->bbone_next;
+  }
+
+  /* compute handles from connected bones */
+  if (prev || next) {
+    ED_armature_ebone_to_mat4(ebone, imat);
+    invert_m4(imat);
+
+    if (prev) {
+      param.use_prev = true;
+
+      if (ebone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+        zero_v3(param.prev_h);
+      }
+      else if (ebone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
+        sub_v3_v3v3(tmp, prev->tail, prev->head);
+        sub_v3_v3v3(tmp, ebone->head, tmp);
+        mul_v3_m4v3(param.prev_h, imat, tmp);
+      }
+      else {
+        param.prev_bbone = (prev->segments > 1);
+
+        mul_v3_m4v3(param.prev_h, imat, prev->head);
+      }
+
+      if (!param.prev_bbone) {
+        ED_armature_ebone_to_mat4(prev, bonemat);
+        mul_m4_m4m4(param.prev_mat, imat, bonemat);
+      }
+    }
+
+    if (next) {
+      param.use_next = true;
+
+      if (ebone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+        copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
+      }
+      else if (ebone->bbone_next_type == BBONE_HANDLE_TANGENT) {
+        sub_v3_v3v3(tmp, next->tail, next->head);
+        add_v3_v3v3(tmp, ebone->tail, tmp);
+        mul_v3_m4v3(param.next_h, imat, tmp);
+      }
+      else {
+        param.next_bbone = (next->segments > 1);
+
+        mul_v3_m4v3(param.next_h, imat, next->tail);
+      }
+
+      ED_armature_ebone_to_mat4(next, bonemat);
+      mul_m4_m4m4(param.next_mat, imat, bonemat);
+    }
+  }
+
+  param.ease1 = ebone->ease1;
+  param.ease2 = ebone->ease2;
+  param.roll1 = ebone->roll1;
+  param.roll2 = ebone->roll2;
+
+  if (prev && (ebone->flag & BONE_ADD_PARENT_END_ROLL)) {
+    param.roll1 += prev->roll2;
+  }
+
+  param.scale_in_x = ebone->scale_in_x;
+  param.scale_in_y = ebone->scale_in_y;
+
+  param.scale_out_x = ebone->scale_out_x;
+  param.scale_out_y = ebone->scale_out_y;
+
+  param.curve_in_x = ebone->curve_in_x;
+  param.curve_in_y = ebone->curve_in_y;
+
+  param.curve_out_x = ebone->curve_out_x;
+  param.curve_out_y = ebone->curve_out_y;
+
+  ebone->segments = BKE_pchan_bbone_spline_compute(&param, false, (Mat4 *)result_array);
+}
+
+static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pchan)
+{
+  float s[4][4], ebmat[4][4];
+  float length, xwidth, zwidth;
+  float(*bone_mat)[4];
+  short bbone_segments;
+
+  /* TODO : This should be moved to depsgraph or armature refresh
+   * and not be tight to the draw pass creation.
+   * This would refresh armature without invalidating the draw cache */
+  if (pchan) {
+    length = pchan->bone->length;
+    xwidth = pchan->bone->xwidth;
+    zwidth = pchan->bone->zwidth;
+    bone_mat = pchan->pose_mat;
+    bbone_segments = pchan->bone->segments;
+  }
+  else {
+    eBone->length = len_v3v3(eBone->tail, eBone->head);
+    ED_armature_ebone_to_mat4(eBone, ebmat);
+
+    length = eBone->length;
+    xwidth = eBone->xwidth;
+    zwidth = eBone->zwidth;
+    bone_mat = ebmat;
+    bbone_segments = eBone->segments;
+  }
+
+  size_to_mat4(s, (const float[3]){xwidth, length / bbone_segments, zwidth});
+
+  /* Compute BBones segment matrices... */
+  /* Note that we need this even for one-segment bones, because box drawing need specific weirdo
+   * matrix for the box, that we cannot use to draw end points & co. */
+  if (pchan) {
+    Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+    if (bbone_segments > 1) {
+      BKE_pchan_bbone_spline_setup(pchan, false, false, bbones_mat);
+
+      for (int i = bbone_segments; i--; bbones_mat++) {
+        mul_m4_m4m4(bbones_mat->mat, bbones_mat->mat, s);
+        mul_m4_m4m4(bbones_mat->mat, bone_mat, bbones_mat->mat);
+      }
+    }
+    else {
+      mul_m4_m4m4(bbones_mat->mat, bone_mat, s);
+    }
+  }
+  else {
+    float(*bbones_mat)[4][4] = eBone->disp_bbone_mat;
+
+    if (bbone_segments > 1) {
+      ebone_spline_preview(eBone, bbones_mat);
+
+      for (int i = bbone_segments; i--; bbones_mat++) {
+        mul_m4_m4m4(*bbones_mat, *bbones_mat, s);
+        mul_m4_m4m4(*bbones_mat, bone_mat, *bbones_mat);
+      }
+    }
+    else {
+      mul_m4_m4m4(*bbones_mat, bone_mat, s);
+    }
+  }
+
+  /* Grrr... We need default display matrix to draw end points, axes, etc. :( */
+  draw_bone_update_disp_matrix_default(eBone, pchan);
+}
+
+static void draw_bone_update_disp_matrix_custom(bPoseChannel *pchan)
+{
+  float s[4][4];
+  float length;
+  float(*bone_mat)[4];
+  float(*disp_mat)[4];
+  float(*disp_tail_mat)[4];
+
+  /* See TODO above */
+  length = PCHAN_CUSTOM_DRAW_SIZE(pchan);
+  bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
+  disp_mat = pchan->disp_mat;
+  disp_tail_mat = pchan->disp_tail_mat;
+
+  scale_m4_fl(s, length);
+  mul_m4_m4m4(disp_mat, bone_mat, s);
+  copy_m4_m4(disp_tail_mat, disp_mat);
+  translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
+}
+
+static void draw_axes(ArmatureDrawContext *ctx, EditBone *eBone, bPoseChannel *pchan)
+{
+  float final_col[4];
+  const float *col = (ctx->const_color) ?
+                         ctx->const_color :
+                         (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? ctx->color.text_hi :
+                                                                     ctx->color.text;
+  copy_v4_v4(final_col, col);
+  /* Mix with axes color. */
+  final_col[3] = (ctx->const_color) ? 1.0 : (BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? 0.3 : 0.8;
+  drw_shgroup_bone_axes(ctx, BONE_VAR(eBone, pchan, disp_mat), final_col);
+}
+
+static void draw_points(ArmatureDrawContext *ctx,
+                        const EditBone *eBone,
+                        const bPoseChannel *pchan,
+                        const bArmature *arm,
+                        const int boneflag,
+                        const short constflag,
+                        const int select_id)
+{
+  float col_solid_root[4], col_solid_tail[4], col_wire_root[4], col_wire_tail[4];
+  float col_hint_root[4], col_hint_tail[4];
+
+  copy_v4_v4(col_solid_root, ctx->color.bone_solid);
+  copy_v4_v4(col_solid_tail, ctx->color.bone_solid);
+  copy_v4_v4(col_wire_root, (ctx->const_color) ? ctx->const_color : ctx->color.vertex);
+  copy_v4_v4(col_wire_tail, (ctx->const_color) ? ctx->const_color : ctx->color.vertex);
+
+  const bool is_envelope_draw = (arm->drawtype == ARM_ENVELOPE);
+  const float envelope_ignore = -1.0f;
+
+  col_wire_tail[3] = col_wire_root[3] = get_bone_wire_thickness(ctx, boneflag);
+
+  /* Edit bone points can be selected */
+  if (eBone) {
+    if (eBone->flag & BONE_ROOTSEL) {
+      copy_v3_v3(col_wire_root, ctx->color.vertex_select);
+    }
+    if (eBone->flag & BONE_TIPSEL) {
+      copy_v3_v3(col_wire_tail, ctx->color.vertex_select);
+    }
+  }
+  else if (arm->flag & ARM_POSEMODE) {
+    const float *solid_color = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+    const float *wire_color = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+    copy_v4_v4(col_wire_tail, wire_color);
+    copy_v4_v4(col_wire_root, wire_color);
+    copy_v4_v4(col_solid_tail, solid_color);
+    copy_v4_v4(col_solid_root, solid_color);
+  }
+
+  bone_hint_color_shade(col_hint_root, (ctx->const_color) ? col_solid_root : col_wire_root);
+  bone_hint_color_shade(col_hint_tail, (ctx->const_color) ? col_solid_tail : col_wire_tail);
+
+  /* Draw root point if we are not connected to our parent */
+  if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+                (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+    if (select_id != -1) {
+      DRW_select_load_id(select_id | BONESEL_ROOT);
+    }
+
+    if (eBone) {
+      if (is_envelope_draw) {
+        drw_shgroup_bone_envelope(ctx,
+                                  eBone->disp_mat,
+                                  col_solid_root,
+                                  col_hint_root,
+                                  col_wire_root,
+                                  &eBone->rad_head,
+                                  &envelope_ignore);
+      }
+      else {
+        drw_shgroup_bone_point(ctx, eBone->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+      }
+    }
+    else {
+      Bone *bone = pchan->bone;
+      if (is_envelope_draw) {
+        drw_shgroup_bone_envelope(ctx,
+                                  pchan->disp_mat,
+                                  col_solid_root,
+                                  col_hint_root,
+                                  col_wire_root,
+                                  &bone->rad_head,
+                                  &envelope_ignore);
+      }
+      else {
+        drw_shgroup_bone_point(ctx, pchan->disp_mat, col_solid_root, col_hint_root, col_wire_root);
+      }
+    }
+  }
+
+  /*  Draw tip point */
+  if (select_id != -1) {
+    DRW_select_load_id(select_id | BONESEL_TIP);
+  }
+
+  if (is_envelope_draw) {
+    const float *rad_tail = eBone ? &eBone->rad_tail : &pchan->bone->rad_tail;
+    drw_shgroup_bone_envelope(ctx,
+                              BONE_VAR(eBone, pchan, disp_mat),
+                              col_solid_tail,
+                              col_hint_tail,
+                              col_wire_tail,
+                              &envelope_ignore,
+                              rad_tail);
+  }
+  else {
+    drw_shgroup_bone_point(
+        ctx, BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail, col_hint_tail, col_wire_tail);
+  }
+
+  if (select_id != -1) {
+    DRW_select_load_id(-1);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Bones
+ * \{ */
+
+static void draw_bone_custom_shape(ArmatureDrawContext *ctx,
+                                   EditBone *eBone,
+                                   bPoseChannel *pchan,
+                                   bArmature *arm,
+                                   const int boneflag,
+                                   const short constflag,
+                                   const int select_id)
+{
+  const float *col_solid = get_bone_solid_color(ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+  const float(*disp_mat)[4] = pchan->disp_mat;
+
+  if (select_id != -1) {
+    DRW_select_load_id(select_id | BONESEL_BONE);
+  }
+
+  if (pchan->custom->type == OB_EMPTY) {
+    Object *ob = pchan->custom;
+    if (ob->empty_drawtype != OB_EMPTY_IMAGE) {
+      drw_shgroup_bone_custom_empty(ctx, disp_mat, col_wire, pchan->custom);
+    }
+  }
+  if ((boneflag & BONE_DRAWWIRE) == 0) {
+    drw_shgroup_bone_custom_solid(ctx, disp_mat, col_solid, col_hint, col_wire, pchan->custom);
+  }
+  else {
+    drw_shgroup_bone_custom_wire(ctx, disp_mat, col_wire, pchan->custom);
+  }
+
+  if (select_id != -1) {
+    DRW_select_load_id(-1);
+  }
+}
+
+static void draw_bone_envelope(ArmatureDrawContext *ctx,
+                               EditBone *eBone,
+                               bPoseChannel *pchan,
+                               bArmature *arm,
+                               const int boneflag,
+                               const short constflag,
+                               const int select_id)
+{
+  const float *col_solid = get_bone_solid_with_consts_color(
+      ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+  float *rad_head, *rad_tail, *distance;
+  if (eBone) {
+    rad_tail = &eBone->rad_tail;
+    distance = &eBone->dist;
+    rad_head = (eBone->parent && (boneflag & BONE_CONNECTED)) ? &eBone->parent->rad_tail :
+                                                                &eBone->rad_head;
+  }
+  else {
+    rad_tail = &pchan->bone->rad_tail;
+    distance = &pchan->bone->dist;
+    rad_head = (pchan->parent && (boneflag & BONE_CONNECTED)) ? &pchan->parent->bone->rad_tail :
+                                                                &pchan->bone->rad_head;
+  }
+
+  if ((select_id == -1) && (boneflag & BONE_NO_DEFORM) == 0 &&
+      ((boneflag & BONE_SELECTED) || (eBone && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL))))) {
+    drw_shgroup_bone_envelope_distance(
+        ctx, BONE_VAR(eBone, pchan, disp_mat), rad_head, rad_tail, distance);
+  }
+
+  if (select_id != -1) {
+    DRW_select_load_id(select_id | BONESEL_BONE);
+  }
+
+  drw_shgroup_bone_envelope(
+      ctx, BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire, rad_head, rad_tail);
+
+  if (select_id != -1) {
+    DRW_select_load_id(-1);
+  }
+
+  draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+static void draw_bone_line(ArmatureDrawContext *ctx,
+                           EditBone *eBone,
+                           bPoseChannel *pchan,
+                           bArmature *arm,
+                           const int boneflag,
+                           const short constflag,
+                           const int select_id)
+{
+  const float *col_bone = get_bone_solid_with_consts_color(
+      ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+  const float no_display[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+  const float *col_head = no_display;
+  const float *col_tail = col_bone;
+
+  if (ctx->const_color != NULL) {
+    col_wire = no_display; /* actually shrink the display. */
+    col_bone = col_head = col_tail = ctx->const_color;
+  }
+  else {
+    if (eBone) {
+      if (eBone->flag & BONE_TIPSEL) {
+        col_tail = ctx->color.vertex_select;
+      }
+      if (boneflag & BONE_SELECTED) {
+        col_bone = ctx->color.edge_select;
+      }
+      col_wire = ctx->color.wire;
+    }
+
+    /* Draw root point if we are not connected to our parent. */
+    if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+                  (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+
+      if (eBone) {
+        col_head = (eBone->flag & BONE_ROOTSEL) ? ctx->color.vertex_select : col_bone;
+      }
+      else {
+        col_head = col_bone;
+      }
+    }
+  }
+
+  if (select_id == -1) {
+    /* Not in selection mode, draw everything at once. */
+    drw_shgroup_bone_stick(
+        ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, col_head, col_tail);
+  }
+  else {
+    /* In selection mode, draw bone, root and tip separately. */
+    DRW_select_load_id(select_id | BONESEL_BONE);
+    drw_shgroup_bone_stick(
+        ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, col_bone, no_display, no_display);
+
+    if (col_head[3] > 0.0f) {
+      DRW_select_load_id(select_id | BONESEL_ROOT);
+      drw_shgroup_bone_stick(
+          ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, col_head, no_display);
+    }
+
+    DRW_select_load_id(select_id | BONESEL_TIP);
+    drw_shgroup_bone_stick(
+        ctx, BONE_VAR(eBone, pchan, disp_mat), col_wire, no_display, no_display, col_tail);
+
+    DRW_select_load_id(-1);
+  }
+}
+
+static void draw_bone_wire(ArmatureDrawContext *ctx,
+                           EditBone *eBone,
+                           bPoseChannel *pchan,
+                           bArmature *arm,
+                           const int boneflag,
+                           const short constflag,
+                           const int select_id)
+{
+  const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+  if (select_id != -1) {
+    DRW_select_load_id(select_id | BONESEL_BONE);
+  }
+
+  if (pchan) {
+    Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+    BLI_assert(bbones_mat != NULL);
+
+    for (int i = pchan->bone->segments; i--; bbones_mat++) {
+      drw_shgroup_bone_wire(ctx, bbones_mat->mat, col_wire);
+    }
+  }
+  else if (eBone) {
+    for (int i = 0; i < eBone->segments; i++) {
+      drw_shgroup_bone_wire(ctx, eBone->disp_bbone_mat[i], col_wire);
+    }
+  }
+
+  if (select_id != -1) {
+    DRW_select_load_id(-1);
+  }
+
+  if (eBone) {
+    draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+  }
+}
+
+static void draw_bone_box(ArmatureDrawContext *ctx,
+                          EditBone *eBone,
+                          bPoseChannel *pchan,
+                          bArmature *arm,
+                          const int boneflag,
+                          const short constflag,
+                          const int select_id)
+{
+  const float *col_solid = get_bone_solid_with_consts_color(
+      ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+  if (select_id != -1) {
+    DRW_select_load_id(select_id | BONESEL_BONE);
+  }
+
+  if (pchan) {
+    Mat4 *bbones_mat = (Mat4 *)pchan->draw_data->bbone_matrix;
+    BLI_assert(bbones_mat != NULL);
+
+    for (int i = pchan->bone->segments; i--; bbones_mat++) {
+      drw_shgroup_bone_box(ctx, bbones_mat->mat, col_solid, col_hint, col_wire);
+    }
+  }
+  else if (eBone) {
+    for (int i = 0; i < eBone->segments; i++) {
+      drw_shgroup_bone_box(ctx, eBone->disp_bbone_mat[i], col_solid, col_hint, col_wire);
+    }
+  }
+
+  if (select_id != -1) {
+    DRW_select_load_id(-1);
+  }
+
+  if (eBone) {
+    draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+  }
+}
+
+static void draw_bone_octahedral(ArmatureDrawContext *ctx,
+                                 EditBone *eBone,
+                                 bPoseChannel *pchan,
+                                 bArmature *arm,
+                                 const int boneflag,
+                                 const short constflag,
+                                 const int select_id)
+{
+  const float *col_solid = get_bone_solid_with_consts_color(
+      ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_wire = get_bone_wire_color(ctx, eBone, pchan, arm, boneflag, constflag);
+  const float *col_hint = get_bone_hint_color(ctx, eBone, pchan, arm, boneflag, constflag);
+
+  if (select_id != -1) {
+    DRW_select_load_id(select_id | BONESEL_BONE);
+  }
+
+  drw_shgroup_bone_octahedral(
+      ctx, BONE_VAR(eBone, pchan, disp_mat), col_solid, col_hint, col_wire);
+
+  if (select_id != -1) {
+    DRW_select_load_id(-1);
+  }
+
+  draw_points(ctx, eBone, pchan, arm, boneflag, constflag, select_id);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Degrees of Freedom
+ * \{ */
+
+static void draw_bone_degrees_of_freedom(ArmatureDrawContext *ctx, bPoseChannel *pchan)
+{
+  BoneInstanceData inst_data;
+  float tmp[4][4], posetrans[4][4];
+  float xminmax[2], zminmax[2];
+  float color[4];
+
+  if (ctx->dof_sphere == NULL) {
+    return;
+  }
+
+  /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
+  xminmax[0] = sinf(pchan->limitmin[0] * 0.5f);
+  xminmax[1] = sinf(pchan->limitmax[0] * 0.5f);
+  zminmax[0] = sinf(pchan->limitmin[2] * 0.5f);
+  zminmax[1] = sinf(pchan->limitmax[2] * 0.5f);
+
+  unit_m4(posetrans);
+  translate_m4(posetrans, pchan->pose_mat[3][0], pchan->pose_mat[3][1], pchan->pose_mat[3][2]);
+  /* in parent-bone pose space... */
+  if (pchan->parent) {
+    copy_m4_m4(tmp, pchan->parent->pose_mat);
+    zero_v3(tmp[3]);
+    mul_m4_m4m4(posetrans, posetrans, tmp);
+  }
+  /* ... but own restspace */
+  mul_m4_m4m3(posetrans, posetrans, pchan->bone->bone_mat);
+
+  float scale = pchan->bone->length * pchan->size[1];
+  scale_m4_fl(tmp, scale);
+  tmp[1][1] = -tmp[1][1];
+  mul_m4_m4m4(posetrans, posetrans, tmp);
+
+  /* into world space. */
+  mul_m4_m4m4(inst_data.mat, ctx->ob->obmat, posetrans);
+
+  if ((pchan->ikflag & BONE_IK_XLIMIT) && (pchan->ikflag & BONE_IK_ZLIMIT)) {
+    bone_instance_data_set_angle_minmax(
+        &inst_data, xminmax[0], zminmax[0], xminmax[1], zminmax[1]);
+
+    copy_v4_fl4(color, 0.25f, 0.25f, 0.25f, 0.25f);
+    DRW_buffer_add_entry(ctx->dof_sphere, color, &inst_data);
+
+    copy_v4_fl4(color, 0.0f, 0.0f, 0.0f, 1.0f);
+    DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+  }
+  if (pchan->ikflag & BONE_IK_XLIMIT) {
+    bone_instance_data_set_angle_minmax(&inst_data, xminmax[0], 0.0f, xminmax[1], 0.0f);
+    copy_v4_fl4(color, 1.0f, 0.0f, 0.0f, 1.0f);
+    DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+  }
+  if (pchan->ikflag & BONE_IK_ZLIMIT) {
+    bone_instance_data_set_angle_minmax(&inst_data, 0.0f, zminmax[0], 0.0f, zminmax[1]);
+    copy_v4_fl4(color, 0.0f, 0.0f, 1.0f, 1.0f);
+    DRW_buffer_add_entry(ctx->dof_lines, color, &inst_data);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw Relationships
+ * \{ */
+
+static void pchan_draw_ik_lines(ArmatureDrawContext *ctx,
+                                bPoseChannel *pchan,
+                                const bool only_temp,
+                                const int constflag)
+{
+  bConstraint *con;
+  bPoseChannel *parchan;
+  float *line_start = NULL, *line_end = NULL;
+
+  for (con = pchan->constraints.first; con; con = con->next) {
+    if (con->enforce == 0.0f) {
+      continue;
+    }
+
+    switch (con->type) {
+      case CONSTRAINT_TYPE_KINEMATIC: {
+        bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+        int segcount = 0;
+
+        /* if only_temp, only draw if it is a temporary ik-chain */
+        if (only_temp && !(data->flag & CONSTRAINT_IK_TEMP)) {
+          continue;
+        }
+
+        /* exclude tip from chain? */
+        parchan = ((data->flag & CONSTRAINT_IK_TIP) == 0) ? pchan->parent : pchan;
+        line_start = parchan->pose_tail;
+
+        /* Find the chain's root */
+        while (parchan->parent) {
+          segcount++;
+          if (segcount == data->rootbone || segcount > 255) {
+            break; /* 255 is weak */
+          }
+          parchan = parchan->parent;
+        }
+
+        if (parchan) {
+          line_end = parchan->pose_head;
+
+          if (constflag & PCHAN_HAS_TARGET) {
+            drw_shgroup_bone_ik_lines(ctx, line_start, line_end);
+          }
+          else {
+            drw_shgroup_bone_ik_no_target_lines(ctx, line_start, line_end);
+          }
+        }
+        break;
+      }
+      case CONSTRAINT_TYPE_SPLINEIK: {
+        bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+        int segcount = 0;
+
+        /* don't draw if only_temp, as Spline IK chains cannot be temporary */
+        if (only_temp) {
+          continue;
+        }
+
+        parchan = pchan;
+        line_start = parchan->pose_tail;
+
+        /* Find the chain's root */
+        while (parchan->parent) {
+          segcount++;
+          /* FIXME: revise the breaking conditions */
+          if (segcount == data->chainlen || segcount > 255) {
+            break; /* 255 is weak */
+          }
+          parchan = parchan->parent;
+        }
+        /* Only draw line in case our chain is more than one bone long! */
+        if (parchan != pchan) { /* XXX revise the breaking conditions to only stop at the tail? */
+          line_end = parchan->pose_head;
+          drw_shgroup_bone_ik_spline_lines(ctx, line_start, line_end);
+        }
+        break;
+      }
+    }
+  }
+}
+
+static void draw_bone_relations(ArmatureDrawContext *ctx,
+                                EditBone *ebone,
+                                bPoseChannel *pchan,
+                                bArmature *arm,
+                                const int boneflag,
+                                const short constflag)
+{
+  if (ebone && ebone->parent) {
+    if (ctx->do_relations) {
+      /* Always draw for unconnected bones, regardless of selection,
+       * since riggers will want to know about the links between bones
+       */
+      if ((boneflag & BONE_CONNECTED) == 0) {
+        drw_shgroup_bone_relationship_lines(ctx, ebone->head, ebone->parent->tail);
+      }
+    }
+  }
+  else if (pchan && pchan->parent) {
+    if (ctx->do_relations) {
+      /* Only draw if bone or its parent is selected - reduces viewport complexity with complex
+       * rigs */
+      if ((boneflag & BONE_SELECTED) ||
+          (pchan->parent->bone && (pchan->parent->bone->flag & BONE_SELECTED))) {
+        if ((boneflag & BONE_CONNECTED) == 0) {
+          drw_shgroup_bone_relationship_lines(ctx, pchan->pose_head, pchan->parent->pose_tail);
+        }
+      }
+    }
+
+    /* Draw a line to IK root bone if bone is selected. */
+    if (arm->flag & ARM_POSEMODE) {
+      if (constflag & (PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK)) {
+        if (boneflag & BONE_SELECTED) {
+          pchan_draw_ik_lines(ctx, pchan, !ctx->do_relations, constflag);
+        }
+      }
+    }
+  }
+}
+
+static void draw_bone_name(ArmatureDrawContext *ctx,
+                           EditBone *eBone,
+                           bPoseChannel *pchan,
+                           bArmature *arm,
+                           const int boneflag)
+{
+  struct DRWTextStore *dt = DRW_text_cache_ensure();
+  uchar color[4];
+  float vec[3];
+
+  bool highlight = (pchan && (arm->flag & ARM_POSEMODE) && (boneflag & BONE_SELECTED)) ||
+                   (eBone && (eBone->flag & BONE_SELECTED));
+
+  UI_GetThemeColor4ubv(highlight ? TH_TEXT_HI : TH_TEXT, color);
+
+  float *head = pchan ? pchan->pose_head : eBone->head;
+  float *tail = pchan ? pchan->pose_tail : eBone->tail;
+  mid_v3_v3v3(vec, head, tail);
+  mul_m4_v3(ctx->ob->obmat, vec);
+
+  DRW_text_cache_add(dt,
+                     vec,
+                     (pchan) ? pchan->name : eBone->name,
+                     (pchan) ? strlen(pchan->name) : strlen(eBone->name),
+                     10,
+                     0,
+                     DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+                     color);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Draw Loops
+ * \{ */
+
+static void draw_armature_edit(ArmatureDrawContext *ctx)
+{
+  Object *ob = ctx->ob;
+  EditBone *eBone;
+  int index;
+  const bool is_select = DRW_state_is_select();
+  const bool show_text = DRW_state_show_text();
+
+  const Object *ob_orig = DEG_get_original_object(ob);
+  /* FIXME(campbell): We should be able to use the CoW object,
+   * however the active bone isn't updated. Long term solution is an 'EditArmature' struct.
+   * for now we can draw from the original armature. See: T66773. */
+  // bArmature *arm = ob->data;
+  bArmature *arm = ob_orig->data;
+
+  edbo_compute_bbone_child(arm);
+
+  for (eBone = arm->edbo->first, index = ob_orig->runtime.select_id; eBone;
+       eBone = eBone->next, index += 0x10000) {
+    if (eBone->layer & arm->layer) {
+      if ((eBone->flag & BONE_HIDDEN_A) == 0) {
+        const int select_id = is_select ? index : (uint)-1;
+        const short constflag = 0;
+
+        /* catch exception for bone with hidden parent */
+        int boneflag = eBone->flag;
+        if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) {
+          boneflag &= ~BONE_CONNECTED;
+        }
+
+        /* set temporary flag for drawing bone as active, but only if selected */
+        if (eBone == arm->act_edbone) {
+          boneflag |= BONE_DRAW_ACTIVE;
+        }
+
+        draw_bone_relations(ctx, eBone, NULL, arm, boneflag, constflag);
+
+        if (arm->drawtype == ARM_ENVELOPE) {
+          draw_bone_update_disp_matrix_default(eBone, NULL);
+          draw_bone_envelope(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+        }
+        else if (arm->drawtype == ARM_LINE) {
+          draw_bone_update_disp_matrix_default(eBone, NULL);
+          draw_bone_line(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+        }
+        else if (arm->drawtype == ARM_WIRE) {
+          draw_bone_update_disp_matrix_bbone(eBone, NULL);
+          draw_bone_wire(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+        }
+        else if (arm->drawtype == ARM_B_BONE) {
+          draw_bone_update_disp_matrix_bbone(eBone, NULL);
+          draw_bone_box(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+        }
+        else {
+          draw_bone_update_disp_matrix_default(eBone, NULL);
+          draw_bone_octahedral(ctx, eBone, NULL, arm, boneflag, constflag, select_id);
+        }
+
+        if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+          draw_bone_name(ctx, eBone, NULL, arm, boneflag);
+        }
+
+        if (arm->flag & ARM_DRAWAXES) {
+          draw_axes(ctx, eBone, NULL);
+        }
+      }
+    }
+  }
+}
+
+static void draw_armature_pose(ArmatureDrawContext *ctx)
+{
+  Object *ob = ctx->ob;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  const Scene *scene = draw_ctx->scene;
+  bArmature *arm = ob->data;
+  bPoseChannel *pchan;
+  int index = -1;
+  const bool show_text = DRW_state_show_text();
+
+  /* We can't safely draw non-updated pose, might contain NULL bone pointers... */
+  if (ob->pose->flag & POSE_RECALC) {
+    return;
+  }
+
+  bool is_pose_select = false;
+  /* Object can be edited in the scene. */
+  if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+    if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) {
+      arm->flag |= ARM_POSEMODE;
+    }
+    is_pose_select =
+        /* If we're in pose-mode or object-mode with the ability to enter pose mode. */
+        (
+            /* Draw as if in pose mode (when selection is possible). */
+            (arm->flag & ARM_POSEMODE) ||
+            /* When we're in object mode, which may select bones. */
+            ((ob->mode & OB_MODE_POSE) &&
+             (
+                 /* Switch from object mode when object lock is disabled. */
+                 ((draw_ctx->object_mode == OB_MODE_OBJECT) &&
+                  (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) ||
+                 /* Allow selection when in weight-paint mode
+                  * (selection code ensures this wont become active). */
+                 ((draw_ctx->object_mode == OB_MODE_WEIGHT_PAINT) &&
+                  (draw_ctx->object_pose != NULL))))) &&
+        DRW_state_is_select();
+
+    if (is_pose_select) {
+      const Object *ob_orig = DEG_get_original_object(ob);
+      index = ob_orig->runtime.select_id;
+    }
+  }
+
+  for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, index += 0x10000) {
+    Bone *bone = pchan->bone;
+    const bool bone_visible = (bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0;
+
+    if (bone_visible) {
+      if (bone->layer & arm->layer) {
+        const bool draw_dofs = !is_pose_select && ctx->show_relations &&
+                               (arm->flag & ARM_POSEMODE) && (bone->flag & BONE_SELECTED) &&
+                               ((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
+                               (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT));
+        const int select_id = is_pose_select ? index : (uint)-1;
+        const short constflag = pchan->constflag;
+
+        pchan_draw_data_init(pchan);
+
+        if (!ctx->const_color) {
+          set_pchan_colorset(ctx, ob, pchan);
+        }
+
+        int boneflag = bone->flag;
+        /* catch exception for bone with hidden parent */
+        boneflag = bone->flag;
+        if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
+          boneflag &= ~BONE_CONNECTED;
+        }
+
+        /* set temporary flag for drawing bone as active, but only if selected */
+        if (bone == arm->act_bone) {
+          boneflag |= BONE_DRAW_ACTIVE;
+        }
+
+        draw_bone_relations(ctx, NULL, pchan, arm, boneflag, constflag);
+
+        if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) {
+          draw_bone_update_disp_matrix_custom(pchan);
+          draw_bone_custom_shape(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+        }
+        else if (arm->drawtype == ARM_ENVELOPE) {
+          draw_bone_update_disp_matrix_default(NULL, pchan);
+          draw_bone_envelope(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+        }
+        else if (arm->drawtype == ARM_LINE) {
+          draw_bone_update_disp_matrix_default(NULL, pchan);
+          draw_bone_line(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+        }
+        else if (arm->drawtype == ARM_WIRE) {
+          draw_bone_update_disp_matrix_bbone(NULL, pchan);
+          draw_bone_wire(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+        }
+        else if (arm->drawtype == ARM_B_BONE) {
+          draw_bone_update_disp_matrix_bbone(NULL, pchan);
+          draw_bone_box(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+        }
+        else {
+          draw_bone_update_disp_matrix_default(NULL, pchan);
+          draw_bone_octahedral(ctx, NULL, pchan, arm, boneflag, constflag, select_id);
+        }
+
+        if (draw_dofs) {
+          draw_bone_degrees_of_freedom(ctx, pchan);
+        }
+
+        if (show_text && (arm->flag & ARM_DRAWNAMES)) {
+          draw_bone_name(ctx, NULL, pchan, arm, boneflag);
+        }
+
+        if (arm->flag & ARM_DRAWAXES) {
+          draw_axes(ctx, NULL, pchan);
+        }
+      }
+    }
+  }
+
+  arm->flag &= ~ARM_POSEMODE;
+}
+
+static void armature_context_setup(ArmatureDrawContext *ctx,
+                                   OVERLAY_PrivateData *pd,
+                                   Object *ob,
+                                   const bool do_envelope_dist,
+                                   const bool is_pose_mode,
+                                   float *const_color)
+{
+  const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0 ||
+                       (pd->armature.do_pose_fade_geom && is_pose_mode);
+  const bool is_filled = !pd->armature.transparent || do_envelope_dist;
+  bArmature *arm = ob->data;
+  OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[is_xray];
+
+  switch (arm->drawtype) {
+    case ARM_ENVELOPE:
+      ctx->envelope_outline = cb->envelope_outline;
+      ctx->envelope_solid = (is_filled) ? cb->envelope_solid : NULL;
+      ctx->envelope_distance = (do_envelope_dist) ? cb->envelope_distance : NULL;
+      break;
+    case ARM_LINE:
+      ctx->stick = cb->stick;
+      break;
+    case ARM_WIRE:
+      ctx->wire = cb->wire;
+      break;
+    case ARM_B_BONE:
+      ctx->outline = cb->box_outline;
+      ctx->solid = (is_filled) ? cb->box_solid : NULL;
+      break;
+    case ARM_OCTA:
+      ctx->outline = cb->octa_outline;
+      ctx->solid = (is_filled) ? cb->octa_solid : NULL;
+      break;
+  }
+  ctx->ob = ob;
+  ctx->extras = &pd->extra_call_buffers[is_xray];
+  ctx->dof_lines = cb->dof_lines;
+  ctx->dof_sphere = cb->dof_sphere;
+  ctx->point_solid = (is_filled) ? cb->point_solid : NULL;
+  ctx->point_outline = cb->point_outline;
+  ctx->custom_solid = (is_filled) ? cb->custom_solid : NULL;
+  ctx->custom_outline = cb->custom_outline;
+  ctx->custom_wire = cb->custom_solid; /* Use same shader. */
+  ctx->custom_shapes_ghash = cb->custom_shapes_ghash;
+  ctx->transparent = pd->armature.transparent;
+  ctx->show_relations = pd->armature.show_relations;
+  ctx->const_color = const_color;
+  ctx->const_wire = (((ob->base_flag & BASE_SELECTED) || (arm->drawtype == ARM_WIRE)) ?
+                         1.5f :
+                         ((ctx->transparent) ? 1.0f : 0.0f));
+
+  /** See: 'set_pchan_color'*/
+#define NO_ALPHA(c) (((c)[3] = 1.0f), (c))
+
+  UI_GetThemeColor3fv(TH_SELECT, NO_ALPHA(ctx->color.select));
+  UI_GetThemeColorShade3fv(TH_EDGE_SELECT, 60, NO_ALPHA(ctx->color.edge_select));
+  UI_GetThemeColorShade3fv(TH_EDGE_SELECT, -20, NO_ALPHA(ctx->color.bone_select));
+  UI_GetThemeColor3fv(TH_WIRE, NO_ALPHA(ctx->color.wire));
+  UI_GetThemeColor3fv(TH_WIRE_EDIT, NO_ALPHA(ctx->color.wire_edit));
+  UI_GetThemeColor3fv(TH_BONE_SOLID, NO_ALPHA(ctx->color.bone_solid));
+  UI_GetThemeColorBlendShade3fv(
+      TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f, 0, NO_ALPHA(ctx->color.bone_active_unselect));
+  UI_GetThemeColor3fv(TH_BONE_POSE, NO_ALPHA(ctx->color.bone_pose));
+  UI_GetThemeColor3fv(TH_BONE_POSE_ACTIVE, NO_ALPHA(ctx->color.bone_pose_active));
+  UI_GetThemeColorBlendShade3fv(
+      TH_WIRE, TH_BONE_POSE, 0.15f, 0, NO_ALPHA(ctx->color.bone_pose_active_unselect));
+  UI_GetThemeColor3fv(TH_TEXT_HI, NO_ALPHA(ctx->color.text_hi));
+  UI_GetThemeColor3fv(TH_TEXT, NO_ALPHA(ctx->color.text));
+  UI_GetThemeColor3fv(TH_VERTEX_SELECT, NO_ALPHA(ctx->color.vertex_select));
+  UI_GetThemeColor3fv(TH_VERTEX, NO_ALPHA(ctx->color.vertex));
+
+#undef NO_ALPHA
+}
+
+void OVERLAY_edit_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  ArmatureDrawContext arm_ctx;
+  armature_context_setup(&arm_ctx, pd, ob, true, false, NULL);
+  draw_armature_edit(&arm_ctx);
+}
+
+void OVERLAY_pose_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  ArmatureDrawContext arm_ctx;
+  armature_context_setup(&arm_ctx, pd, ob, true, true, NULL);
+  draw_armature_pose(&arm_ctx);
+}
+
+void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  ArmatureDrawContext arm_ctx;
+  float *color;
+  DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+  armature_context_setup(&arm_ctx, pd, ob, false, false, color);
+  draw_armature_pose(&arm_ctx);
+}
+
+static bool POSE_is_driven_by_active_armature(Object *ob)
+{
+  Object *ob_arm = modifiers_isDeformedByArmature(ob);
+  if (ob_arm) {
+    const DRWContextState *draw_ctx = DRW_context_state_get();
+    bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx);
+    if (!is_active && ob_arm->proxy_from) {
+      is_active = OVERLAY_armature_is_pose_mode(ob_arm->proxy_from, draw_ctx);
+    }
+    return is_active;
+  }
+  else {
+    Object *ob_mesh_deform = modifiers_isDeformedByMeshDeform(ob);
+    if (ob_mesh_deform) {
+      /* Recursive. */
+      return POSE_is_driven_by_active_armature(ob_mesh_deform);
+    }
+  }
+  return false;
+}
+
+void OVERLAY_pose_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+  if (geom) {
+    if (POSE_is_driven_by_active_armature(ob)) {
+      DRW_shgroup_call(pd->armature_bone_select_act_grp, geom, ob);
+    }
+    else {
+      DRW_shgroup_call(pd->armature_bone_select_grp, geom, ob);
+    }
+  }
+}
+
+void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  for (int i = 0; i < 2; i++) {
+    if (pd->armature_call_buffers[i].custom_shapes_ghash) {
+      /* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
+      BLI_ghash_free(pd->armature_call_buffers[i].custom_shapes_ghash, NULL, NULL);
+    }
+  }
+}
+
+void OVERLAY_armature_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->armature_transp_ps);
+  DRW_draw_pass(psl->armature_ps[0]);
+}
+
+void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  if (psl->armature_bone_select_ps == NULL) {
+    DRW_draw_pass(psl->armature_ps[1]);
+  }
+}
+
+void OVERLAY_pose_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+  if (psl->armature_bone_select_ps != NULL) {
+    DRW_draw_pass(psl->armature_bone_select_ps);
+
+    if (DRW_state_is_fbo()) {
+      GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f);
+    }
+    /* Selection still works because we are drawing only the pose bones in this case. */
+
+    DRW_draw_pass(psl->armature_ps[1]);
+  }
+}
\ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c
new file mode 100644 (file)
index 0000000..8125334
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_curve_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  View3D *v3d = draw_ctx->v3d;
+  DRWShadingGroup *grp;
+  GPUShader *sh;
+  DRWState state;
+
+  pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+  pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
+
+  /* Run Twice for in-front passes. */
+  for (int i = 0; i < 2; i++) {
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH;
+    state |= ((i == 0) ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_ALWAYS);
+    DRW_PASS_CREATE(psl->edit_curve_wire_ps[i], state | pd->clipping_state);
+
+    sh = OVERLAY_shader_edit_curve_wire();
+    pd->edit_curve_normal_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_curve_wire_ps[i]);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_float_copy(grp, "normalSize", pd->shdata.edit_curve_normal_length);
+
+    pd->edit_curve_wire_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_curve_wire_ps[i]);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_float_copy(grp, "normalSize", 0.0f);
+  }
+  {
+    state = DRW_STATE_WRITE_COLOR;
+    DRW_PASS_CREATE(psl->edit_curve_handle_ps, state | pd->clipping_state);
+
+    sh = OVERLAY_shader_edit_curve_handle();
+    pd->edit_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles);
+    DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+    sh = OVERLAY_shader_edit_curve_point();
+    pd->edit_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  }
+}
+
+void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  bool draw_normals = (pd->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_NORMALS) != 0;
+  bool do_xray = (ob->dtx & OB_DRAWXRAY) != 0;
+
+  Curve *cu = ob->data;
+  struct GPUBatch *geom;
+
+  geom = DRW_cache_curve_edge_wire_get(ob);
+  if (geom) {
+    DRW_shgroup_call_no_cull(pd->edit_curve_wire_grp[do_xray], geom, ob);
+  }
+
+  if ((cu->flag & CU_3D) && draw_normals) {
+    geom = DRW_cache_curve_edge_normal_get(ob);
+    DRW_shgroup_call_instances(pd->edit_curve_normal_grp[do_xray], ob, geom, 3);
+  }
+
+  geom = DRW_cache_curve_edge_overlay_get(ob);
+  if (geom) {
+    DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
+  }
+
+  geom = DRW_cache_curve_vert_overlay_get(ob, pd->edit_curve.show_handles);
+  if (geom) {
+    DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
+  }
+}
+
+void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  struct GPUBatch *geom;
+
+  geom = DRW_cache_curve_edge_overlay_get(ob);
+  if (geom) {
+    DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
+  }
+
+  geom = DRW_cache_curve_vert_overlay_get(ob, false);
+  if (geom) {
+    DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
+  }
+}
+
+void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->edit_curve_wire_ps[0]);
+  DRW_draw_pass(psl->edit_curve_wire_ps[1]);
+
+  DRW_draw_pass(psl->edit_curve_handle_ps);
+}
\ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
new file mode 100644 (file)
index 0000000..e03ed7f
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "DNA_mesh_types.h"
+
+#include "BKE_editmesh.h"
+
+#include "draw_cache_impl.h"
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+#define OVERLAY_EDIT_TEXT \
+  (V3D_OVERLAY_EDIT_EDGE_LEN | V3D_OVERLAY_EDIT_FACE_AREA | V3D_OVERLAY_EDIT_FACE_ANG | \
+   V3D_OVERLAY_EDIT_EDGE_ANG | V3D_OVERLAY_EDIT_INDICES)
+
+void OVERLAY_edit_mesh_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_TextureList *txl = vedata->txl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+
+  pd->edit_mesh.do_zbufclip = XRAY_FLAG_ENABLED(draw_ctx->v3d);
+
+  if (!pd->edit_mesh.do_zbufclip) {
+    /* Small texture which will have very small impact on rendertime. */
+    DRW_texture_ensure_2d(&txl->dummy_depth_tx, 1, 1, GPU_DEPTH_COMPONENT24, 0);
+  }
+
+  /* Create view with depth offset */
+  DRWView *default_view = (DRWView *)DRW_view_default_get();
+  /* Don't use AA view (pd->view_default) because edit mode already has anti-aliasing. */
+  pd->view_edit_faces = default_view;
+  pd->view_edit_faces_cage = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 0.5f);
+  pd->view_edit_edges = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 1.0f);
+  pd->view_edit_verts = DRW_view_create_with_zoffset(default_view, draw_ctx->rv3d, 1.5f);
+}
+
+void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_TextureList *txl = vedata->txl;
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  OVERLAY_ShadingData *shdata = &pd->shdata;
+  DRWShadingGroup *grp = NULL;
+  GPUShader *sh = NULL;
+  DRWState state = 0;
+
+  DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ToolSettings *tsettings = draw_ctx->scene->toolsettings;
+  View3D *v3d = draw_ctx->v3d;
+  bool select_vert = pd->edit_mesh.select_vert = (tsettings->selectmode & SCE_SELECT_VERTEX) != 0;
+  bool select_face = pd->edit_mesh.select_face = (tsettings->selectmode & SCE_SELECT_FACE) != 0;
+  bool select_edge = pd->edit_mesh.select_edge = (tsettings->selectmode & SCE_SELECT_EDGE) != 0;
+
+  bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+  bool show_face_dots = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) != 0 ||
+                        pd->edit_mesh.do_zbufclip;
+
+  pd->edit_mesh.ghost_ob = 0;
+  pd->edit_mesh.edit_ob = 0;
+  pd->edit_mesh.do_faces = true;
+  pd->edit_mesh.do_edges = true;
+
+  int *mask = shdata->data_mask;
+  mask[0] = 0xFF; /* Face Flag */
+  mask[1] = 0xFF; /* Edge Flag */
+
+  const int flag = pd->edit_mesh.flag = v3d->overlay.edit_flag;
+
+  SET_FLAG_FROM_TEST(mask[0], flag & V3D_OVERLAY_EDIT_FACES, VFLAG_FACE_SELECTED);
+  SET_FLAG_FROM_TEST(mask[0], flag & V3D_OVERLAY_EDIT_FREESTYLE_FACE, VFLAG_FACE_FREESTYLE);
+  SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_FREESTYLE_EDGE, VFLAG_EDGE_FREESTYLE);
+  SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_SEAMS, VFLAG_EDGE_SEAM);
+  SET_FLAG_FROM_TEST(mask[1], flag & V3D_OVERLAY_EDIT_SHARP, VFLAG_EDGE_SHARP);
+  SET_FLAG_FROM_TEST(mask[2], flag & V3D_OVERLAY_EDIT_CREASES, 0xFF);
+  SET_FLAG_FROM_TEST(mask[3], flag & V3D_OVERLAY_EDIT_BWEIGHTS, 0xFF);
+
+  if ((flag & V3D_OVERLAY_EDIT_FACES) == 0) {
+    pd->edit_mesh.do_faces = false;
+    pd->edit_mesh.do_zbufclip = false;
+  }
+  if ((flag & V3D_OVERLAY_EDIT_EDGES) == 0) {
+    if ((tsettings->selectmode & SCE_SELECT_EDGE) == 0) {
+      if ((v3d->shading.type < OB_SOLID) || (v3d->shading.flag & V3D_SHADING_XRAY)) {
+        /* Special case, when drawing wire, draw edges, see: T67637. */
+      }
+      else {
+        pd->edit_mesh.do_edges = false;
+      }
+    }
+  }
+
+  float backwire_opacity = (pd->edit_mesh.do_zbufclip) ? v3d->overlay.backwire_opacity : 1.0f;
+  float face_alpha = (do_occlude_wire || !pd->edit_mesh.do_faces) ? 0.0f : 1.0f;
+  GPUTexture **depth_tex = (pd->edit_mesh.do_zbufclip) ? &dtxl->depth : &txl->dummy_depth_tx;
+
+  if (select_face && !pd->edit_mesh.do_faces && pd->edit_mesh.do_edges) {
+    /* Force display of face centers in this case because that's
+     * the only way to see if a face is selected. */
+    show_face_dots = true;
+  }
+
+  {
+    /* TODO(fclem) Shouldn't this be going into the paint overlay? */
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+    DRW_PASS_CREATE(psl->edit_mesh_weight_ps, state | pd->clipping_state);
+
+    sh = OVERLAY_shader_paint_weight();
+    pd->edit_mesh_weight_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_weight_ps);
+    DRW_shgroup_uniform_float_copy(grp, "opacity", 1.0);
+    DRW_shgroup_uniform_bool_copy(grp, "drawContours", false);
+    DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  }
+  /* Run Twice for in-front passes. */
+  for (int i = 0; i < 2; i++) {
+    /* Complementary Depth Pass */
+    state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+    DRW_PASS_CREATE(psl->edit_mesh_depth_ps[i], state | pd->clipping_state);
+
+    sh = OVERLAY_shader_depth_only();
+    pd->edit_mesh_depth_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_depth_ps[i]);
+  }
+  {
+    /* Normals */
+    state = DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
+            (pd->edit_mesh.do_zbufclip ? DRW_STATE_BLEND_ALPHA : 0);
+    DRW_PASS_CREATE(psl->edit_mesh_normals_ps, state | pd->clipping_state);
+
+    sh = OVERLAY_shader_edit_mesh_normal();
+    pd->edit_mesh_normals_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_normals_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_float_copy(grp, "normalSize", v3d->overlay.normals_length);
+    DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+    DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+  }
+  {
+    /* Mesh Analysis Pass */
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+    DRW_PASS_CREATE(psl->edit_mesh_analysis_ps, state | pd->clipping_state);
+
+    sh = OVERLAY_shader_edit_mesh_analysis();
+    pd->edit_mesh_analysis_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_analysis_ps);
+    DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+  }
+  /* Run Twice for in-front passes. */
+  for (int i = 0; i < 2; i++) {
+    GPUShader *edge_sh = OVERLAY_shader_edit_mesh_edge(!select_vert);
+    GPUShader *face_sh = OVERLAY_shader_edit_mesh_face();
+    const bool do_zbufclip = (i == 0 && pd->edit_mesh.do_zbufclip);
+    DRWState state_common = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
+                            DRW_STATE_BLEND_ALPHA;
+    /* Faces */
+    /* Cage geom needs to be offsetted to avoid Z-fighting. */
+    for (int j = 0; j < 2; j++) {
+      DRWPass **edit_face_ps = (j == 0) ? &psl->edit_mesh_faces_ps[i] :
+                                          &psl->edit_mesh_faces_cage_ps[i];
+      DRWShadingGroup **shgrp = (j == 0) ? &pd->edit_mesh_faces_grp[i] :
+                                           &pd->edit_mesh_faces_cage_grp[i];
+      state = state_common;
+      DRW_PASS_CREATE(*edit_face_ps, state | pd->clipping_state);
+
+      grp = *shgrp = DRW_shgroup_create(face_sh, *edit_face_ps);
+      DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_uniform_ivec4(grp, "dataMask", mask, 1);
+      DRW_shgroup_uniform_float_copy(grp, "alpha", face_alpha);
+      DRW_shgroup_uniform_bool_copy(grp, "selectFaces", select_face);
+    }
+
+    if (do_zbufclip) {
+      state_common |= DRW_STATE_WRITE_DEPTH;
+      // state_common &= ~DRW_STATE_BLEND_ALPHA;
+    }
+
+    /* Edges */
+    /* Change first vertex convention to match blender loop structure. */
+    state = state_common | DRW_STATE_FIRST_VERTEX_CONVENTION;
+    DRW_PASS_CREATE(psl->edit_mesh_edges_ps[i], state | pd->clipping_state);
+
+    grp = pd->edit_mesh_edges_grp[i] = DRW_shgroup_create(edge_sh, psl->edit_mesh_edges_ps[i]);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_ivec4(grp, "dataMask", mask, 1);
+    DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+    DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+    DRW_shgroup_uniform_bool_copy(grp, "selectEdges", pd->edit_mesh.do_edges || select_edge);
+
+    /* Verts */
+    DRW_PASS_CREATE(psl->edit_mesh_verts_ps[i], state | pd->clipping_state);
+
+    if (select_vert) {
+      sh = OVERLAY_shader_edit_mesh_vert();
+      grp = pd->edit_mesh_verts_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+      DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+      DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+
+      sh = OVERLAY_shader_edit_mesh_skin_root();
+      grp = pd->edit_mesh_skin_roots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+      DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    }
+    /* Facedots */
+    if (select_face && show_face_dots) {
+      sh = OVERLAY_shader_edit_mesh_facedot();
+      grp = pd->edit_mesh_facedots_grp[i] = DRW_shgroup_create(sh, psl->edit_mesh_verts_ps[i]);
+      DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_uniform_float_copy(grp, "alpha", backwire_opacity);
+      DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tex);
+      DRW_shgroup_state_enable(grp, DRW_STATE_WRITE_DEPTH);
+    }
+    else {
+      pd->edit_mesh_facedots_grp[i] = NULL;
+    }
+  }
+}
+
+static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob, bool in_front)
+{
+  struct GPUBatch *geom_tris, *geom_verts, *geom_edges, *geom_fcenter, *skin_roots, *circle;
+  DRWShadingGroup *vert_shgrp, *edge_shgrp, *fdot_shgrp, *face_shgrp, *skin_roots_shgrp;
+
+  bool has_edit_mesh_cage = false;
+  bool has_skin_roots = false;
+  /* TODO: Should be its own function. */
+  Mesh *me = (Mesh *)ob->data;
+  BMEditMesh *embm = me->edit_mesh;
+  if (embm) {
+    has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+    has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1;
+  }
+
+  vert_shgrp = pd->edit_mesh_verts_grp[in_front];
+  edge_shgrp = pd->edit_mesh_edges_grp[in_front];
+  fdot_shgrp = pd->edit_mesh_facedots_grp[in_front];
+  face_shgrp = (has_edit_mesh_cage) ? pd->edit_mesh_faces_cage_grp[in_front] :
+                                      pd->edit_mesh_faces_grp[in_front];
+  skin_roots_shgrp = pd->edit_mesh_skin_roots_grp[in_front];
+
+  geom_edges = DRW_mesh_batch_cache_get_edit_edges(ob->data);
+  geom_tris = DRW_mesh_batch_cache_get_edit_triangles(ob->data);
+  DRW_shgroup_call_no_cull(edge_shgrp, geom_edges, ob);
+  DRW_shgroup_call_no_cull(face_shgrp, geom_tris, ob);
+
+  if (pd->edit_mesh.select_vert) {
+    geom_verts = DRW_mesh_batch_cache_get_edit_vertices(ob->data);
+    DRW_shgroup_call_no_cull(vert_shgrp, geom_verts, ob);
+
+    if (has_skin_roots) {
+      circle = DRW_cache_circle_get();
+      skin_roots = DRW_mesh_batch_cache_get_edit_skin_roots(ob->data);
+      DRW_shgroup_call_instances_with_attribs(skin_roots_shgrp, ob, circle, skin_roots);
+    }
+  }
+
+  if (fdot_shgrp) {
+    geom_fcenter = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
+    DRW_shgroup_call_no_cull(fdot_shgrp, geom_fcenter, ob);
+  }
+}
+
+void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  struct GPUBatch *geom = NULL;
+
+  bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+  bool do_occlude_wire = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+  bool do_show_weight = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT) != 0;
+  bool do_show_mesh_analysis = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_STATVIS) != 0;
+  bool fnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_FACE_NORMALS) != 0;
+  bool vnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_VERT_NORMALS) != 0;
+  bool lnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_LOOP_NORMALS) != 0;
+
+  if (do_show_weight) {
+    geom = DRW_cache_mesh_surface_weights_get(ob);
+    DRW_shgroup_call_no_cull(pd->edit_mesh_weight_grp, geom, ob);
+  }
+  else if (do_show_mesh_analysis && !pd->xray_enabled) {
+    geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
+    if (geom) {
+      DRW_shgroup_call_no_cull(pd->edit_mesh_analysis_grp, geom, ob);
+    }
+  }
+
+  if (do_occlude_wire || do_in_front) {
+    geom = DRW_cache_mesh_surface_get(ob);
+    DRW_shgroup_call_no_cull(pd->edit_mesh_depth_grp[do_in_front], geom, ob);
+  }
+
+  if (vnormals_do || lnormals_do || fnormals_do) {
+    struct GPUBatch *normal_geom = DRW_cache_normal_arrow_get();
+    if (vnormals_do) {
+      geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
+      DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+    }
+    if (lnormals_do) {
+      geom = DRW_mesh_batch_cache_get_edit_lnors(ob->data);
+      DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+    }
+    if (fnormals_do) {
+      geom = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
+      DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+    }
+  }
+
+  if (pd->edit_mesh.do_zbufclip) {
+    overlay_edit_mesh_add_ob_to_pass(pd, ob, false);
+  }
+  else {
+    overlay_edit_mesh_add_ob_to_pass(pd, ob, do_in_front);
+  }
+
+  pd->edit_mesh.ghost_ob += (ob->dtx & OB_DRAWXRAY) ? 1 : 0;
+  pd->edit_mesh.edit_ob += 1;
+
+  if (DRW_state_show_text() && (pd->edit_mesh.flag & OVERLAY_EDIT_TEXT)) {
+    const DRWContextState *draw_ctx = DRW_context_state_get();
+    DRW_text_edit_mesh_measure_stats(draw_ctx->ar, draw_ctx->v3d, ob, &draw_ctx->scene->unit);
+  }
+}
+
+static void overlay_edit_mesh_draw_components(OVERLAY_PassList *psl,
+                                              OVERLAY_PrivateData *pd,
+                                              bool in_front)
+{
+  DRW_view_set_active(pd->view_edit_faces);
+  DRW_draw_pass(psl->edit_mesh_faces_ps[in_front]);
+
+  DRW_view_set_active(pd->view_edit_faces_cage);
+  DRW_draw_pass(psl->edit_mesh_faces_cage_ps[in_front]);
+
+  DRW_view_set_active(pd->view_edit_edges);
+  DRW_draw_pass(psl->edit_mesh_edges_ps[in_front]);
+
+  DRW_view_set_active(pd->view_edit_verts);
+  DRW_draw_pass(psl->edit_mesh_verts_ps[in_front]);
+
+  DRW_view_set_active(pd->view_default);
+}
+
+void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+  DRW_draw_pass(psl->edit_mesh_weight_ps);
+  DRW_draw_pass(psl->edit_mesh_analysis_ps);
+
+  DRW_draw_pass(psl->edit_mesh_depth_ps[NOT_IN_FRONT]);
+
+  if (pd->edit_mesh.do_zbufclip) {
+    DRW_draw_pass(psl->edit_mesh_depth_ps[IN_FRONT]);
+
+    /* render facefill */
+    DRW_view_set_active(pd->view_edit_faces);
+    DRW_draw_pass(psl->edit_mesh_faces_ps[NOT_IN_FRONT]);
+
+    DRW_view_set_active(pd->view_edit_faces_cage);
+    DRW_draw_pass(psl->edit_mesh_faces_cage_ps[NOT_IN_FRONT]);
+
+    DRW_view_set_active(pd->view_default);
+
+    GPU_framebuffer_bind(fbl->overlay_in_front_fb);
+    GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f);
+    DRW_draw_pass(psl->edit_mesh_normals_ps);
+
+    DRW_view_set_active(pd->view_edit_edges);
+    DRW_draw_pass(psl->edit_mesh_edges_ps[NOT_IN_FRONT]);
+
+    DRW_view_set_active(pd->view_edit_verts);
+    DRW_draw_pass(psl->edit_mesh_verts_ps[NOT_IN_FRONT]);
+
+    GPU_framebuffer_bind(fbl->overlay_default_fb);
+  }
+  else {
+    const DRWContextState *draw_ctx = DRW_context_state_get();
+    View3D *v3d = draw_ctx->v3d;
+
+    DRW_draw_pass(psl->edit_mesh_normals_ps);
+    overlay_edit_mesh_draw_components(psl, pd, false);
+
+    if (v3d->shading.type == OB_SOLID && pd->edit_mesh.ghost_ob == 1 &&
+        pd->edit_mesh.edit_ob == 1) {
+      /* In the case of single ghost object edit (common case for retopology):
+       * we clear the depth buffer so that only the depth of the retopo mesh
+       * is occluding the edit cage. */
+      GPU_framebuffer_clear_depth(fbl->overlay_default_fb, 1.0f);
+    }
+
+    DRW_draw_pass(psl->edit_mesh_depth_ps[IN_FRONT]);
+    overlay_edit_mesh_draw_components(psl, pd, true);
+  }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c
new file mode 100644 (file)
index 0000000..d8edf34
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_font.h"
+
+#include "DNA_curve_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  View3D *v3d = draw_ctx->v3d;
+  DRWShadingGroup *grp;
+  GPUShader *sh;
+  DRWState state;
+
+  pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+  pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
+
+  /* Run Twice for in-front passes. */
+  for (int i = 0; i < 2; i++) {
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH;
+    state |= ((i == 0) ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_ALWAYS);
+    DRW_PASS_CREATE(psl->edit_text_wire_ps[i], state | pd->clipping_state);
+
+    sh = OVERLAY_shader_uniform_color();
+    pd->edit_text_wire_grp[i] = grp = DRW_shgroup_create(sh, psl->edit_text_wire_ps[i]);
+    DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.colorWire);
+  }
+  {
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT;
+    DRW_PASS_CREATE(psl->edit_text_overlay_ps, state | pd->clipping_state);
+
+    sh = OVERLAY_shader_uniform_color();
+    pd->edit_text_overlay_grp = DRW_shgroup_create(sh, psl->edit_text_overlay_ps);
+  }
+}
+
+/* Use 2D quad corners to create a matrix that set
+ * a [-1..1] quad at the right position. */
+static void v2_quad_corners_to_mat4(float corners[4][2], float r_mat[4][4])
+{
+  unit_m4(r_mat);
+  sub_v2_v2v2(r_mat[0], corners[1], corners[0]);
+  sub_v2_v2v2(r_mat[1], corners[3], corners[0]);
+  mul_v2_fl(r_mat[0], 0.5f);
+  mul_v2_fl(r_mat[1], 0.5f);
+  copy_v2_v2(r_mat[3], corners[0]);
+  add_v2_v2(r_mat[3], r_mat[0]);
+  add_v2_v2(r_mat[3], r_mat[1]);
+}
+
+static void edit_text_cache_populate_select(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const Curve *cu = ob->data;
+  EditFont *ef = cu->editfont;
+  float final_mat[4][4], box[4][2];
+  struct GPUBatch *geom = DRW_cache_quad_get();
+
+  for (int i = 0; i < ef->selboxes_len; i++) {
+    EditFontSelBox *sb = &ef->selboxes[i];
+
+    float selboxw;
+    if (i + 1 != ef->selboxes_len) {
+      if (ef->selboxes[i + 1].y == sb->y) {
+        selboxw = ef->selboxes[i + 1].x - sb->x;
+      }
+      else {
+        selboxw = sb->w;
+      }
+    }
+    else {
+      selboxw = sb->w;
+    }
+    /* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */
+    if (sb->rot == 0.0f) {
+      copy_v2_fl2(box[0], sb->x, sb->y);
+      copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
+      copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
+    }
+    else {
+      float mat[2][2];
+      angle_to_mat2(mat, sb->rot);
+      copy_v2_fl2(box[0], sb->x, sb->y);
+      mul_v2_v2fl(box[1], mat[0], selboxw);
+      add_v2_v2(box[1], &sb->x);
+      mul_v2_v2fl(box[3], mat[1], sb->h);
+      add_v2_v2(box[3], &sb->x);
+    }
+    v2_quad_corners_to_mat4(box, final_mat);
+    mul_m4_m4m4(final_mat, ob->obmat, final_mat);
+
+    DRW_shgroup_call_obmat(pd->edit_text_overlay_grp, geom, final_mat);
+  }
+}
+
+static void edit_text_cache_populate_cursor(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const Curve *cu = ob->data;
+  EditFont *edit_font = cu->editfont;
+  float(*cursor)[2] = edit_font->textcurs;
+  float mat[4][4];
+
+  v2_quad_corners_to_mat4(cursor, mat);
+  mul_m4_m4m4(mat, ob->obmat, mat);
+
+  struct GPUBatch *geom = DRW_cache_quad_get();
+  DRW_shgroup_call_obmat(pd->edit_text_overlay_grp, geom, mat);
+}
+
+static void edit_text_cache_populate_boxes(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  const Curve *cu = ob->data;
+
+  for (int i = 0; i < cu->totbox; i++) {
+    TextBox *tb = &cu->tb[i];
+    const bool is_active = (i == (cu->actbox - 1));
+    float *color = is_active ? G_draw.block.colorActive : G_draw.block.colorWire;
+
+    if ((tb->w != 0.0f) || (tb->h != 0.0f)) {
+      float vecs[4][3];
+      vecs[0][0] = vecs[1][0] = vecs[2][0] = vecs[3][0] = cu->xof + tb->x;
+      vecs[0][1] = vecs[1][1] = vecs[2][1] = vecs[3][1] = cu->yof + tb->y + cu->fsize_realtime;
+      vecs[0][2] = vecs[1][2] = vecs[2][2] = vecs[3][2] = 0.001;
+
+      vecs[1][0] += tb->w;
+      vecs[2][0] += tb->w;
+      vecs[2][1] -= tb->h;
+      vecs[3][1] -= tb->h;
+
+      for (int j = 0; j < 4; j++) {
+        mul_v3_m4v3(vecs[j], ob->obmat, vecs[j]);
+      }
+      for (int j = 0; j < 4; j++) {
+        OVERLAY_extra_line_dashed(cb, vecs[j], vecs[(j + 1) % 4], color);
+      }
+    }
+  }
+}
+
+void OVERLAY_edit_text_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  Curve *cu = ob->data;
+  struct GPUBatch *geom;
+  bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+
+  bool has_surface = (cu->flag & (CU_FRONT | CU_BACK)) || cu->ext1 != 0.0f || cu->ext2 != 0.0f;
+  if ((cu->flag & CU_FAST) || !has_surface) {
+    geom = DRW_cache_text_edge_wire_get(ob);
+    if (geom) {
+      DRW_shgroup_call(pd->edit_text_wire_grp[do_in_front], geom, ob);
+    }
+  }
+  else {
+    /* object mode draws */
+  }
+
+  edit_text_cache_populate_select(vedata, ob);
+  edit_text_cache_populate_cursor(vedata, ob);
+  edit_text_cache_populate_boxes(vedata, ob);
+}
+
+void OVERLAY_edit_text_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_view_set_active(NULL);
+
+  DRW_draw_pass(psl->edit_text_wire_ps[0]);
+  DRW_draw_pass(psl->edit_text_wire_ps[1]);
+
+  DRW_draw_pass(psl->edit_text_overlay_ps);
+}
\ No newline at end of file
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
new file mode 100644 (file)
index 0000000..667172e
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * Engine for drawing a selection map where the pixels indicate the selection indices.
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "ED_view3d.h"
+
+#include "BKE_object.h"
+
+#include "overlay_engine.h"
+#include "overlay_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Engine Callbacks
+ * \{ */
+
+static void OVERLAY_engine_init(void *vedata)
+{
+  OVERLAY_Data *data = vedata;
+  OVERLAY_StorageList *stl = data->stl;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  const RegionView3D *rv3d = draw_ctx->rv3d;
+  const View3D *v3d = draw_ctx->v3d;
+
+  if (!stl->pd) {
+    /* Alloc transient pointers */
+    stl->pd = MEM_callocN(sizeof(*stl->pd), __func__);
+  }
+
+  OVERLAY_PrivateData *pd = stl->pd;
+  View3DOverlay overlay;
+  short v3d_flag, v3d_gridflag;
+
+  pd->hide_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) != 0;
+  pd->ctx_mode = CTX_data_mode_enum_ex(
+      draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
+
+  if (!pd->hide_overlays) {
+    overlay = v3d->overlay;
+    v3d_flag = v3d->flag;
+    v3d_gridflag = v3d->gridflag;
+  }
+  else {
+    memset(&overlay, 0, sizeof(overlay));
+    v3d_flag = 0;
+    v3d_gridflag = 0;
+    overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES |
+                   V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
+  }
+
+  if (v3d->shading.type == OB_WIRE) {
+    overlay.flag |= V3D_OVERLAY_WIREFRAMES;
+  }
+
+  /* Check if anything changed, and if so, reset AA. */
+  if (v3d_flag != pd->v3d_flag || pd->v3d_gridflag != v3d_gridflag ||
+      memcmp(&pd->overlay, &overlay, sizeof(overlay))) {
+    pd->overlay = overlay;
+    pd->v3d_flag = v3d_flag;
+    pd->v3d_gridflag = v3d_gridflag;
+    OVERLAY_antialiasing_reset(vedata);
+  }
+
+  pd->wireframe_mode = (v3d->shading.type == OB_WIRE);
+  pd->clipping_state = (rv3d->rflag & RV3D_CLIPPING) ? DRW_STATE_CLIP_PLANES : 0;
+  pd->xray_enabled = XRAY_ACTIVE(v3d);
+  pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE;
+  pd->clear_in_front = (v3d->shading.type != OB_SOLID);
+
+  OVERLAY_antialiasing_init(vedata);
+
+  switch (stl->pd->ctx_mode) {
+    case CTX_MODE_EDIT_MESH:
+      OVERLAY_edit_mesh_init(vedata);
+      break;
+    default:
+      /* Nothing to do. */
+      break;
+  }
+  OVERLAY_facing_init(vedata);
+  OVERLAY_grid_init(vedata);
+  OVERLAY_image_init(vedata);
+  OVERLAY_outline_init(vedata);
+  OVERLAY_wireframe_init(vedata);
+}
+
+static void OVERLAY_cache_init(void *vedata)
+{
+  OVERLAY_Data *data = vedata;
+  OVERLAY_StorageList *stl = data->stl;
+  OVERLAY_PrivateData *pd = stl->pd;
+
+  switch (pd->ctx_mode) {
+    case CTX_MODE_EDIT_MESH:
+      OVERLAY_edit_mesh_cache_init(vedata);
+      break;
+    case CTX_MODE_EDIT_SURFACE:
+    case CTX_MODE_EDIT_CURVE:
+      OVERLAY_edit_curve_cache_init(vedata);
+      break;
+    case CTX_MODE_EDIT_TEXT:
+      OVERLAY_edit_text_cache_init(vedata);
+      break;
+    case CTX_MODE_EDIT_ARMATURE:
+      break;
+    case CTX_MODE_EDIT_METABALL:
+      break;
+    case CTX_MODE_EDIT_LATTICE:
+      OVERLAY_edit_lattice_cache_init(vedata);
+      break;
+    case CTX_MODE_PARTICLE:
+      OVERLAY_edit_particle_cache_init(vedata);
+      break;
+    case CTX_MODE_POSE:
+    case CTX_MODE_PAINT_WEIGHT:
+    case CTX_MODE_PAINT_VERTEX:
+    case CTX_MODE_PAINT_TEXTURE:
+      OVERLAY_paint_cache_init(vedata);
+      break;
+    case CTX_MODE_SCULPT:
+      OVERLAY_sculpt_cache_init(vedata);
+      break;
+    case CTX_MODE_OBJECT:
+    case CTX_MODE_PAINT_GPENCIL:
+    case CTX_MODE_EDIT_GPENCIL:
+    case CTX_MODE_SCULPT_GPENCIL:
+    case CTX_MODE_WEIGHT_GPENCIL:
+      break;
+    default:
+      BLI_assert(!"Draw mode invalid");
+      break;
+  }
+  OVERLAY_antialiasing_cache_init(vedata);
+  OVERLAY_armature_cache_init(vedata);
+  OVERLAY_extra_cache_init(vedata);
+  OVERLAY_facing_cache_init(vedata);
+  OVERLAY_grid_cache_init(vedata);
+  OVERLAY_image_cache_init(vedata);
+  OVERLAY_metaball_cache_init(vedata);
+  OVERLAY_motion_path_cache_init(vedata);
+  OVERLAY_outline_cache_init(vedata);
+  OVERLAY_particle_cache_init(vedata);
+  OVERLAY_wireframe_cache_init(vedata);
+}
+
+BLI_INLINE OVERLAY_DupliData *OVERLAY_duplidata_get(Object *ob, void *vedata, bool *do_init)
+{
+  OVERLAY_DupliData **dupli_data = (OVERLAY_DupliData **)DRW_duplidata_get(vedata);
+  *do_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(OVERLAY_DupliData), __func__);
+      *do_init = true;
+    }
+    else if ((*dupli_data)->base_flag != ob->base_flag) {
+      /* Select state might have change, reinit. */
+      *do_init = true;
+    }
+    return *dupli_data;
+  }
+  return NULL;
+}
+
+static void OVERLAY_cache_populate(void *vedata, Object *ob)
+{
+  OVERLAY_Data *data = vedata;
+  OVERLAY_PrivateData *pd = data->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  const bool is_select = DRW_state_is_select();
+  const bool renderable = DRW_object_is_renderable(ob);
+  const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx);
+  const bool in_edit_mode = BKE_object_is_in_editmode(ob);
+  const bool in_particle_edit_mode = ob->mode == OB_MODE_PARTICLE_EDIT;
+  const bool in_paint_mode = (ob == draw_ctx->obact) &&
+                             (draw_ctx->object_mode & OB_MODE_ALL_PAINT);
+  const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL);
+  const bool has_surface = ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT);
+  const bool draw_surface = !((ob->dt < OB_WIRE) || (!renderable && (ob->dt != OB_WIRE)));
+  const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION);
+  const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
+  const bool draw_wires = draw_surface && has_surface &&
+                          (pd->wireframe_mode || !pd->hide_overlays);
+  const bool draw_outlines = !in_edit_mode && !in_paint_mode && renderable &&
+                             (pd->v3d_flag & V3D_SELECT_OUTLINE) &&
+                             ((ob->base_flag & BASE_SELECTED) ||
+                              (is_select && ob->type == OB_LIGHTPROBE));
+  const bool draw_bone_selection = (ob->type == OB_MESH) && pd->armature.do_pose_fade_geom &&
+                                   !is_select;
+  const bool draw_extras =
+      ((pd->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_XTRAS) == 0) ||
+      /* Show if this is the camera we're looking through since it's useful for selecting. */
+      ((draw_ctx->rv3d->persp == RV3D_CAMOB) && ((ID *)draw_ctx->v3d->camera == ob->id.orig_id));
+
+  const bool draw_motion_paths = (pd->overlay.flag & V3D_OVERLAY_HIDE_MOTION_PATHS) == 0;
+
+  bool do_init;
+  OVERLAY_DupliData *dupli = OVERLAY_duplidata_get(ob, vedata, &do_init);
+
+  if (draw_facing) {
+    OVERLAY_facing_cache_populate(vedata, ob);
+  }
+  if (draw_wires) {
+    OVERLAY_wireframe_cache_populate(vedata, ob, dupli, do_init);
+  }
+  if (draw_outlines) {
+    OVERLAY_outline_cache_populate(vedata, ob, dupli, do_init);
+  }
+  if (draw_bone_selection) {
+    OVERLAY_pose_cache_populate(vedata, ob);
+  }
+
+  if (in_edit_mode) {
+    switch (ob->type) {
+      case OB_MESH:
+        OVERLAY_edit_mesh_cache_populate(vedata, ob);
+        break;
+      case OB_ARMATURE:
+        if (draw_bones) {
+          OVERLAY_edit_armature_cache_populate(vedata, ob);
+        }
+        break;
+      case OB_CURVE:
+        OVERLAY_edit_curve_cache_populate(vedata, ob);
+        break;
+      case OB_SURF:
+        OVERLAY_edit_surf_cache_populate(vedata, ob);
+        break;
+      case OB_LATTICE:
+        OVERLAY_edit_lattice_cache_populate(vedata, ob);
+        break;
+      case OB_MBALL:
+        OVERLAY_edit_metaball_cache_populate(vedata, ob);
+        break;
+      case OB_FONT:
+        OVERLAY_edit_text_cache_populate(vedata, ob);
+        break;
+    }
+  }
+  else if (in_pose_mode && draw_bones) {
+    OVERLAY_pose_armature_cache_populate(vedata, ob);
+  }
+  else if (in_paint_mode) {
+    switch (draw_ctx->object_mode) {
+      case OB_MODE_VERTEX_PAINT:
+        OVERLAY_paint_vertex_cache_populate(vedata, ob);
+        break;
+      case OB_MODE_WEIGHT_PAINT:
+        OVERLAY_paint_weight_cache_populate(vedata, ob);
+        break;
+      case OB_MODE_TEXTURE_PAINT:
+        OVERLAY_paint_texture_cache_populate(vedata, ob);
+        break;
+      default:
+        break;
+    }
+  }
+  else if (in_particle_edit_mode) {
+    OVERLAY_edit_particle_cache_populate(vedata, ob);
+  }
+
+  if (in_sculpt_mode) {
+    OVERLAY_sculpt_cache_populate(vedata, ob);
+  }
+
+  if (draw_motion_paths) {
+    OVERLAY_motion_path_cache_populate(vedata, ob);
+  }
+
+  switch (ob->type) {
+    case OB_ARMATURE:
+      if (draw_bones && (is_select || (!in_edit_mode && !in_pose_mode))) {
+        OVERLAY_armature_cache_populate(vedata, ob);
+      }
+      break;
+    case OB_MBALL:
+      if (!in_edit_mode) {
+        OVERLAY_metaball_cache_populate(vedata, ob);
+      }
+      break;
+    case OB_GPENCIL:
+      OVERLAY_gpencil_cache_populate(vedata, ob);
+      break;
+  }
+  /* Non-Meshes */
+  if (draw_extras) {
+    switch (ob->type) {
+      case OB_EMPTY:
+        OVERLAY_empty_cache_populate(vedata, ob);
+        break;
+      case OB_LAMP:
+        OVERLAY_light_cache_populate(vedata, ob);
+        break;
+      case OB_CAMERA:
+        OVERLAY_camera_cache_populate(vedata, ob);
+        break;
+      case OB_SPEAKER:
+        OVERLAY_speaker_cache_populate(vedata, ob);
+        break;
+      case OB_LIGHTPROBE:
+        OVERLAY_lightprobe_cache_populate(vedata, ob);
+        break;
+      case OB_LATTICE:
+        OVERLAY_lattice_cache_populate(vedata, ob);
+        break;
+    }
+  }
+
+  if (!BLI_listbase_is_empty(&ob->particlesystem)) {
+    OVERLAY_particle_cache_populate(vedata, ob);
+  }
+
+  /* Relationship, object center, bounbox ... */
+  OVERLAY_extra_cache_populate(vedata, ob);
+
+  if (dupli) {
+    dupli->base_flag = ob->base_flag;
+  }
+}
+
+static void OVERLAY_cache_finish(void *vedata)
+{
+  /* TODO(fclem) Only do this when really needed. */
+  {
+    /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */
+    DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+    DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+    DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0);
+
+    GPU_framebuffer_ensure_config(
+        &dfbl->default_fb,
+        {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+    GPU_framebuffer_ensure_config(
+        &dfbl->in_front_fb,
+        {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+  }
+
+  OVERLAY_antialiasing_cache_finish(vedata);
+  OVERLAY_armature_cache_finish(vedata);
+  OVERLAY_image_cache_finish(vedata);
+}
+
+static void OVERLAY_draw_scene(void *vedata)
+{
+  OVERLAY_Data *data = vedata;
+  OVERLAY_PrivateData *pd = data->stl->pd;
+  OVERLAY_FramebufferList *fbl = data->fbl;
+
+  OVERLAY_antialiasing_start(vedata);
+
+  DRW_view_set_active(pd->view_default);
+
+  OVERLAY_image_draw(vedata);
+  OVERLAY_facing_draw(vedata);
+  OVERLAY_wireframe_draw(vedata);
+  OVERLAY_armature_draw(vedata);
+  OVERLAY_particle_draw(vedata);
+  OVERLAY_metaball_draw(vedata);
+  OVERLAY_extra_draw(vedata);
+
+  DRW_view_set_active(NULL);
+
+  OVERLAY_grid_draw(vedata);
+  OVERLAY_outline_draw(vedata);
+
+  DRW_view_set_active(pd->view_default);
+
+  if (DRW_state_is_fbo()) {
+    GPU_framebuffer_bind(fbl->overlay_in_front_fb);
+
+    /* If we are not in solid shading mode, we clear the depth. */
+    if (pd->clear_in_front) {
+      /* TODO(fclem) This clear should be done in a global place. */
+      GPU_framebuffer_clear_depth(fbl->overlay_in_front_fb, 1.0f);
+    }
+  }
+
+  OVERLAY_wireframe_in_front_draw(vedata);
+  OVERLAY_armature_in_front_draw(vedata);
+  OVERLAY_extra_in_front_draw(vedata);
+  OVERLAY_metaball_in_front_draw(vedata);
+  OVERLAY_image_in_front_draw(vedata);
+
+  if (DRW_state_is_fbo()) {
+    GPU_framebuffer_bind(fbl->overlay_default_fb);
+  }
+
+  OVERLAY_motion_path_draw(vedata);
+  OVERLAY_extra_centers_draw(vedata);
+
+  switch (pd->ctx_mode) {
+    case CTX_MODE_EDIT_MESH:
+      OVERLAY_edit_mesh_draw(vedata);
+      break;
+    case CTX_MODE_EDIT_SURFACE:
+    case CTX_MODE_EDIT_CURVE:
+      OVERLAY_edit_curve_draw(vedata);
+      break;
+    case CTX_MODE_EDIT_TEXT:
+      /* Text overlay need final color for color inversion. */
+      OVERLAY_antialiasing_end(vedata);
+      OVERLAY_edit_text_draw(vedata);
+      return; /* WATCH! dont do AA twice. */
+    case CTX_MODE_EDIT_LATTICE:
+      OVERLAY_edit_lattice_draw(vedata);
+      break;
+    case CTX_MODE_POSE:
+      /* Pain overlay needs final color because of multiply blend mode. */
+      OVERLAY_antialiasing_end(vedata);
+      OVERLAY_paint_draw(vedata);
+      OVERLAY_pose_draw(vedata);
+      return; /* WATCH! dont do AA twice. */
+    case CTX_MODE_PAINT_WEIGHT:
+    case CTX_MODE_PAINT_VERTEX:
+    case CTX_MODE_PAINT_TEXTURE:
+      /* Pain overlay need final color because of multiply blend mode. */
+      OVERLAY_antialiasing_end(vedata);
+      OVERLAY_paint_draw(vedata);
+      return; /* WATCH! dont do AA twice. */
+    case CTX_MODE_PARTICLE:
+      OVERLAY_edit_particle_draw(vedata);
+      break;
+    case CTX_MODE_SCULPT:
+      OVERLAY_sculpt_draw(vedata);
+      break;
+    default:
+      break;
+  }
+
+  OVERLAY_antialiasing_end(vedata);
+}
+
+static void OVERLAY_engine_free(void)
+{
+  OVERLAY_shader_free();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Engine Type
+ * \{ */
+
+static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
+
+DrawEngineType draw_engine_overlay_type = {
+    NULL,
+    NULL,
+    N_("Overlay"),
+    &overlay_data_size,
+    &OVERLAY_engine_init,
+    &OVERLAY_engine_free,
+    &OVERLAY_cache_init,
+    &OVERLAY_cache_populate,
+    &OVERLAY_cache_finish,
+    NULL,
+    &OVERLAY_draw_scene,
+    NULL,
+    NULL,
+    NULL,
+};
+
+/** \} */
+
+#undef SELECT_ENGINE
similarity index 60%
rename from source/blender/draw/modes/edit_mesh_mode_intern.h
rename to source/blender/draw/engines/overlay/overlay_engine.h
index 706c7b7bd881449b60187103ac9ded635427260d..795e3805037ebcd6c897cb5ad7414d6c30376347 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
  */
 
 /** \file
- * \ingroup draw
+ * \ingroup draw_engine
  */
 
-#ifndef __EDIT_MESH_MODE_INTERN_H__
-#define __EDIT_MESH_MODE_INTERN_H__
-
-struct ARegion;
-struct Object;
-struct UnitSettings;
-struct View3D;
+#ifndef __OVERLAY_ENGINE_H__
+#define __OVERLAY_ENGINE_H__
 
-/* edit_mesh_mode_text.c */
-void DRW_edit_mesh_mode_text_measure_stats(struct ARegion *ar,
-                                           struct View3D *v3d,
-                                           struct Object *ob,
-                                           const UnitSettings *unit);
+extern DrawEngineType draw_engine_overlay_type;
 
-#endif /* __EDIT_MESH_MODE_INTERN_H__ */
+#endif /* __OVERLAY_ENGINE_H__ */
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
new file mode 100644 (file)
index 0000000..d088142
--- /dev/null
@@ -0,0 +1,1586 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "UI_resources.h"
+
+#include "BKE_anim.h"
+#include "BKE_camera.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_movieclip.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_tracking.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_smoke_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_draw.h"
+
+#include "overlay_private.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  DRW_PASS_CREATE(psl->extra_blend_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
+  DRW_PASS_CREATE(psl->extra_centers_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
+
+  for (int i = 0; i < 2; i++) {
+    /* Non Meshes Pass (Camera, empties, lights ...) */
+    struct GPUShader *sh;
+    struct GPUVertFormat *format;
+    DRWShadingGroup *grp, *grp_sub;
+
+    OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+    OVERLAY_ExtraCallBuffers *cb = &pd->extra_call_buffers[i];
+    DRWPass **p_extra_ps = &psl->extra_ps[i];
+
+    DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+    DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+    DRW_PASS_CREATE(*p_extra_ps, state | pd->clipping_state | infront_state);
+
+    DRWPass *extra_ps = *p_extra_ps;
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+#define BUF_POINT(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_POINTS)
+#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
+
+    /* Sorted by shader to avoid state changes during render. */
+    {
+      format = formats->instance_extra;
+      sh = OVERLAY_shader_extra();
+
+      grp = DRW_shgroup_create(sh, extra_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      cb->camera_distances = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_distances_get());
+      cb->camera_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_frame_get());
+      cb->camera_tria[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_tria_wire_get());
+      cb->camera_tria[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_tria_get());
+      cb->empty_axes = BUF_INSTANCE(grp_sub, format, DRW_cache_bone_arrows_get());
+      cb->empty_capsule_body = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_capsule_body_get());
+      cb->empty_capsule_cap = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_capsule_cap_get());
+      cb->empty_circle = BUF_INSTANCE(grp_sub, format, DRW_cache_circle_get());
+      cb->empty_cone = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cone_get());
+      cb->empty_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cube_get());
+      cb->empty_cylinder = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_cylinder_get());
+      cb->empty_image_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_quad_wires_get());
+      cb->empty_plain_axes = BUF_INSTANCE(grp_sub, format, DRW_cache_plain_axes_get());
+      cb->empty_single_arrow = BUF_INSTANCE(grp_sub, format, DRW_cache_single_arrow_get());
+      cb->empty_sphere = BUF_INSTANCE(grp_sub, format, DRW_cache_empty_sphere_get());
+      cb->empty_sphere_solid = BUF_INSTANCE(grp_sub, format, DRW_cache_sphere_get());
+      cb->field_cone_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_cone_limit_get());
+      cb->field_curve = BUF_INSTANCE(grp_sub, format, DRW_cache_field_curve_get());
+      cb->field_force = BUF_INSTANCE(grp_sub, format, DRW_cache_field_force_get());
+      cb->field_sphere_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_sphere_limit_get());
+      cb->field_tube_limit = BUF_INSTANCE(grp_sub, format, DRW_cache_field_tube_limit_get());
+      cb->field_vortex = BUF_INSTANCE(grp_sub, format, DRW_cache_field_vortex_get());
+      cb->field_wind = BUF_INSTANCE(grp_sub, format, DRW_cache_field_wind_get());
+      cb->light_area[0] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_disk_lines_get());
+      cb->light_area[1] = BUF_INSTANCE(grp_sub, format, DRW_cache_light_area_square_lines_get());
+      cb->light_point = BUF_INSTANCE(grp_sub, format, DRW_cache_light_point_lines_get());
+      cb->light_spot = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_lines_get());
+      cb->light_sun = BUF_INSTANCE(grp_sub, format, DRW_cache_light_sun_lines_get());
+      cb->probe_cube = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
+      cb->probe_grid = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_grid_get());
+      cb->probe_planar = BUF_INSTANCE(grp_sub, format, DRW_cache_lightprobe_planar_get());
+      cb->speaker = BUF_INSTANCE(grp_sub, format, DRW_cache_speaker_get());
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_ALWAYS);
+      DRW_shgroup_state_disable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL);
+      cb->origin_xform = BUF_INSTANCE(grp_sub, format, DRW_cache_bone_arrows_get());
+    }
+    {
+      format = formats->instance_extra;
+      grp = DRW_shgroup_create(sh, psl->extra_blend_ps); /* NOTE: not the same pass! */
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_BACK);
+      cb->camera_volume = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_get());
+      cb->camera_volume_frame = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_volume_wire_get());
+      cb->light_spot_cone_back = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_state_enable(grp_sub, DRW_STATE_CULL_FRONT);
+      cb->light_spot_cone_front = BUF_INSTANCE(grp_sub, format, DRW_cache_light_spot_volume_get());
+    }
+    {
+      format = formats->instance_pos;
+      sh = OVERLAY_shader_extra_groundline();
+
+      grp = DRW_shgroup_create(sh, extra_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+      DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+      cb->groundline = BUF_INSTANCE(grp, format, DRW_cache_groundline_get());
+    }
+    {
+      sh = OVERLAY_shader_extra_wire(false);
+
+      grp = DRW_shgroup_create(sh, extra_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+      cb->extra_dashed_lines = BUF_LINE(grp, formats->pos_color);
+      cb->extra_lines = BUF_LINE(grp, formats->wire_extra);
+    }
+    {
+      sh = OVERLAY_shader_extra_wire(true);
+
+      cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+    }
+    {
+      sh = OVERLAY_shader_extra_loose_point();
+
+      cb->extra_loose_points = grp = DRW_shgroup_create(sh, extra_ps);
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+    }
+    {
+      format = formats->pos;
+      sh = OVERLAY_shader_extra_point();
+
+      grp = DRW_shgroup_create(sh, psl->extra_centers_ps); /* NOTE: not the same pass! */
+      DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorActive);
+      cb->center_active = BUF_POINT(grp_sub, format);
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorSelect);
+      cb->center_selected = BUF_POINT(grp_sub, format);
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorDeselect);
+      cb->center_deselected = BUF_POINT(grp_sub, format);
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorLibrarySelect);
+      cb->center_selected_lib = BUF_POINT(grp_sub, format);
+
+      grp_sub = DRW_shgroup_create_sub(grp);
+      DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorLibrary);
+      cb->center_deselected_lib = BUF_POINT(grp_sub, format);
+    }
+  }
+}
+
+void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
+                               const float start[3],
+                               const float end[3],
+                               const float color[4])
+{
+  DRW_buffer_add_entry(cb->extra_dashed_lines, end, color);
+  DRW_buffer_add_entry(cb->extra_dashed_lines, start, color);
+}
+
+void OVERLAY_extra_line(OVERLAY_ExtraCallBuffers *cb,
+                        const float start[3],
+                        const float end[3],
+                        const int color_id)
+{
+  DRW_buffer_add_entry(cb->extra_lines, start, &color_id);
+  DRW_buffer_add_entry(cb->extra_lines, end, &color_id);
+}
+
+OVERLAY_ExtraCallBuffers *OVERLAY_extra_call_buffer_get(OVERLAY_Data *vedata, Object *ob)
+{
+  bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  return &pd->extra_call_buffers[do_in_front];
+}
+
+void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb,
+                                struct GPUBatch *geom,
+                                const float mat[4][4],
+                                const float color[4])
+{
+  float draw_mat[4][4];
+  pack_v4_in_mat4(draw_mat, mat, color);
+  DRW_shgroup_call_obmat(cb->extra_loose_points, geom, draw_mat);
+}
+
+void OVERLAY_extra_wire(OVERLAY_ExtraCallBuffers *cb,
+                        struct GPUBatch *geom,
+                        const float mat[4][4],
+                        const float color[4])
+{
+  float draw_mat[4][4];
+  pack_v4_in_mat4(draw_mat, mat, color);
+  DRW_shgroup_call_obmat(cb->extra_wire, geom, draw_mat);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Empties
+ * \{ */
+
+void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb,
+                         const float mat[4][4],
+                         const float draw_size,
+                         const char draw_type,
+                         const float color[4])
+{
+  float instdata[4][4];
+  pack_fl_in_mat4(instdata, mat, draw_size);
+
+  switch (draw_type) {
+    case OB_PLAINAXES:
+      DRW_buffer_add_entry(cb->empty_plain_axes, color, instdata);
+      break;
+    case OB_SINGLE_ARROW:
+      DRW_buffer_add_entry(cb->empty_single_arrow, color, instdata);
+      break;
+    case OB_CUBE:
+      DRW_buffer_add_entry(cb->empty_cube, color, instdata);
+      break;
+    case OB_CIRCLE:
+      DRW_buffer_add_entry(cb->empty_circle, color, instdata);
+      break;
+    case OB_EMPTY_SPHERE:
+      DRW_buffer_add_entry(cb->empty_sphere, color, instdata);
+      break;
+    case OB_EMPTY_CONE:
+      DRW_buffer_add_entry(cb->empty_cone, color, instdata);
+      break;
+    case OB_ARROWS:
+      DRW_buffer_add_entry(cb->empty_axes, color, instdata);
+      break;
+    case OB_EMPTY_IMAGE:
+      /* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */
+      DRW_buffer_add_entry(cb->empty_image_frame, color, instdata);
+      break;
+  }
+}
+
+void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  if (((ob->base_flag & BASE_FROM_DUPLI) != 0) && ((ob->transflag & OB_DUPLICOLLECTION) != 0) &&
+      ob->instance_collection) {
+    return;
+  }
+
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ViewLayer *view_layer = draw_ctx->view_layer;
+  float *color;
+
+  switch (ob->empty_drawtype) {
+    case OB_PLAINAXES:
+    case OB_SINGLE_ARROW:
+    case OB_CUBE:
+    case OB_CIRCLE:
+    case OB_EMPTY_SPHERE:
+    case OB_EMPTY_CONE:
+    case OB_ARROWS:
+      DRW_object_wire_theme_get(ob, view_layer, &color);
+      OVERLAY_empty_shape(cb, ob->obmat, ob->empty_drawsize, ob->empty_drawtype, color);
+      break;
+    case OB_EMPTY_IMAGE:
+      OVERLAY_image_empty_cache_populate(vedata, ob);
+      break;
+  }
+}
+
+static void OVERLAY_bounds(
+    OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id, char boundtype, bool around_origin)
+{
+  float color[4], center[3], size[3], tmp[4][4], final_mat[4][4];
+  BoundBox bb_local;
+
+  if (ob->type == OB_MBALL && !BKE_mball_is_basis(ob)) {
+    return;
+  }
+
+  BoundBox *bb = BKE_object_boundbox_get(ob);
+
+  if (bb == NULL) {
+    const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
+    bb = &bb_local;
+    BKE_boundbox_init_from_minmax(bb, min, max);
+  }
+
+  UI_GetThemeColor4fv(theme_id, color);
+  BKE_boundbox_calc_size_aabb(bb, size);
+
+  if (around_origin) {
+    zero_v3(center);
+  }
+  else {
+    BKE_boundbox_calc_center_aabb(bb, center);
+  }
+
+  switch (boundtype) {
+    case OB_BOUND_BOX:
+      size_to_mat4(tmp, size);
+      copy_v3_v3(tmp[3], center);
+      mul_m4_m4m4(tmp, ob->obmat, tmp);
+      DRW_buffer_add_entry(cb->empty_cube, color, tmp);
+      break;
+    case OB_BOUND_SPHERE:
+      size[0] = max_fff(size[0], size[1], size[2]);
+      size[1] = size[2] = size[0];
+      size_to_mat4(tmp, size);
+      copy_v3_v3(tmp[3], center);
+      mul_m4_m4m4(tmp, ob->obmat, tmp);
+      DRW_buffer_add_entry(cb->empty_sphere, color, tmp);
+      break;
+    case OB_BOUND_CYLINDER:
+      size[0] = max_ff(size[0], size[1]);
+      size[1] = size[0];
+      size_to_mat4(tmp, size);
+      copy_v3_v3(tmp[3], center);
+      mul_m4_m4m4(tmp, ob->obmat, tmp);
+      DRW_buffer_add_entry(cb->empty_cylinder, color, tmp);
+      break;
+    case OB_BOUND_CONE:
+      size[0] = max_ff(size[0], size[1]);
+      size[1] = size[0];
+      size_to_mat4(tmp, size);
+      copy_v3_v3(tmp[3], center);
+      /* Cone batch has base at 0 and is pointing towards +Y. */
+      swap_v3_v3(tmp[1], tmp[2]);
+      tmp[3][2] -= size[2];
+      mul_m4_m4m4(tmp, ob->obmat, tmp);
+      DRW_buffer_add_entry(cb->empty_cone, color, tmp);
+      break;
+    case OB_BOUND_CAPSULE:
+      size[0] = max_ff(size[0], size[1]);
+      size[1] = size[0];
+      scale_m4_fl(tmp, size[0]);
+      copy_v2_v2(tmp[3], center);
+      tmp[3][2] = center[2] + max_ff(0.0f, size[2] - size[0]);
+      mul_m4_m4m4(final_mat, ob->obmat, tmp);
+      DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat);
+      negate_v3(tmp[2]);
+      tmp[3][2] = center[2] - max_ff(0.0f, size[2] - size[0]);
+      mul_m4_m4m4(final_mat, ob->obmat, tmp);
+      DRW_buffer_add_entry(cb->empty_capsule_cap, color, final_mat);
+      tmp[2][2] = max_ff(0.0f, size[2] * 2.0f - size[0] * 2.0f);
+      mul_m4_m4m4(final_mat, ob->obmat, tmp);
+      DRW_buffer_add_entry(cb->empty_capsule_body, color, final_mat);
+      break;
+  }
+}
+
+static void OVERLAY_collision(OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id)
+{
+  switch (ob->rigidbody_object->shape) {
+    case RB_SHAPE_BOX:
+      OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_BOX, true);
+      break;
+    case RB_SHAPE_SPHERE:
+      OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_SPHERE, true);
+      break;
+    case RB_SHAPE_CONE:
+      OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CONE, true);
+      break;
+    case RB_SHAPE_CYLINDER:
+      OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CYLINDER, true);
+      break;
+    case RB_SHAPE_CAPSULE:
+      OVERLAY_bounds(cb, ob, theme_id, OB_BOUND_CAPSULE, true);
+      break;
+  }
+}
+
+static void OVERLAY_texture_space(OVERLAY_ExtraCallBuffers *cb, Object *ob, int theme_id)
+{
+  if (ob->data == NULL) {
+    return;
+  }
+
+  ID *ob_data = ob->data;
+  float *texcoloc = NULL;
+  float *texcosize = NULL;
+
+  switch (GS(ob_data->name)) {
+    case ID_ME:
+      BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize);
+      break;
+    case ID_CU: {
+      Curve *cu = (Curve *)ob_data;
+      BKE_curve_texspace_ensure(cu);
+      texcoloc = cu->loc;
+      texcosize = cu->size;
+      break;
+    }
+    case ID_MB: {
+      MetaBall *mb = (MetaBall *)ob_data;
+      texcoloc = mb->loc;
+      texcosize = mb->size;
+      break;
+    }
+    default:
+      BLI_assert(0);
+  }
+
+  float mat[4][4], color[4];
+  size_to_mat4(mat, texcosize);
+  copy_v3_v3(mat[3], texcoloc);
+
+  mul_m4_m4m4(mat, ob->obmat, mat);
+
+  UI_GetThemeColor4fv(theme_id, color);
+
+  DRW_buffer_add_entry(cb->empty_cube, color, mat);
+}
+
+static void OVERLAY_forcefield(OVERLAY_ExtraCallBuffers *cb, Object *ob, ViewLayer *view_layer)
+{
+  int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+  float *color = DRW_color_background_blend_get(theme_id);
+  PartDeflect *pd = ob->pd;
+  Curve *cu = (ob->type == OB_CURVE) ? ob->data : NULL;
+
+  union {
+    float mat[4][4];
+    struct {
+      float _pad00[3], size_x;
+      float _pad01[3], size_y;
+      float _pad02[3], size_z;
+      float pos[3], _pad03[1];
+    };
+  } instdata;
+
+  copy_m4_m4(instdata.mat, ob->obmat);
+  instdata.size_x = instdata.size_y = instdata.size_z = ob->empty_drawsize;
+
+  switch (pd->forcefield) {
+    case PFIELD_FORCE:
+      DRW_buffer_add_entry(cb->field_force, color, &instdata);
+      break;
+    case PFIELD_WIND:
+      instdata.size_z = pd->f_strength;
+      DRW_buffer_add_entry(cb->field_wind, color, &instdata);
+      break;
+    case PFIELD_VORTEX:
+      instdata.size_y = (pd->f_strength < 0.0f) ? -instdata.size_y : instdata.size_y;
+      DRW_buffer_add_entry(cb->field_vortex, color, &instdata);
+      break;
+    case PFIELD_GUIDE:
+      if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path &&
+          ob->runtime.curve_cache->path->data) {
+        instdata.size_x = instdata.size_y = instdata.size_z = pd->f_strength;
+        float pos[3], tmp[3];
+        where_on_path(ob, 0.0f, pos, tmp, NULL, NULL, NULL);
+        copy_v3_v3(instdata.pos, ob->obmat[3]);
+        translate_m4(instdata.mat, pos[0], pos[1], pos[2]);
+        DRW_buffer_add_entry(cb->field_curve, color, &instdata);
+
+        where_on_path(ob, 1.0f, pos, tmp, NULL, NULL, NULL);
+        copy_v3_v3(instdata.pos, ob->obmat[3]);
+        translate_m4(instdata.mat, pos[0], pos[1], pos[2]);
+        DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+        /* Restore */
+        copy_v3_v3(instdata.pos, ob->obmat[3]);
+      }
+      break;
+  }
+
+  if (pd->falloff == PFIELD_FALL_TUBE) {
+    if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+      instdata.size_z = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+      instdata.size_x = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
+      instdata.size_y = instdata.size_x;
+      DRW_buffer_add_entry(cb->field_tube_limit, color, &instdata);
+    }
+    if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+      instdata.size_z = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+      instdata.size_x = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
+      instdata.size_y = instdata.size_x;
+      DRW_buffer_add_entry(cb->field_tube_limit, color, &instdata);
+    }
+  }
+  else if (pd->falloff == PFIELD_FALL_CONE) {
+    if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+      float radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
+      float distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+      instdata.size_x = distance * sinf(radius);
+      instdata.size_z = distance * cosf(radius);
+      instdata.size_y = instdata.size_x;
+      DRW_buffer_add_entry(cb->field_cone_limit, color, &instdata);
+    }
+    if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+      float radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
+      float distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+      instdata.size_x = distance * sinf(radius);
+      instdata.size_z = distance * cosf(radius);
+      instdata.size_y = instdata.size_x;
+      DRW_buffer_add_entry(cb->field_cone_limit, color, &instdata);
+    }
+  }
+  else if (pd->falloff == PFIELD_FALL_SPHERE) {
+    if (pd->flag & PFIELD_USEMAX) {
+      instdata.size_x = instdata.size_y = instdata.size_z = pd->maxdist;
+      DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+    }
+    if (pd->flag & PFIELD_USEMIN) {
+      instdata.size_x = instdata.size_y = instdata.size_z = pd->mindist;
+      DRW_buffer_add_entry(cb->field_sphere_limit, color, &instdata);
+    }
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lights
+ * \{ */
+
+void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ViewLayer *view_layer = draw_ctx->view_layer;
+
+  Light *la = ob->data;
+  float *color_p;
+  DRW_object_wire_theme_get(ob, view_layer, &color_p);
+  /* Remove the alpha. */
+  float color[4] = {color_p[0], color_p[1], color_p[2], 1.0f};
+  /* Pack render data into object matrix. */
+  union {
+    float mat[4][4];
+    struct {
+      float _pad00[3];
+      union {
+        float area_size_x;
+        float spot_cosine;
+      };
+      float _pad01[3];
+      union {
+        float area_size_y;
+        float spot_blend;
+      };
+      float _pad02[3], clip_sta;
+      float pos[3], clip_end;
+    };
+  } instdata;
+
+  copy_m4_m4(instdata.mat, ob->obmat);
+  /* FIXME / TODO: clipend has no meaning nowadays.
+   * In EEVEE, Only clipsta is used shadowmaping.
+   * Clip end is computed automatically based on light power. */
+  instdata.clip_end = la->clipend;
+  instdata.clip_sta = la->clipsta;
+
+  DRW_buffer_add_entry(cb->groundline, instdata.pos);
+
+  if (la->type == LA_LOCAL) {
+    instdata.area_size_x = instdata.area_size_y = la->area_size;
+    DRW_buffer_add_entry(cb->light_point, color, &instdata);
+  }
+  else if (la->type == LA_SUN) {
+    DRW_buffer_add_entry(cb->light_sun, color, &instdata);
+  }
+  else if (la->type == LA_SPOT) {
+    /* For cycles and eevee the spot attenuation is
+     * y = (1/(1 + x^2) - a)/((1 - a) b)
+     * We solve the case where spot attenuation y = 1 and y = 0
+     * root for y = 1 is  (-1 - c) / c
+     * root for y = 0 is  (1 - a) / a
+     * and use that to position the blend circle. */
+    float a = cosf(la->spotsize * 0.5f);
+    float b = la->spotblend;
+    float c = a * b - a - b;
+    /* Optimized version or root1 / root0 */
+    instdata.spot_blend = sqrtf((-a - c * a) / (c - c * a));
+    instdata.spot_cosine = a;
+    /* HACK: We pack the area size in alpha color. This is decoded by the shader. */
+    color[3] = -max_ff(la->area_size, FLT_MIN);
+    DRW_buffer_add_entry(cb->light_spot, color, &instdata);
+
+    if ((la->mode & LA_SHOW_CONE) && !DRW_state_is_select()) {
+      float color_inside[4] = {0.0f, 0.0f, 0.0f, 0.5f};
+      float color_outside[4] = {1.0f, 1.0f, 1.0f, 0.3f};
+      DRW_buffer_add_entry(cb->light_spot_cone_front, color_inside, &instdata);
+      DRW_buffer_add_entry(cb->light_spot_cone_back, color_outside, &instdata);
+    }
+  }
+  else if (la->type == LA_AREA) {
+    bool uniform_scale = !ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE);
+    int sqr = ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_RECT);
+    instdata.area_size_x = la->area_size;
+    instdata.area_size_y = uniform_scale ? la->area_size : la->area_sizey;
+    DRW_buffer_add_entry(cb->light_area[sqr], color, &instdata);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lightprobe
+ * \{ */
+
+void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ViewLayer *view_layer = draw_ctx->view_layer;
+  float *color_p;
+  DRW_object_wire_theme_get(ob, view_layer, &color_p);
+  const LightProbe *prb = (LightProbe *)ob->data;
+  const bool show_clipping = (prb->flag & LIGHTPROBE_FLAG_SHOW_CLIP_DIST) != 0;
+  const bool show_parallax = (prb->flag & LIGHTPROBE_FLAG_SHOW_PARALLAX) != 0;
+  const bool show_influence = (prb->flag & LIGHTPROBE_FLAG_SHOW_INFLUENCE) != 0;
+
+  union {
+    float mat[4][4];
+    struct {
+      float _pad00[4];
+      float _pad01[4];
+      float _pad02[3], clip_sta;
+      float pos[3], clip_end;
+    };
+  } instdata;
+
+  copy_m4_m4(instdata.mat, ob->obmat);
+
+  switch (prb->type) {
+    case LIGHTPROBE_TYPE_CUBE:
+      instdata.clip_sta = show_clipping ? prb->clipsta : -1.0;
+      instdata.clip_end = show_clipping ? prb->clipend : -1.0;
+      DRW_buffer_add_entry(cb->probe_grid, color_p, &instdata);
+      DRW_buffer_add_entry(cb->groundline, instdata.pos);
+
+      if (show_influence) {
+        char shape = (prb->attenuation_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE;
+        float f = 1.0f - prb->falloff;
+        OVERLAY_empty_shape(cb, ob->obmat, prb->distinf, shape, color_p);
+        OVERLAY_empty_shape(cb, ob->obmat, prb->distinf * f, shape, color_p);
+      }
+
+      if (show_parallax) {
+        char shape = (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) ? OB_CUBE : OB_EMPTY_SPHERE;
+        float dist = ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) ? prb->distpar :
+                                                                            prb->distinf;
+        OVERLAY_empty_shape(cb, ob->obmat, dist, shape, color_p);
+      }
+      break;
+    case LIGHTPROBE_TYPE_GRID:
+      instdata.clip_sta = show_clipping ? prb->clipsta : -1.0;
+      instdata.clip_end = show_clipping ? prb->clipend : -1.0;
+      DRW_buffer_add_entry(cb->probe_grid, color_p, &instdata);
+
+      if (show_influence) {
+        float f = 1.0f - prb->falloff;
+        OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf, OB_CUBE, color_p);
+        OVERLAY_empty_shape(cb, ob->obmat, 1.0 + prb->distinf * f, OB_CUBE, color_p);
+      }
+      break;
+    case LIGHTPROBE_TYPE_PLANAR:
+      DRW_buffer_add_entry(cb->probe_planar, color_p, &instdata);
+
+      if (show_influence) {
+        normalize_v3_length(instdata.mat[2], prb->distinf);
+        DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+        mul_v3_fl(instdata.mat[2], 1.0f - prb->falloff);
+        DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+      }
+      zero_v3(instdata.mat[2]);
+      DRW_buffer_add_entry(cb->empty_cube, color_p, &instdata);
+
+      normalize_m4_m4(instdata.mat, ob->obmat);
+      OVERLAY_empty_shape(cb, instdata.mat, ob->empty_drawsize, OB_SINGLE_ARROW, color_p);
+      break;
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Speaker
+ * \{ */
+
+void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ViewLayer *view_layer = draw_ctx->view_layer;
+  float *color_p;
+  DRW_object_wire_theme_get(ob, view_layer, &color_p);
+
+  DRW_buffer_add_entry(cb->speaker, color_p, ob->obmat);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Camera
+ * \{ */
+
+typedef union OVERLAY_CameraInstanceData {
+  /* Pack render data into object matrix and object color. */
+  struct {
+    float color[4];
+    float mat[4][4];
+  };
+  struct {
+    float _pad0[2];
+    float volume_sta;
+    union {
+      float depth;
+      float focus;
+      float volume_end;
+    };
+    float _pad00[3];
+    union {
+      float corner_x;
+      float dist_color_id;
+    };
+    float _pad01[3];
+    union {
+      float corner_y;
+    };
+    float _pad02[3];
+    union {
+      float center_x;
+      float clip_sta;
+      float mist_sta;
+    };
+    float pos[3];
+    union {
+      float center_y;
+      float clip_end;
+      float mist_end;
+    };
+  };
+} OVERLAY_CameraInstanceData;
+
+static void camera_view3d_reconstruction(OVERLAY_ExtraCallBuffers *cb,
+                                         Scene *scene,
+                                         View3D *v3d,
+                                         Object *camera_object,
+                                         Object *ob,
+                                         const float color[4])
+{
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  const bool is_select = DRW_state_is_select();
+  const Object *orig_camera_object = DEG_get_original_object(camera_object);
+
+  MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
+  if (clip == NULL) {
+    return;
+  }
+
+  const bool is_solid_bundle = (v3d->bundle_drawtype == OB_EMPTY_SPHERE) &&
+                               ((v3d->shading.type != OB_SOLID) || !XRAY_FLAG_ENABLED(v3d));
+
+  MovieTracking *tracking = &clip->tracking;
+  /* Index must start in 1, to mimic BKE_tracking_track_get_indexed. */
+  int track_index = 1;
+
+  uchar text_color_selected[4], text_color_unselected[4];
+  float bundle_color_unselected[4], bundle_color_solid[4];
+
+  UI_GetThemeColor4ubv(TH_SELECT, text_color_selected);
+  UI_GetThemeColor4ubv(TH_TEXT, text_color_unselected);
+  UI_GetThemeColor4fv(TH_WIRE, bundle_color_unselected);
+  UI_GetThemeColor4fv(TH_BUNDLE_SOLID, bundle_color_solid);
+
+  float camera_mat[4][4], normal_mat[4][4];
+  BKE_tracking_get_camera_object_matrix(scene, ob, camera_mat);
+
+  normalize_m4_m4(normal_mat, ob->obmat);
+
+  LISTBASE_FOREACH (MovieTrackingObject *, tracking_object, &tracking->objects) {
+    float tracking_object_mat[4][4];
+
+    if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+      copy_m4_m4(tracking_object_mat, camera_mat);
+    }
+    else {
+      const int framenr = BKE_movieclip_remap_scene_to_clip_frame(
+          clip, DEG_get_ctime(draw_ctx->depsgraph));
+      float object_mat[4][4];
+      BKE_tracking_camera_get_reconstructed_interpolate(
+          tracking, tracking_object, framenr, object_mat);
+
+      invert_m4(object_mat);
+      mul_m4_m4m4(tracking_object_mat, normal_mat, object_mat);
+    }
+
+    ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+    for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
+      if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+        continue;
+      }
+      bool is_selected = TRACK_SELECTED(track);
+
+      float bundle_mat[4][4];
+      copy_m4_m4(bundle_mat, tracking_object_mat);
+      translate_m4(bundle_mat, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+
+      const float *bundle_color;
+      if (track->flag & TRACK_CUSTOMCOLOR) {
+        bundle_color = track->color;
+      }
+      else if (is_solid_bundle) {
+        bundle_color = bundle_color_solid;
+      }
+      else if (is_selected) {
+        bundle_color = color;
+      }
+      else {
+        bundle_color = bundle_color_unselected;
+      }
+
+      if (is_select) {
+        DRW_select_load_id(orig_camera_object->runtime.select_id | (track_index << 16));
+        track_index++;
+      }
+
+      if (is_solid_bundle) {
+        if (is_selected) {
+          OVERLAY_empty_shape(cb, bundle_mat, v3d->bundle_size, v3d->bundle_drawtype, color);
+        }
+
+        const float bundle_color_v4[4] = {
+            bundle_color[0],
+            bundle_color[1],
+            bundle_color[2],
+            1.0f,
+        };
+
+        bundle_mat[3][3] = v3d->bundle_size; /* See shader. */
+        DRW_buffer_add_entry(cb->empty_sphere_solid, bundle_color_v4, bundle_mat);
+      }
+      else {
+        OVERLAY_empty_shape(cb, bundle_mat, v3d->bundle_size, v3d->bundle_drawtype, bundle_color);
+      }
+
+      if ((v3d->flag2 & V3D_SHOW_BUNDLENAME) && !is_select) {
+        struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+        DRW_text_cache_add(dt,
+                           bundle_mat[3],
+                           track->name,
+                           strlen(track->name),
+                           10,
+                           0,
+                           DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+                           is_selected ? text_color_selected : text_color_unselected);
+      }
+    }
+
+    if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA) &&
+        !is_select) {
+      MovieTrackingReconstruction *reconstruction;
+      reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object);
+
+      if (reconstruction->camnr) {
+        MovieReconstructedCamera *camera = reconstruction->cameras;
+        float v0[3], v1[3];
+        for (int a = 0; a < reconstruction->camnr; a++, camera++) {
+          copy_v3_v3(v0, v1);
+          copy_v3_v3(v1, camera->mat[3]);
+          mul_m4_v3(camera_mat, v1);
+          if (a > 0) {
+            /* This one is suboptimal (gl_lines instead of gl_line_strip)
+             * but we keep this for simplicity */
+            OVERLAY_extra_line(cb, v0, v1, TH_CAMERA_PATH);
+          }
+        }
+      }
+    }
+  }
+}
+
+static float camera_offaxis_shiftx_get(Scene *scene,
+                                       Object *ob,
+                                       const OVERLAY_CameraInstanceData *instdata,
+                                       bool right_eye)
+{
+  Camera *cam = ob->data;
+  if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+    const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+    const float shiftx = BKE_camera_multiview_shift_x(&scene->r, ob, viewnames[right_eye]);
+    const float delta_shiftx = shiftx - cam->shiftx;
+    const float width = instdata->corner_x * 2.0f;
+    return delta_shiftx * width;
+  }
+  else {
+    return 0.0;
+  }
+}
+/**
+ * Draw the stereo 3d support elements (cameras, plane, volume).
+ * They are only visible when not looking through the camera:
+ */
+static void camera_stereoscopy_extra(OVERLAY_ExtraCallBuffers *cb,
+                                     Scene *scene,
+                                     View3D *v3d,
+                                     Object *ob,
+                                     const OVERLAY_CameraInstanceData *instdata)
+{
+  OVERLAY_CameraInstanceData stereodata = *instdata;
+  Camera *cam = ob->data;
+  const bool is_select = DRW_state_is_select();
+  const char *viewnames[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+  const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) != 0;
+  const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) != 0;
+  const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME) != 0;
+
+  for (int eye = 0; eye < 2; eye++) {
+    ob = BKE_camera_multiview_render(scene, ob, viewnames[eye]);
+    BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[eye], stereodata.mat);
+
+    stereodata.corner_x = instdata->corner_x;
+    stereodata.corner_y = instdata->corner_y;
+    stereodata.center_x = instdata->center_x + camera_offaxis_shiftx_get(scene, ob, instdata, eye);
+    stereodata.center_y = instdata->center_y;
+    stereodata.depth = instdata->depth;
+
+    if (is_stereo3d_cameras) {
+      DRW_buffer_add_entry_struct(cb->camera_frame, &stereodata);
+
+      /* Connecting line between cameras. */
+      OVERLAY_extra_line_dashed(cb, stereodata.pos, instdata->pos, G_draw.block.colorWire);
+    }
+
+    if (is_stereo3d_volume && !is_select) {
+      float r = (eye == 1) ? 2.0f : 1.0f;
+
+      stereodata.volume_sta = -cam->clip_start;
+      stereodata.volume_end = -cam->clip_end;
+      /* Encode eye + intensity and alpha (see shader) */
+      copy_v2_fl2(stereodata.color, r + 0.15f, 1.0f);
+      DRW_buffer_add_entry_struct(cb->camera_volume_frame, &stereodata);
+
+      if (v3d->stereo3d_volume_alpha > 0.0f) {
+        /* Encode eye + intensity and alpha (see shader) */
+        copy_v2_fl2(stereodata.color, r + 0.999f, v3d->stereo3d_volume_alpha);
+        DRW_buffer_add_entry_struct(cb->camera_volume, &stereodata);
+      }
+      /* restore */
+      copy_v3_v3(stereodata.color, instdata->color);
+    }
+  }
+
+  if (is_stereo3d_plane && !is_select) {
+    if (cam->stereo.convergence_mode == CAM_S3D_TOE) {
+      /* There is no real convergence plane but we highlight the center
+       * point where the views are pointing at. */
+      // zero_v3(stereodata.mat[0]); /* We reconstruct from Z and Y */
+      // zero_v3(stereodata.mat[1]); /* Y doesn't change */
+      zero_v3(stereodata.mat[2]);
+      zero_v3(stereodata.mat[3]);
+      for (int i = 0; i < 2; i++) {
+        float mat[4][4];
+        /* Need normalized version here. */
+        BKE_camera_multiview_model_matrix(&scene->r, ob, viewnames[i], mat);
+        add_v3_v3(stereodata.mat[2], mat[2]);
+        madd_v3_v3fl(stereodata.mat[3], mat[3], 0.5f);
+      }
+      normalize_v3(stereodata.mat[2]);
+      cross_v3_v3v3(stereodata.mat[0], stereodata.mat[1], stereodata.mat[2]);
+    }
+    else if (cam->stereo.convergence_mode == CAM_S3D_PARALLEL) {
+      /* Show plane at the given distance between the views even if it makes no sense. */
+      zero_v3(stereodata.pos);
+      for (int i = 0; i < 2; i++) {
+        float mat[4][4];
+        BKE_camera_multiview_model_matrix_scaled(&scene->r, ob, viewnames[i], mat);
+        madd_v3_v3fl(stereodata.pos, mat[3], 0.5f);
+      }
+    }
+    else if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) {
+      /* Nothing to do. Everything is already setup. */
+    }
+    stereodata.volume_sta = -cam->stereo.convergence_distance;
+    stereodata.volume_end = -cam->stereo.convergence_distance;
+    /* Encode eye + intensity and alpha (see shader) */
+    copy_v2_fl2(stereodata.color, 0.1f, 1.0f);
+    DRW_buffer_add_entry_struct(cb->camera_volume_frame, &stereodata);
+
+    if (v3d->stereo3d_convergence_alpha > 0.0f) {
+      /* Encode eye + intensity and alpha (see shader) */
+      copy_v2_fl2(stereodata.color, 0.0f, v3d->stereo3d_convergence_alpha);
+      DRW_buffer_add_entry_struct(cb->camera_volume, &stereodata);
+    }
+  }
+}
+
+void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  OVERLAY_CameraInstanceData instdata;
+
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ViewLayer *view_layer = draw_ctx->view_layer;
+  View3D *v3d = draw_ctx->v3d;
+  Scene *scene = draw_ctx->scene;
+  RegionView3D *rv3d = draw_ctx->rv3d;
+
+  Camera *cam = ob->data;
+  Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+  const bool is_select = DRW_state_is_select();
+  const bool is_active = (ob == camera_object);
+  const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
+
+  const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
+  const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
+  const bool is_stereo3d_display_extra = is_active && is_multiview && (!look_through) &&
+                                         ((v3d->stereo3d_flag) != 0);
+  const bool is_selection_camera_stereo = is_select && look_through && is_multiview &&
+                                          is_stereo3d_view;
+
+  float vec[4][3], asp[2], shift[2], scale[3], drawsize, center[2], corner[2];
+
+  float *color_p;
+  DRW_object_wire_theme_get(ob, view_layer, &color_p);
+  copy_v4_v4(instdata.color, color_p);
+
+  normalize_m4_m4(instdata.mat, ob->obmat);
+
+  /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here. */
+  if (is_selection_camera_stereo) {
+    copy_v3_fl(scale, 1.0f);
+  }
+  else {
+    copy_v3_fl3(scale, len_v3(ob->obmat[0]), len_v3(ob->obmat[1]), len_v3(ob->obmat[2]));
+    invert_v3(scale);
+  }
+
+  BKE_camera_view_frame_ex(
+      scene, cam, cam->drawsize, look_through, scale, asp, shift, &drawsize, vec);
+
+  /* Apply scale to simplify the rest of the drawing. */
+  invert_v3(scale);
+  for (int i = 0; i < 4; i++) {
+    mul_v3_v3(vec[i], scale);
+    /* Project to z=-1 plane. Makes positionning / scaling easier. (see shader) */
+    mul_v2_fl(vec[i], 1.0f / fabsf(vec[i][2]));
+  }
+
+  /* Frame coords */
+  mid_v2_v2v2(center, vec[0], vec[2]);
+  sub_v2_v2v2(corner, vec[0], center);
+  instdata.corner_x = corner[0];
+  instdata.corner_y = corner[1];
+  instdata.center_x = center[0];
+  instdata.center_y = center[1];
+  instdata.depth = vec[0][2];
+
+  if (look_through) {
+    if (!DRW_state_is_image_render()) {
+      /* Only draw the frame. */
+      if (is_multiview) {
+        float mat[4][4];
+        const bool is_right = v3d->multiview_eye == STEREO_RIGHT_ID;
+        const char *view_name = is_right ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME;
+        BKE_camera_multiview_model_matrix(&scene->r, ob, view_name, mat);
+        instdata.center_x += camera_offaxis_shiftx_get(scene, ob, &instdata, is_right);
+        for (int i = 0; i < 4; i++) {
+          /* Partial copy to avoid overriding packed data. */
+          copy_v3_v3(instdata.mat[i], mat[i]);
+        }
+      }
+      instdata.depth = -instdata.depth; /* Hides the back of the camera wires (see shader). */
+      DRW_buffer_add_entry_struct(cb->camera_frame, &instdata);
+    }
+  }
+  else {
+    /* Stereo cameras, volumes, plane drawing. */
+    if (is_stereo3d_display_extra) {
+      camera_stereoscopy_extra(cb, scene, v3d, ob, &instdata);
+    }
+    else {
+      DRW_buffer_add_entry_struct(cb->camera_frame, &instdata);
+    }
+  }
+
+  if (!look_through) {
+    /* Triangle. */
+    float tria_size = 0.7f * drawsize / fabsf(instdata.depth);
+    float tria_margin = 0.1f * drawsize / fabsf(instdata.depth);
+    instdata.center_x = center[0];
+    instdata.center_y = center[1] + instdata.corner_y + tria_margin + tria_size;
+    instdata.corner_x = instdata.corner_y = -tria_size;
+    DRW_buffer_add_entry_struct(cb->camera_tria[is_active], &instdata);
+  }
+
+  if (cam->flag & CAM_SHOWLIMITS) {
+    /* Scale focus point. */
+    mul_v3_fl(instdata.mat[0], cam->drawsize);
+    mul_v3_fl(instdata.mat[1], cam->drawsize);
+
+    instdata.dist_color_id = (is_active) ? 3 : 2;
+    instdata.focus = -BKE_camera_object_dof_distance(ob);
+    instdata.clip_sta = cam->clip_start;
+    instdata.clip_end = cam->clip_end;
+    DRW_buffer_add_entry_struct(cb->camera_distances, &instdata);
+  }
+
+  if (cam->flag & CAM_SHOWMIST) {
+    World *world = scene->world;
+    if (world) {
+      instdata.dist_color_id = (is_active) ? 1 : 0;
+      instdata.focus = 1.0f; /* Disable */
+      instdata.mist_sta = world->miststa;
+      instdata.mist_end = world->miststa + world->mistdist;
+      DRW_buffer_add_entry_struct(cb->camera_distances, &instdata);
+    }
+  }
+
+  /* Motion Tracking. */
+  if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) != 0) {
+    camera_view3d_reconstruction(cb, scene, v3d, camera_object, ob, color_p);
+  }
+
+  /* Background images. */
+  if (look_through && (cam->flag & CAM_SHOW_BG_IMAGE) && !BLI_listbase_is_empty(&cam->bg_images)) {
+    OVERLAY_image_camera_cache_populate(vedata, ob);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Relationships & constraints
+ * \{ */
+
+static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
+                                       Depsgraph *depsgraph,
+                                       Scene *scene,
+                                       Object *ob)
+{
+  float *relation_color = G_draw.block.colorWire;
+  float *constraint_color = G_draw.block.colorGridAxisZ; /* ? */
+
+  if (ob->parent && (DRW_object_visibility_in_active_context(ob->parent) & OB_VISIBLE_SELF)) {
+    float *parent_pos = ob->runtime.parent_display_origin;
+    OVERLAY_extra_line_dashed(cb, parent_pos, ob->obmat[3], relation_color);
+  }
+
+  if (ob->rigidbody_constraint) {
+    Object *rbc_ob1 = ob->rigidbody_constraint->ob1;
+    Object *rbc_ob2 = ob->rigidbody_constraint->ob2;
+    if (rbc_ob1 && (DRW_object_visibility_in_active_context(rbc_ob1) & OB_VISIBLE_SELF)) {
+      OVERLAY_extra_line_dashed(cb, rbc_ob1->obmat[3], ob->obmat[3], relation_color);
+    }
+    if (rbc_ob2 && (DRW_object_visibility_in_active_context(rbc_ob2) & OB_VISIBLE_SELF)) {
+      OVERLAY_extra_line_dashed(cb, rbc_ob2->obmat[3], ob->obmat[3], relation_color);
+    }
+  }
+
+  /* Drawing the constraint lines */
+  if (!BLI_listbase_is_empty(&ob->constraints)) {
+    bConstraint *curcon;
+    bConstraintOb *cob;
+    ListBase *list = &ob->constraints;
+
+    cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+
+    for (curcon = list->first; curcon; curcon = curcon->next) {
+      if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+        /* special case for object solver and follow track constraints because they don't fill
+         * constraint targets properly (design limitation -- scene is needed for their target
+         * but it can't be accessed from get_targets callback) */
+        Object *camob = NULL;
+
+        if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+          bFollowTrackConstraint *data = (bFollowTrackConstraint *)curcon->data;
+          camob = data->camera ? data->camera : scene->camera;
+        }
+        else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+          bObjectSolverConstraint *data = (bObjectSolverConstraint *)curcon->data;
+          camob = data->camera ? data->camera : scene->camera;
+        }
+
+        if (camob) {
+          OVERLAY_extra_line_dashed(cb, camob->obmat[3], ob->obmat[3], constraint_color);
+        }
+      }
+      else {
+        const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+
+        if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) {
+          ListBase targets = {NULL, NULL};
+          bConstraintTarget *ct;
+
+          cti->get_constraint_targets(curcon, &targets);
+
+          for (ct = targets.first; ct; ct = ct->next) {
+            /* calculate target's matrix */
+            if (cti->get_target_matrix) {
+              cti->get_target_matrix(depsgraph, curcon, cob, ct, DEG_get_ctime(depsgraph));
+            }
+            else {
+              unit_m4(ct->matrix);
+            }
+            OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color);
+          }
+
+          if (cti->flush_constraint_targets) {
+            cti->flush_constraint_targets(curcon, &targets, 1);
+          }
+        }
+      }
+    }
+    BKE_constraints_clear_evalob(cob);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GPencil.
+ * \{ */
+
+static void OVERLAY_gpencil_color_names(Object *ob)
+{
+  if (ob->mode != OB_MODE_EDIT_GPENCIL) {
+    return;
+  }
+
+  bGPdata *gpd = (bGPdata *)ob->data;
+  if (gpd == NULL) {
+    return;
+  }
+
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ViewLayer *view_layer = draw_ctx->view_layer;
+  int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+  uchar color[4];
+  UI_GetThemeColor4ubv(theme_id, color);
+  struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+  for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+    if (gpl->flag & GP_LAYER_HIDE) {
+      continue;
+    }
+    bGPDframe *gpf = gpl->actframe;
+    if (gpf == NULL) {
+      continue;
+    }
+    for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+      Material *ma = give_current_material(ob, gps->mat_nr + 1);
+      if (ma == NULL) {
+        continue;
+      }
+
+      MaterialGPencilStyle *gp_style = ma->gp_style;
+      /* skip stroke if it doesn't have any valid data */
+      if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
+        continue;
+      }
+      /* check if the color is visible */
+      if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
+        continue;
+      }
+
+      /* only if selected */
+      if (gps->flag & GP_STROKE_SELECT) {
+        float fpt[3];
+        for (int i = 0; i < gps->totpoints; i++) {
+          bGPDspoint *pt = &gps->points[i];
+          if (pt->flag & GP_SPOINT_SELECT) {
+            mul_v3_m4v3(fpt, ob->obmat, &pt->x);
+            DRW_text_cache_add(dt,
+                               fpt,
+                               ma->id.name + 2,
+                               strlen(ma->id.name + 2),
+                               10,
+                               0,
+                               DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+                               color);
+            break;
+          }
+        }
+      }
+    }
+  }
+}
+
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *UNUSED(vedata), Object *ob)
+{
+  /* don't show object extras in set's */
+  if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+    if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
+      OVERLAY_gpencil_color_names(ob);
+    }
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Volumetric / Smoke sim
+ * \{ */
+
+static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
+                                 OVERLAY_Data *data,
+                                 Object *ob,
+                                 ModifierData *md,
+                                 Scene *scene,
+                                 float *color)
+{
+  SmokeModifierData *smd = (SmokeModifierData *)md;
+  SmokeDomainSettings *sds = smd->domain;
+
+  /* Don't show smoke before simulation starts, this could be made an option in the future. */
+  const bool draw_velocity = (sds->draw_velocity && sds->fluid &&
+                              CFRA >= sds->point_cache[0]->startframe);
+
+  /* Small cube showing voxel size. */
+  {
+    float min[3];
+    madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min);
+    float voxel_cubemat[4][4] = {{0.0f}};
+    /* scale small cube to voxel size */
+    voxel_cubemat[0][0] = 1.0f / (float)sds->base_res[0];
+    voxel_cubemat[1][1] = 1.0f / (float)sds->base_res[1];
+    voxel_cubemat[2][2] = 1.0f / (float)sds->base_res[2];
+    voxel_cubemat[3][3] = 1.0f;
+    /* translate small cube to corner */
+    copy_v3_v3(voxel_cubemat[3], min);
+    /* move small cube into the domain (otherwise its centered on vertex of domain object) */
+    translate_m4(voxel_cubemat, 1.0f, 1.0f, 1.0f);
+    mul_m4_m4m4(voxel_cubemat, ob->obmat, voxel_cubemat);
+
+    DRW_buffer_add_entry(cb->empty_cube, color, voxel_cubemat);
+  }
+
+  if (draw_velocity) {
+    const bool use_needle = (sds->vector_draw_type == VECTOR_DRAW_NEEDLE);
+    int line_count = (use_needle) ? 6 : 1;
+    int slice_axis = -1;
+    line_count *= sds->res[0] * sds->res[1] * sds->res[2];
+
+    if (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED &&
+        sds->axis_slice_method == AXIS_SLICE_SINGLE) {
+      float viewinv[4][4];
+      DRW_view_viewmat_get(NULL, viewinv, true);
+
+      const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) :
+                                                              sds->slice_axis - 1;
+      slice_axis = axis;
+      line_count /= sds->res[axis];
+    }
+
+    GPU_create_smoke_velocity(smd);
+
+    GPUShader *sh = OVERLAY_shader_volume_velocity(use_needle);
+    DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]);
+    DRW_shgroup_uniform_texture(grp, "velocityX", sds->tex_velocity_x);
+    DRW_shgroup_uniform_texture(grp, "velocityY", sds->tex_velocity_y);
+    DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z);
+    DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale);
+    DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth);
+    DRW_shgroup_uniform_vec3_copy(grp, "cellSize", sds->cell_size);
+    DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", sds->p0);
+    DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", sds->res_min);
+    DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis);
+    DRW_shgroup_call_procedural_lines(grp, ob, line_count);
+
+    BLI_addtail(&data->stl->pd->smoke_domains, BLI_genericNodeN(smd));
+  }
+}
+
+static void OVERLAY_volume_free_smoke_textures(OVERLAY_Data *data)
+{
+  /* Free Smoke Textures after rendering */
+  /* XXX This is a waste of processing and GPU bandwidth if nothing
+   * is updated. But the problem is since Textures are stored in the
+   * modifier we don't want them to take precious VRAM if the
+   * modifier is not used for display. We should share them for
+   * all viewport in a redraw at least. */
+  LinkData *link;
+  while ((link = BLI_pophead(&data->stl->pd->smoke_domains))) {
+    SmokeModifierData *smd = (SmokeModifierData *)link->data;
+    GPU_free_smoke_velocity(smd);
+    MEM_freeN(link);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+static void OVERLAY_object_center(OVERLAY_ExtraCallBuffers *cb,
+                                  Object *ob,
+                                  OVERLAY_PrivateData *pd,
+                                  ViewLayer *view_layer)
+{
+  const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob);
+
+  if (ob == OBACT(view_layer)) {
+    DRW_buffer_add_entry(cb->center_active, ob->obmat[3]);
+  }
+  else if (ob->base_flag & BASE_SELECTED) {
+    DRWCallBuffer *cbuf = (is_library) ? cb->center_selected_lib : cb->center_selected;
+    DRW_buffer_add_entry(cbuf, ob->obmat[3]);
+  }
+  else if (pd->v3d_flag & V3D_DRAW_CENTERS) {
+    DRWCallBuffer *cbuf = (is_library) ? cb->center_deselected_lib : cb->center_deselected;
+    DRW_buffer_add_entry(cbuf, ob->obmat[3]);
+  }
+}
+
+static void OVERLAY_object_name(Object *ob, int theme_id)
+{
+  struct DRWTextStore *dt = DRW_text_cache_ensure();
+  uchar color[4];
+  UI_GetThemeColor4ubv(theme_id, color);
+
+  DRW_text_cache_add(dt,
+                     ob->obmat[3],
+                     ob->id.name + 2,
+                     strlen(ob->id.name + 2),
+                     10,
+                     0,
+                     DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+                     color);
+}
+
+void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ViewLayer *view_layer = draw_ctx->view_layer;
+  Scene *scene = draw_ctx->scene;
+  ModifierData *md = NULL;
+
+  const bool is_select_mode = DRW_state_is_select();
+  const bool is_paint_mode = (draw_ctx->object_mode &
+                              (OB_MODE_ALL_PAINT | OB_MODE_ALL_PAINT_GPENCIL)) != 0;
+  const bool from_dupli = (ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) != 0;
+  const bool has_bounds = !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE);
+  const bool has_texspace = has_bounds &&
+                            !ELEM(ob->type, OB_EMPTY, OB_LATTICE, OB_ARMATURE, OB_GPENCIL);
+
+  const bool draw_relations = ((pd->v3d_flag & V3D_HIDE_HELPLINES) == 0) && !is_select_mode;
+  const bool draw_obcenters = !is_paint_mode &&
+                              (pd->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_ORIGINS) == 0;
+  const bool draw_texspace = (ob->dtx & OB_TEXSPACE) && has_texspace;
+  const bool draw_obname = (ob->dtx & OB_DRAWNAME) && DRW_state_show_text();
+  const bool draw_bounds = has_bounds && ((ob->dt == OB_BOUNDBOX) ||
+                                          ((ob->dtx & OB_DRAWBOUNDOX) && !from_dupli));
+  const bool draw_xform = draw_ctx->object_mode == OB_MODE_OBJECT &&
+                          (scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) &&
+                          (ob->base_flag & BASE_SELECTED) && !is_select_mode;
+  const bool draw_volume = !from_dupli && (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+                           (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+                           (((SmokeModifierData *)md)->domain != NULL);
+
+  float *color;
+  int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
+
+  if (ob->pd && ob->pd->forcefield) {
+    OVERLAY_forcefield(cb, ob, view_layer);
+  }
+
+  if (draw_bounds) {
+    OVERLAY_bounds(cb, ob, theme_id, ob->boundtype, false);
+  }
+  /* Helpers for when we're transforming origins. */
+  if (draw_xform) {
+    float color_xform[4] = {0.75f, 0.75f, 0.75f, 0.5f};
+    DRW_buffer_add_entry(cb->origin_xform, color_xform, ob->obmat);
+  }
+  /* don't show object extras in set's */
+  if (!from_dupli) {
+    if (draw_obcenters) {
+      OVERLAY_object_center(cb, ob, pd, view_layer);
+    }
+    if (draw_relations) {
+      OVERLAY_relationship_lines(cb, draw_ctx->depsgraph, draw_ctx->scene, ob);
+    }
+    if (draw_obname) {
+      OVERLAY_object_name(ob, theme_id);
+    }
+    if (draw_texspace) {
+      OVERLAY_texture_space(cb, ob, theme_id);
+    }
+    if (ob->rigidbody_object != NULL) {
+      OVERLAY_collision(cb, ob, theme_id);
+    }
+    if (ob->dtx & OB_AXIS) {
+      DRW_buffer_add_entry(cb->empty_axes, color, ob->obmat);
+    }
+    if (draw_volume) {
+      OVERLAY_volume_extra(cb, vedata, ob, md, scene, color);
+    }
+  }
+}
+
+void OVERLAY_extra_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->extra_blend_ps);
+
+  if (pd->antialiasing.enabled) {
+    GPU_framebuffer_bind(fbl->overlay_line_fb);
+  }
+
+  DRW_draw_pass(psl->extra_ps[0]);
+
+  if (pd->antialiasing.enabled) {
+    GPU_framebuffer_bind(fbl->overlay_default_fb);
+  }
+}
+
+void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->extra_ps[1]);
+
+  OVERLAY_volume_free_smoke_textures(vedata);
+}
+
+void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->extra_centers_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_facing.c b/source/blender/draw/engines/overlay/overlay_facing.c
new file mode 100644 (file)
index 0000000..a69d753
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_facing_init(OVERLAY_Data *UNUSED(vedata))
+{
+}
+
+void OVERLAY_facing_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+  DRW_PASS_CREATE(psl->facing_ps, state | pd->clipping_state);
+
+  GPUShader *sh = OVERLAY_shader_facing();
+  pd->facing_grp = DRW_shgroup_create(sh, psl->facing_ps);
+}
+
+void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
+  if (geom) {
+    DRW_shgroup_call(pd->facing_grp, geom, ob);
+  }
+}
+
+void OVERLAY_facing_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  /* We need to match underlying geometry pass, at the cost of bypassing TAA. */
+  DRW_view_set_active(NULL);
+
+  DRW_draw_pass(psl->facing_ps);
+
+  DRW_view_set_active(pd->view_default);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c
new file mode 100644 (file)
index 0000000..7dea6c1
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_camera_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "overlay_private.h"
+
+enum {
+  SHOW_AXIS_X = (1 << 0),
+  SHOW_AXIS_Y = (1 << 1),
+  SHOW_AXIS_Z = (1 << 2),
+  SHOW_GRID = (1 << 3),
+  PLANE_XY = (1 << 4),
+  PLANE_XZ = (1 << 5),
+  PLANE_YZ = (1 << 6),
+  CLIP_ZPOS = (1 << 7),
+  CLIP_ZNEG = (1 << 8),
+  GRID_BACK = (1 << 9),
+};
+
+void OVERLAY_grid_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  OVERLAY_ShadingData *shd = &pd->shdata;
+
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  View3D *v3d = draw_ctx->v3d;
+  Scene *scene = draw_ctx->scene;
+  RegionView3D *rv3d = draw_ctx->rv3d;
+
+  const bool show_axis_x = (pd->v3d_gridflag & V3D_SHOW_X) != 0;
+  const bool show_axis_y = (pd->v3d_gridflag & V3D_SHOW_Y) != 0;
+  const bool show_axis_z = (pd->v3d_gridflag & V3D_SHOW_Z) != 0;
+  const bool show_floor = (pd->v3d_gridflag & V3D_SHOW_FLOOR) != 0;
+  const bool show_ortho_grid = (pd->v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0;
+
+  shd->grid_flag = 0;
+
+  if (pd->hide_overlays || !(show_axis_y || show_axis_z || show_floor || show_ortho_grid)) {
+    return;
+  }
+
+  float viewinv[4][4], wininv[4][4];
+  float viewmat[4][4], winmat[4][4];
+  DRW_view_winmat_get(NULL, winmat, false);
+  DRW_view_winmat_get(NULL, wininv, true);
+  DRW_view_viewmat_get(NULL, viewmat, false);
+  DRW_view_viewmat_get(NULL, viewinv, true);
+
+  /* if perps */
+  if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) {
+    if (show_axis_x) {
+      shd->grid_flag |= PLANE_XY | SHOW_AXIS_X;
+    }
+    if (show_axis_y) {
+      shd->grid_flag |= PLANE_XY | SHOW_AXIS_Y;
+    }
+    if (show_floor) {
+      shd->grid_flag |= PLANE_XY | SHOW_GRID;
+    }
+  }
+  else {
+    if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
+      shd->grid_flag = PLANE_YZ | SHOW_AXIS_Y | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
+    }
+    else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+      shd->grid_flag = PLANE_XY | SHOW_AXIS_X | SHOW_AXIS_Y | SHOW_GRID | GRID_BACK;
+    }
+    else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+      shd->grid_flag = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK;
+    }
+  }
+
+  shd->grid_axes[0] = (float)((shd->grid_flag & (PLANE_XZ | PLANE_XY)) != 0);
+  shd->grid_axes[1] = (float)((shd->grid_flag & (PLANE_YZ | PLANE_XY)) != 0);
+  shd->grid_axes[2] = (float)((shd->grid_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+
+  /* Z axis if needed */
+  if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
+    shd->zpos_flag = SHOW_AXIS_Z;
+
+    float zvec[3], campos[3];
+    negate_v3_v3(zvec, viewinv[2]);
+    copy_v3_v3(campos, viewinv[3]);
+
+    /* z axis : chose the most facing plane */
+    if (fabsf(zvec[0]) < fabsf(zvec[1])) {
+      shd->zpos_flag |= PLANE_XZ;
+    }
+    else {
+      shd->zpos_flag |= PLANE_YZ;
+    }
+
+    shd->zneg_flag = shd->zpos_flag;
+
+    /* Persp : If camera is below floor plane, we switch clipping
+     * Ortho : If eye vector is looking up, we switch clipping */
+    if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) ||
+        ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) {
+      shd->zpos_flag |= CLIP_ZPOS;
+      shd->zneg_flag |= CLIP_ZNEG;
+    }
+    else {
+      shd->zpos_flag |= CLIP_ZNEG;
+      shd->zneg_flag |= CLIP_ZPOS;
+    }
+
+    shd->zplane_axes[0] = (float)((shd->zpos_flag & (PLANE_XZ | PLANE_XY)) != 0);
+    shd->zplane_axes[1] = (float)((shd->zpos_flag & (PLANE_YZ | PLANE_XY)) != 0);
+    shd->zplane_axes[2] = (float)((shd->zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+  }
+  else {
+    shd->zneg_flag = shd->zpos_flag = CLIP_ZNEG | CLIP_ZPOS;
+  }
+
+  float dist;
+  if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) {
+    Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+    dist = ((Camera *)(camera_object->data))->clip_end;
+  }
+  else {
+    dist = v3d->clip_end;
+  }
+
+  if (winmat[3][3] == 0.0f) {
+    shd->grid_mesh_size = dist;
+  }
+  else {
+    float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
+    shd->grid_mesh_size = viewdist * dist;
+  }
+
+  shd->grid_distance = dist / 2.0f;
+  shd->grid_line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f;
+
+  ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps);
+}
+
+void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_ShadingData *shd = &vedata->stl->pd->shdata;
+  OVERLAY_PassList *psl = vedata->psl;
+  DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+  psl->grid_ps = NULL;
+
+  if (shd->grid_flag == 0 || !DRW_state_is_fbo()) {
+    return;
+  }
+
+  DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+  DRW_PASS_CREATE(psl->grid_ps, state);
+
+  GPUShader *sh = OVERLAY_shader_grid();
+  struct GPUBatch *geom = DRW_cache_grid_get();
+
+  /* Create 3 quads to render ordered transparency Z axis */
+  DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps);
+  DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zneg_flag, 1);
+  DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1);
+  DRW_shgroup_uniform_float(grp, "gridDistance", &shd->grid_distance, 1);
+  DRW_shgroup_uniform_float_copy(grp, "lineKernel", shd->grid_line_size);
+  DRW_shgroup_uniform_float_copy(grp, "meshSize", shd->grid_mesh_size);
+  DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+  DRW_shgroup_call(grp, geom, NULL);
+
+  grp = DRW_shgroup_create(sh, psl->grid_ps);
+  DRW_shgroup_uniform_int(grp, "gridFlag", &shd->grid_flag, 1);
+  DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->grid_axes, 1);
+  DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+  DRW_shgroup_uniform_float(grp, "gridSteps", shd->grid_steps, ARRAY_SIZE(shd->grid_steps));
+  DRW_shgroup_call(grp, geom, NULL);
+
+  grp = DRW_shgroup_create(sh, psl->grid_ps);
+  DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zpos_flag, 1);
+  DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1);
+  DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+  DRW_shgroup_call(grp, geom, NULL);
+}
+
+void OVERLAY_grid_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+  if (psl->grid_ps) {
+    GPU_framebuffer_bind(fbl->overlay_color_only_fb);
+    DRW_draw_pass(psl->grid_ps);
+
+    GPU_framebuffer_bind(fbl->overlay_default_fb);
+  }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
new file mode 100644 (file)
index 0000000..1984e32
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_camera.h"
+#include "BKE_image.h"
+#include "BKE_movieclip.h"
+#include "BKE_object.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_screen_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_image_init(OVERLAY_Data *vedata)
+{
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  pd->view_reference_images = DRW_view_create_with_zoffset(
+      pd->view_default, draw_ctx->rv3d, -1.0f);
+}
+
+void OVERLAY_image_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  DRWState state;
+
+  state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_BLEND_ALPHA_UNDER_PREMUL;
+  DRW_PASS_CREATE(psl->image_background_under_ps, state);
+
+  state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+  DRW_PASS_CREATE(psl->image_background_over_ps, state);
+
+  state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+  DRW_PASS_CREATE(psl->image_empties_ps, state | pd->clipping_state);
+
+  state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+  DRW_PASS_CREATE(psl->image_empties_back_ps, state | pd->clipping_state);
+  DRW_PASS_CREATE(psl->image_empties_blend_ps, state | pd->clipping_state);
+
+  state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+  DRW_PASS_CREATE(psl->image_empties_front_ps, state);
+  DRW_PASS_CREATE(psl->image_foreground_ps, state);
+}
+
+static void overlay_image_calc_aspect(Image *ima, const int size[2], float r_image_aspect[2])
+{
+  float ima_x, ima_y;
+  if (ima) {
+    ima_x = size[0];
+    ima_y = size[1];
+  }
+  else {
+    /* if no image, make it a 1x1 empty square, honor scale & offset */
+    ima_x = ima_y = 1.0f;
+  }
+  /* Get the image aspect even if the buffer is invalid */
+  float sca_x = 1.0f, sca_y = 1.0f;
+  if (ima) {
+    if (ima->aspx > ima->aspy) {
+      sca_y = ima->aspy / ima->aspx;
+    }
+    else if (ima->aspx < ima->aspy) {
+      sca_x = ima->aspx / ima->aspy;
+    }
+  }
+
+  const float scale_x_inv = ima_x * sca_x;
+  const float scale_y_inv = ima_y * sca_y;
+  if (scale_x_inv > scale_y_inv) {
+    r_image_aspect[0] = 1.0f;
+    r_image_aspect[1] = scale_y_inv / scale_x_inv;
+  }
+  else {
+    r_image_aspect[0] = scale_x_inv / scale_y_inv;
+    r_image_aspect[1] = 1.0f;
+  }
+}
+
+static void camera_background_images_stereo_setup(Scene *scene,
+                                                  View3D *v3d,
+                                                  Image *ima,
+                                                  ImageUser *iuser)
+{
+  if (BKE_image_is_stereo(ima)) {
+    iuser->flag |= IMA_SHOW_STEREO;
+
+    if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+      iuser->multiview_eye = STEREO_LEFT_ID;
+    }
+    else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+      /* show only left or right camera */
+      iuser->multiview_eye = v3d->stereo3d_camera;
+    }
+
+    BKE_image_multiview_index(ima, iuser);
+  }
+  else {
+    iuser->flag &= ~IMA_SHOW_STEREO;
+  }
+}
+
+static struct GPUTexture *image_camera_background_texture_get(CameraBGImage *bgpic,
+                                                              const DRWContextState *draw_ctx,
+                                                              OVERLAY_PrivateData *pd,
+                                                              float *r_aspect,
+                                                              bool *r_use_alpha_premult)
+{
+  Image *image = bgpic->ima;
+  ImageUser *iuser = &bgpic->iuser;
+  MovieClip *clip = NULL;
+  GPUTexture *tex = NULL;
+  Scene *scene = draw_ctx->scene;
+  float aspect_x, aspect_y;
+  int width, height;
+  int ctime = (int)DEG_get_ctime(draw_ctx->depsgraph);
+  *r_use_alpha_premult = false;
+
+  switch (bgpic->source) {
+    case CAM_BGIMG_SOURCE_IMAGE:
+      if (image == NULL) {
+        return NULL;
+      }
+      *r_use_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
+
+      BKE_image_user_frame_calc(image, iuser, ctime);
+      if (image->source == IMA_SRC_SEQUENCE && !(iuser->flag & IMA_USER_FRAME_IN_RANGE)) {
+        /* Frame is out of range, dont show. */
+        return NULL;
+      }
+      else {
+        camera_background_images_stereo_setup(scene, draw_ctx->v3d, image, iuser);
+      }
+
+      ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+      if (ibuf == NULL) {
+        return NULL;
+      }
+
+      tex = GPU_texture_from_blender(image, iuser, GL_TEXTURE_2D);
+      if (tex == NULL) {
+        return NULL;
+      }
+
+      aspect_x = bgpic->ima->aspx;
+      aspect_y = bgpic->ima->aspy;
+
+      width = ibuf->x;
+      height = ibuf->y;
+
+      BKE_image_release_ibuf(image, ibuf, NULL);
+      break;
+
+    case CAM_BGIMG_SOURCE_MOVIE:
+      if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) {
+        if (scene->camera) {
+          clip = BKE_object_movieclip_get(scene, scene->camera, true);
+        }
+      }
+      else {
+        clip = bgpic->clip;
+      }
+
+      if (clip == NULL) {
+        return NULL;
+      }
+
+      BKE_movieclip_user_set_frame(&bgpic->cuser, ctime);
+      tex = GPU_texture_from_movieclip(clip, &bgpic->cuser, GL_TEXTURE_2D);
+      if (tex == NULL) {
+        return NULL;
+      }
+
+      aspect_x = clip->aspx;
+      aspect_y = clip->aspy;
+
+      BKE_movieclip_get_size(clip, &bgpic->cuser, &width, &height);
+
+      /* Save for freeing. */
+      BLI_addtail(&pd->bg_movie_clips, BLI_genericNodeN(clip));
+      break;
+
+    default:
+      /* Unsupported type. */
+      return NULL;
+  }
+
+  *r_aspect = (width * aspect_x) / (height * aspect_y);
+  return tex;
+}
+
+static void OVERLAY_image_free_movieclips_textures(OVERLAY_Data *data)
+{
+  /* Free Movie clip textures after rendering */
+  LinkData *link;
+  while ((link = BLI_pophead(&data->stl->pd->bg_movie_clips))) {
+    MovieClip *clip = (MovieClip *)link->data;
+    GPU_free_texture_movieclip(clip);
+    MEM_freeN(link);
+  }
+}
+
+static void image_camera_background_matrix_get(const Camera *cam,
+                                               const CameraBGImage *bgpic,
+                                               const DRWContextState *draw_ctx,
+                                               const float image_aspect,
+                                               float rmat[4][4])
+{
+  float rotate[4][4], scale[4][4], translate[4][4];
+
+  axis_angle_to_mat4_single(rotate, 'Z', -bgpic->rotation);
+  unit_m4(scale);
+  unit_m4(translate);
+
+  /*  Normalized Object space camera frame corners. */
+  float cam_corners[4][3];
+  BKE_camera_view_frame(draw_ctx->scene, cam, cam_corners);
+  float cam_width = fabsf(cam_corners[0][0] - cam_corners[3][0]);
+  float cam_height = fabsf(cam_corners[0][1] - cam_corners[1][1]);
+  float cam_aspect = cam_width / cam_height;
+
+  if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
+    /* Crop. */
+    if (image_aspect > cam_aspect) {
+      scale[0][0] *= cam_height * image_aspect;
+      scale[1][1] *= cam_height;
+    }
+    else {
+      scale[0][0] *= cam_width;
+      scale[1][1] *= cam_width / image_aspect;
+    }
+  }
+  else if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
+    /* Fit. */
+    if (image_aspect > cam_aspect) {
+      scale[0][0] *= cam_width;
+      scale[1][1] *= cam_width / image_aspect;
+    }
+    else {
+      scale[0][0] *= cam_height * image_aspect;
+      scale[1][1] *= cam_height;
+    }
+  }
+  else {
+    /* Stretch. */
+    scale[0][0] *= cam_width;
+    scale[1][1] *= cam_height;
+  }
+
+  translate[3][0] = bgpic->offset[0];
+  translate[3][1] = bgpic->offset[1];
+  translate[3][2] = cam_corners[0][2];
+  /* These lines are for keeping 2.80 behavior and could be removed to keep 2.79 behavior. */
+  translate[3][0] *= min_ff(1.0f, cam_aspect);
+  translate[3][1] /= max_ff(1.0f, cam_aspect) * (image_aspect / cam_aspect);
+  /* quad is -1..1 so divide by 2. */
+  scale[0][0] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) ? -1.0 : 1.0);
+  scale[1][1] *= 0.5f * bgpic->scale * ((bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) ? -1.0 : 1.0);
+  /* Camera shift. (middle of cam_corners) */
+  translate[3][0] += (cam_corners[0][0] + cam_corners[2][0]) * 0.5f;
+  translate[3][1] += (cam_corners[0][1] + cam_corners[2][1]) * 0.5f;
+
+  mul_m4_series(rmat, translate, rotate, scale);
+}
+
+void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  OVERLAY_PassList *psl = vedata->psl;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  Camera *cam = ob->data;
+
+  const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, draw_ctx->rv3d);
+
+  if (!show_frame || DRW_state_is_select()) {
+    return;
+  }
+
+  float norm_obmat[4][4];
+  normalize_m4_m4(norm_obmat, ob->obmat);
+
+  for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+    if (bgpic->flag & CAM_BGIMG_FLAG_DISABLED) {
+      continue;
+    }
+
+    float aspect = 1.0;
+    bool use_alpha_premult;
+    float mat[4][4];
+
+    /* retrieve the image we want to show, continue to next when no image could be found */
+    GPUTexture *tex = image_camera_background_texture_get(
+        bgpic, draw_ctx, pd, &aspect, &use_alpha_premult);
+
+    if (tex) {
+      image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat);
+
+      mul_m4_m4m4(mat, norm_obmat, mat);
+      const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0;
+
+      /* When drawing background we do 2 passes.
+       * - One alpha over, which works where background is visible.
+       * - One alpha under, works under partially visible objects. (only in cycles)
+       * This approach is not ideal and should be revisited.
+       **/
+      for (int i = 0; i < (is_foreground ? 1 : 2); i++) {
+        DRWPass *pass = is_foreground ? psl->image_foreground_ps :
+                                        ((i == 0) ? psl->image_background_under_ps :
+                                                    psl->image_background_over_ps);
+        GPUShader *sh = OVERLAY_shader_image();
+        DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+        float color[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha};
+        DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
+        DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
+        DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true);
+        DRW_shgroup_uniform_bool_copy(grp, "imgLinear", !DRW_state_do_color_management());
+        DRW_shgroup_uniform_bool_copy(grp, "depthSet", true);
+        DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+        DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
+      }
+    }
+  }
+}
+
+void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  const RegionView3D *rv3d = draw_ctx->rv3d;
+  GPUTexture *tex = NULL;
+  Image *ima = ob->data;
+  float mat[4][4];
+
+  const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, rv3d);
+  const bool show_image = show_frame && BKE_object_empty_image_data_is_visible_in_view3d(ob, rv3d);
+  const bool use_alpha_blend = (ob->empty_image_flag & OB_EMPTY_IMAGE_USE_ALPHA_BLEND) != 0;
+  const bool use_alpha_premult = ima && (ima->alpha_mode == IMA_ALPHA_PREMUL);
+
+  if (!show_frame) {
+    return;
+  }
+
+  {
+    /* Calling 'BKE_image_get_size' may free the texture. Get the size from 'tex' instead,
+     * see: T59347 */
+    int size[2] = {0};
+    if (ima != NULL) {
+      tex = GPU_texture_from_blender(ima, ob->iuser, GL_TEXTURE_2D);
+      if (tex) {
+        size[0] = GPU_texture_orig_width(tex);
+        size[1] = GPU_texture_orig_height(tex);
+      }
+    }
+    CLAMP_MIN(size[0], 1);
+    CLAMP_MIN(size[1], 1);
+
+    float image_aspect[2];
+    overlay_image_calc_aspect(ob->data, size, image_aspect);
+
+    copy_m4_m4(mat, ob->obmat);
+    mul_v3_fl(mat[0], image_aspect[0] * 0.5f * ob->empty_drawsize);
+    mul_v3_fl(mat[1], image_aspect[1] * 0.5f * ob->empty_drawsize);
+    madd_v3_v3fl(mat[3], mat[0], ob->ima_ofs[0] * 2.0f + 1.0f);
+    madd_v3_v3fl(mat[3], mat[1], ob->ima_ofs[1] * 2.0f + 1.0f);
+  }
+
+  /* Use the actual depth if we are doing depth tests to determine the distance to the object */
+  char depth_mode = DRW_state_is_depth() ? OB_EMPTY_IMAGE_DEPTH_DEFAULT : ob->empty_image_depth;
+  DRWPass *pass = NULL;
+  switch (depth_mode) {
+    case OB_EMPTY_IMAGE_DEPTH_DEFAULT:
+      pass = (use_alpha_blend) ? psl->image_empties_blend_ps : psl->image_empties_ps;
+      break;
+    case OB_EMPTY_IMAGE_DEPTH_BACK:
+      pass = psl->image_empties_back_ps;
+      break;
+    case OB_EMPTY_IMAGE_DEPTH_FRONT:
+      pass = psl->image_empties_front_ps;
+      break;
+  }
+
+  if (show_frame) {
+    OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+    float *color;
+    DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+    OVERLAY_empty_shape(cb, mat, 1.0f, OB_EMPTY_IMAGE, color);
+  }
+
+  if (show_image && tex && ((ob->color[3] > 0.0f) || !use_alpha_blend)) {
+    GPUShader *sh = OVERLAY_shader_image();
+    DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+    DRW_shgroup_uniform_texture(grp, "imgTexture", tex);
+    DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", use_alpha_premult);
+    DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", use_alpha_blend);
+    DRW_shgroup_uniform_bool_copy(grp, "imgLinear", false);
+    DRW_shgroup_uniform_bool_copy(grp, "depthSet", depth_mode != OB_EMPTY_IMAGE_DEPTH_DEFAULT);
+    DRW_shgroup_uniform_vec4_copy(grp, "color", ob->color);
+    DRW_shgroup_call_obmat(grp, DRW_cache_quad_get(), mat);
+  }
+}
+
+void OVERLAY_image_cache_finish(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_pass_sort_shgroup_reverse(psl->image_background_under_ps);
+  DRW_pass_sort_shgroup_z(psl->image_empties_blend_ps);
+  DRW_pass_sort_shgroup_z(psl->image_empties_front_ps);
+  DRW_pass_sort_shgroup_z(psl->image_empties_back_ps);
+}
+
+void OVERLAY_image_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  DRW_view_set_active(pd->view_reference_images);
+
+  DRW_draw_pass(psl->image_background_over_ps);
+  DRW_draw_pass(psl->image_background_under_ps);
+  DRW_draw_pass(psl->image_empties_back_ps);
+
+  DRW_draw_pass(psl->image_empties_ps);
+  DRW_draw_pass(psl->image_empties_blend_ps);
+
+  DRW_view_set_active(pd->view_default);
+}
+
+void OVERLAY_image_in_front_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  DRW_view_set_active(pd->view_reference_images);
+
+  DRW_draw_pass(psl->image_empties_front_ps);
+  DRW_draw_pass(psl->image_foreground_ps);
+
+  DRW_view_set_active(pd->view_default);
+
+  OVERLAY_image_free_movieclips_textures(vedata);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_lattice.c b/source/blender/draw/engines/overlay/overlay_lattice.c
new file mode 100644 (file)
index 0000000..4e4081e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  struct GPUShader *sh;
+  DRWShadingGroup *grp;
+
+  {
+    DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+    DRW_PASS_CREATE(psl->edit_lattice_ps, state | pd->clipping_state);
+
+    sh = OVERLAY_shader_edit_lattice_wire();
+    pd->edit_lattice_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_lattice_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+
+    sh = OVERLAY_shader_edit_lattice_point();
+    pd->edit_lattice_points_grp = grp = DRW_shgroup_create(sh, psl->edit_lattice_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  }
+}
+
+void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  struct GPUBatch *geom;
+
+  geom = DRW_cache_lattice_wire_get(ob, true);
+  DRW_shgroup_call(pd->edit_lattice_wires_grp, geom, ob);
+
+  geom = DRW_cache_lattice_vert_overlay_get(ob);
+  DRW_shgroup_call(pd->edit_lattice_points_grp, geom, ob);
+}
+
+void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+
+  float *color;
+  DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+  struct GPUBatch *geom = DRW_cache_lattice_wire_get(ob, false);
+  OVERLAY_extra_wire(cb, geom, ob->obmat, color);
+}
+
+void OVERLAY_edit_lattice_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->edit_lattice_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_metaball.c b/source/blender/draw/engines/overlay/overlay_metaball.c
new file mode 100644 (file)
index 0000000..a634aed
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_meta_types.h"
+
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_mball.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_metaball_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
+
+#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
+
+  for (int i = 0; i < 2; i++) {
+    DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
+    DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+    DRW_PASS_CREATE(psl->metaball_ps[i], state | pd->clipping_state | infront_state);
+
+    /* Reuse armature shader as it's perfect to outline ellipsoids. */
+    struct GPUVertFormat *format = formats->instance_bone;
+    struct GPUShader *sh = OVERLAY_shader_armature_sphere(true);
+    DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->metaball_ps[i]);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    pd->mball.handle[i] = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+  }
+}
+
+static void metaball_instance_data_set(
+    BoneInstanceData *data, Object *ob, const float *pos, const float radius, const float color[4])
+{
+  /* Bone point radius is 0.05. Compensate for that. */
+  mul_v3_v3fl(data->mat[0], ob->obmat[0], radius / 0.05f);
+  mul_v3_v3fl(data->mat[1], ob->obmat[1], radius / 0.05f);
+  mul_v3_v3fl(data->mat[2], ob->obmat[2], radius / 0.05f);
+  mul_v3_m4v3(data->mat[3], ob->obmat, pos);
+  /* WATCH: Reminder, alpha is wiresize. */
+  OVERLAY_bone_instance_data_set_color(data, color);
+}
+
+void OVERLAY_edit_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  const bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+  const bool is_select = DRW_state_is_select();
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  MetaBall *mb = ob->data;
+
+  const float *color;
+  const float col_radius[4] = {0.63f, 0.19f, 0.19f, 1.0f};           /* 0x3030A0 */
+  const float col_radius_select[4] = {0.94f, 0.63f, 0.63f, 1.0f};    /* 0xA0A0F0 */
+  const float col_stiffness[4] = {0.19f, 0.63f, 0.19f, 1.0f};        /* 0x30A030 */
+  const float col_stiffness_select[4] = {0.63f, 0.94f, 0.63f, 1.0f}; /* 0xA0F0A0 */
+
+  int select_id = 0;
+  if (is_select) {
+    const Object *orig_object = DEG_get_original_object(ob);
+    select_id = orig_object->runtime.select_id;
+  }
+
+  LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
+    const bool is_selected = (ml->flag & SELECT) != 0;
+    const bool is_scale_radius = (ml->flag & MB_SCALE_RAD) != 0;
+    float stiffness_radius = ml->rad * atanf(ml->s) / (float)M_PI_2;
+    BoneInstanceData instdata;
+
+    if (is_select) {
+      DRW_select_load_id(select_id | MBALLSEL_RADIUS);
+    }
+    color = (is_selected && is_scale_radius) ? col_radius_select : col_radius;
+    metaball_instance_data_set(&instdata, ob, &ml->x, ml->rad, color);
+    DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+
+    if (is_select) {
+      DRW_select_load_id(select_id | MBALLSEL_STIFF);
+    }
+    color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness;
+    metaball_instance_data_set(&instdata, ob, &ml->x, stiffness_radius, color);
+    DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+
+    select_id += 0x10000;
+  }
+}
+
+void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  const bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  MetaBall *mb = ob->data;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+
+  float *color;
+  DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
+
+  LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
+    /* Draw radius only. */
+    BoneInstanceData instdata;
+    metaball_instance_data_set(&instdata, ob, &ml->x, ml->rad, color);
+    DRW_buffer_add_entry_struct(pd->mball.handle[do_in_front], &instdata);
+  }
+}
+
+void OVERLAY_metaball_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->metaball_ps[0]);
+}
+
+void OVERLAY_metaball_in_front_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->metaball_ps[1]);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c
new file mode 100644 (file)
index 0000000..349f17d
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_string.h"
+
+#include "DNA_armature_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "GPU_batch.h"
+
+#include "UI_resources.h"
+
+#include "draw_manager_text.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  DRWShadingGroup *grp;
+  GPUShader *sh;
+
+  DRWState state = DRW_STATE_WRITE_COLOR;
+  DRW_PASS_CREATE(psl->motion_paths_ps, state | pd->clipping_state);
+
+  sh = OVERLAY_shader_motion_path_line();
+  pd->motion_path_lines_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
+  DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+
+  sh = OVERLAY_shader_motion_path_vert();
+  pd->motion_path_points_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
+  DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+}
+
+/* Just convert the CPU cache to GPU cache. */
+/* T0D0(fclem) This should go into a draw_cache_impl_motionpath. */
+static GPUVertBuf *mpath_vbo_get(bMotionPath *mpath)
+{
+  if (!mpath->points_vbo) {
+    GPUVertFormat format = {0};
+    /* Match structure of bMotionPathVert. */
+    GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+    GPU_vertformat_attr_add(&format, "flag", GPU_COMP_I32, 1, GPU_FETCH_INT);
+    mpath->points_vbo = GPU_vertbuf_create_with_format(&format);
+    GPU_vertbuf_data_alloc(mpath->points_vbo, mpath->length);
+    /* meh... a useless memcpy. */
+    memcpy(mpath->points_vbo->data, mpath->points, sizeof(bMotionPathVert) * mpath->length);
+  }
+  return mpath->points_vbo;
+}
+
+static GPUBatch *mpath_batch_line_get(bMotionPath *mpath)
+{
+  if (!mpath->batch_line) {
+    mpath->batch_line = GPU_batch_create(GPU_PRIM_LINE_STRIP, mpath_vbo_get(mpath), NULL);
+  }
+  return mpath->batch_line;
+}
+
+static GPUBatch *mpath_batch_points_get(bMotionPath *mpath)
+{
+  if (!mpath->batch_points) {
+    mpath->batch_points = GPU_batch_create(GPU_PRIM_POINTS, mpath_vbo_get(mpath), NULL);
+  }
+  return mpath->batch_points;
+}
+
+static void motion_path_get_frame_range_to_draw(bAnimVizSettings *avs,
+                                                bMotionPath *mpath,
+                                                int current_frame,
+                                                int *r_start,
+                                                int *r_end,
+                                                int *r_step)
+{
+  int start, end;
+
+  if (avs->path_type == MOTIONPATH_TYPE_ACFRA) {
+    start = current_frame - avs->path_bc;
+    end = current_frame + avs->path_ac + 1;
+  }
+  else {
+    start = avs->path_sf;
+    end = avs->path_ef;
+  }
+
+  if (start > end) {
+    SWAP(int, start, end);
+  }
+
+  CLAMP(start, mpath->start_frame, mpath->end_frame);
+  CLAMP(end, mpath->start_frame, mpath->end_frame);
+
+  *r_start = start;
+  *r_end = end;
+  *r_step = max_ii(avs->path_step, 1);
+}
+
+static void motion_path_cache(OVERLAY_Data *vedata,
+                              Object *ob,
+                              bPoseChannel *pchan,
+                              bAnimVizSettings *avs,
+                              bMotionPath *mpath)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  struct DRWTextStore *dt = DRW_text_cache_ensure();
+  int txt_flag = DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_ASCII;
+  int cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
+  bool selected = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->base_flag & BASE_SELECTED);
+  bool show_keyframes = (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) != 0;
+  bool show_keyframes_no = (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) != 0;
+  bool show_frame_no = (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) != 0;
+  bool show_lines = (mpath->flag & MOTIONPATH_FLAG_LINES) != 0;
+  float no_custom_col[3] = {-1.0f, -1.0f, -1.0f};
+  float *color = (mpath->flag & MOTIONPATH_FLAG_CUSTOM) ? mpath->color : no_custom_col;
+
+  int sfra, efra, stepsize;
+  motion_path_get_frame_range_to_draw(avs, mpath, cfra, &sfra, &efra, &stepsize);
+
+  int len = efra - sfra;
+  if (len == 0) {
+    return;
+  }
+  int start_index = sfra - mpath->start_frame;
+
+  /* Draw curve-line of path. */
+  if (show_lines) {
+    int motion_path_settings[4] = {cfra, sfra, efra, mpath->start_frame};
+    DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_lines_grp);
+    DRW_shgroup_uniform_ivec4_copy(grp, "mpathLineSettings", motion_path_settings);
+    DRW_shgroup_uniform_int_copy(grp, "lineThickness", mpath->line_thickness);
+    DRW_shgroup_uniform_bool_copy(grp, "selected", selected);
+    DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
+    /* Only draw the required range. */
+    DRW_shgroup_call_range(grp, mpath_batch_line_get(mpath), start_index, len);
+  }
+
+  /* Draw points. */
+  {
+    int pt_size = max_ii(mpath->line_thickness - 1, 1);
+    int motion_path_settings[4] = {pt_size, cfra, mpath->start_frame, stepsize};
+    DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->motion_path_points_grp);
+    DRW_shgroup_uniform_ivec4_copy(grp, "mpathPointSettings", motion_path_settings);
+    DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes);
+    DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
+    /* Only draw the required range. */
+    DRW_shgroup_call_range(grp, mpath_batch_points_get(mpath), start_index, len);
+  }
+
+  /* Draw frame numbers at each framestep value */
+  if (show_frame_no || (show_keyframes_no && show_keyframes)) {
+    int i;
+    uchar col[4], col_kf[4];
+    UI_GetThemeColor3ubv(TH_TEXT_HI, col);
+    UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col_kf);
+    col[3] = col_kf[3] = 255;
+
+    bMotionPathVert *mpv = mpath->points + start_index;
+    for (i = 0; i < len; i += stepsize, mpv += stepsize) {
+      int frame = sfra + i;
+      char numstr[32];
+      size_t numstr_len;
+      bool is_keyframe = (mpv->flag & MOTIONPATH_VERT_KEY) != 0;
+
+      if ((show_keyframes && show_keyframes_no && is_keyframe) || (show_frame_no && (i == 0))) {
+        numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame);
+        DRW_text_cache_add(
+            dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, (is_keyframe) ? col_kf : col);
+      }
+      else if (show_frame_no) {
+        bMotionPathVert *mpvP = (mpv - stepsize);
+        bMotionPathVert *mpvN = (mpv + stepsize);
+        /* Only draw framenum if several consecutive highlighted points don't occur on same point.
+         */
+        if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) {
+          numstr_len = BLI_snprintf(numstr, sizeof(numstr), " %d", frame);
+          DRW_text_cache_add(dt, mpv->co, numstr, numstr_len, 0, 0, txt_flag, col);
+        }
+      }
+    }
+  }
+}
+
+void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+
+  if (ob->type == OB_ARMATURE) {
+    if (OVERLAY_armature_is_pose_mode(ob, draw_ctx)) {
+      for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+        if (pchan->mpath) {
+          motion_path_cache(vedata, ob, pchan, &ob->pose->avs, pchan->mpath);
+        }
+      }
+    }
+  }
+
+  if (ob->mpath) {
+    motion_path_cache(vedata, ob, NULL, &ob->avs, ob->mpath);
+  }
+}
+
+void OVERLAY_motion_path_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->motion_paths_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
new file mode 100644 (file)
index 0000000..a0c7f57
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_lightprobe_types.h"
+
+#include "UI_resources.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_outline_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+  OVERLAY_TextureList *txl = vedata->txl;
+
+  if (DRW_state_is_fbo()) {
+    /* TODO only alloc if needed. */
+    /* XXX TODO GPU_R16UI can overflow, it would cause no harm
+     * (only bad colored or missing outlines) but we should
+     * use 32bits only if the scene have that many objects */
+    DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0);
+    DRW_texture_ensure_fullscreen_2d(&txl->outlines_id_tx, GPU_R16UI, 0);
+    GPU_framebuffer_ensure_config(
+        &fbl->outlines_prepass_fb,
+        {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
+
+    for (int i = 0; i < 2; i++) {
+      DRW_texture_ensure_fullscreen_2d(&txl->outlines_color_tx[i], GPU_RGBA8, DRW_TEX_FILTER);
+      GPU_framebuffer_ensure_config(
+          &fbl->outlines_process_fb[i],
+          {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->outlines_color_tx[i])});
+    }
+  }
+}
+
+static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
+{
+  if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
+    switch (theme_id) {
+      case TH_ACTIVE:
+      case TH_SELECT:
+        return 2;
+      case TH_TRANSFORM:
+        return 0;
+      default:
+        return -1;
+    }
+  }
+
+  switch (theme_id) {
+    case TH_ACTIVE:
+      return 3;
+    case TH_SELECT:
+      return 1;
+    case TH_TRANSFORM:
+      return 0;
+    default:
+      return -1;
+  }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OVERLAY_PrivateData *pd,
+                                                            int theme_id,
+                                                            const int base_flag)
+{
+  int outline_id = shgroup_theme_id_to_outline_id(theme_id, base_flag);
+  switch (outline_id) {
+    case 3: /* TH_ACTIVE */
+      return pd->outlines_active_grp;
+    case 2: /* Duplis */
+      return pd->outlines_select_dupli_grp;
+    case 1: /* TH_SELECT */
+      return pd->outlines_select_grp;
+    case 0: /* TH_TRANSFORM */
+      return pd->outlines_transform_grp;
+    default:
+      return NULL;
+  }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OVERLAY_PrivateData *pd,
+                                                                  int theme_id,
+                                                                  const int base_flag)
+{
+  int outline_id = shgroup_theme_id_to_outline_id(theme_id, base_flag);
+  switch (outline_id) {
+    case 3: /* TH_ACTIVE */
+      return pd->outlines_probe_active_grp;
+    case 2: /* Duplis */
+      return pd->outlines_probe_select_dupli_grp;
+    case 1: /* TH_SELECT */
+      return pd->outlines_probe_select_grp;
+    case 0: /* TH_TRANSFORM */
+      return pd->outlines_probe_transform_grp;
+    default:
+      return NULL;
+  }
+}
+
+static DRWShadingGroup *outline_shgroup(DRWPass *pass, int outline_id, GPUShader *sh)
+{
+  DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+  DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+  return grp;
+}
+
+void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_TextureList *txl = vedata->txl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+  DRWShadingGroup *grp = NULL;
+
+  const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
+  const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
+  const bool do_large_expand = ((U.pixelsize > 1.0) && (outline_width > 2.0f)) ||
+                               (outline_width > 4.0f);
+  {
+    DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+    DRW_PASS_CREATE(psl->outlines_prepass_ps, state | pd->clipping_state);
+
+    GPUShader *sh_grid = OVERLAY_shader_outline_prepass_grid();
+    GPUShader *sh_geom = OVERLAY_shader_outline_prepass(pd->xray_enabled_and_not_wire);
+    GPUShader *sh = OVERLAY_shader_outline_prepass(false);
+
+    pd->outlines_transform_grp = outline_shgroup(psl->outlines_prepass_ps, 0, sh_geom);
+    pd->outlines_select_grp = outline_shgroup(psl->outlines_prepass_ps, 1, sh_geom);
+    pd->outlines_select_dupli_grp = outline_shgroup(psl->outlines_prepass_ps, 2, sh_geom);
+    pd->outlines_active_grp = outline_shgroup(psl->outlines_prepass_ps, 3, sh_geom);
+
+    pd->outlines_probe_transform_grp = outline_shgroup(psl->outlines_prepass_ps, 0, sh);
+    pd->outlines_probe_select_grp = outline_shgroup(psl->outlines_prepass_ps, 1, sh);
+    pd->outlines_probe_select_dupli_grp = outline_shgroup(psl->outlines_prepass_ps, 2, sh);
+    pd->outlines_probe_active_grp = outline_shgroup(psl->outlines_prepass_ps, 3, sh);
+
+    pd->outlines_probe_grid_grp = grp = DRW_shgroup_create(sh_grid, psl->outlines_prepass_ps);
+    DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+  }
+
+  /* outlines_prepass_ps is still needed for selection of probes. */
+  if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) {
+    return;
+  }
+
+  {
+    DRW_PASS_CREATE(psl->outlines_detect_ps, DRW_STATE_WRITE_COLOR);
+    DRW_PASS_CREATE(psl->outlines_expand_ps, DRW_STATE_WRITE_COLOR);
+    DRW_PASS_CREATE(psl->outlines_bleed_ps, DRW_STATE_WRITE_COLOR);
+    DRW_PASS_CREATE(psl->outlines_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
+
+    GPUShader *sh = OVERLAY_shader_outline_detect(pd->xray_enabled_and_not_wire);
+
+    grp = DRW_shgroup_create(sh, psl->outlines_detect_ps);
+    /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
+    DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
+    DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
+    DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
+    DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+    if (do_outline_expand) {
+      sh = OVERLAY_shader_outline_expand(do_large_expand);
+      grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
+      DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
+      DRW_shgroup_uniform_bool_copy(grp, "doExpand", true);
+      DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+      sh = OVERLAY_shader_outline_expand(false);
+      grp = DRW_shgroup_create(sh, psl->outlines_bleed_ps);
+      DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[1]);
+      DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
+      DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+    }
+    else {
+      sh = OVERLAY_shader_outline_expand(false);
+      grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
+      DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
+      DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
+      DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+    }
+
+    GPUTexture **outline_tx = &txl->outlines_color_tx[do_outline_expand ? 0 : 1];
+    sh = OVERLAY_shader_outline_resolve();
+
+    grp = DRW_shgroup_create(sh, psl->outlines_resolve_ps);
+    DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx);
+    DRW_shgroup_uniform_vec2_copy(grp, "rcpDimensions", DRW_viewport_invert_size_get());
+    DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+  }
+}
+
+static void outline_lightprobe(OVERLAY_PrivateData *pd, Object *ob, ViewLayer *view_layer)
+{
+  DRWShadingGroup *grp;
+  LightProbe *prb = (LightProbe *)ob->data;
+  int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+
+  if (prb->type == LIGHTPROBE_TYPE_GRID) {
+    float corner[3];
+    float increment[3][3];
+    /* Update transforms */
+    float cell_dim[3], half_cell_dim[3];
+    cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
+    cell_dim[1] = 2.0f / (float)(prb->grid_resolution_y);
+    cell_dim[2] = 2.0f / (float)(prb->grid_resolution_z);
+
+    mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
+
+    /* First cell. */
+    copy_v3_fl(corner, -1.0f);
+    add_v3_v3(corner, half_cell_dim);
+    mul_m4_v3(ob->obmat, corner);
+
+    /* Opposite neighbor cell. */
+    copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
+    copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
+    copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
+
+    for (int i = 0; i < 3; i++) {
+      add_v3_v3(increment[i], half_cell_dim);
+      add_v3_fl(increment[i], -1.0f);
+      mul_m4_v3(ob->obmat, increment[i]);
+      sub_v3_v3(increment[i], corner);
+    }
+
+    int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
+    uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+    grp = DRW_shgroup_create_sub(pd->outlines_probe_grid_grp);
+    DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+    DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
+    DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
+    DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
+    DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
+    DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
+    DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
+  }
+  else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+    grp = shgroup_theme_id_to_probe_outline_or_null(pd, theme_id, ob->base_flag);
+    DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
+  }
+}
+
+void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
+                                    Object *ob,
+                                    OVERLAY_DupliData *dupli,
+                                    bool init_dupli)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  struct GPUBatch *geom;
+  DRWShadingGroup *shgroup = NULL;
+
+  if (ob->type == OB_LIGHTPROBE) {
+    outline_lightprobe(pd, ob, draw_ctx->view_layer);
+    return;
+  }
+
+  if (dupli && !init_dupli) {
+    geom = dupli->outline_geom;
+    shgroup = dupli->outline_shgrp;
+  }
+  else {
+    /* This fixes only the biggest case which is a plane in ortho view. */
+    int flat_axis = 0;
+    bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
+                                            DRW_object_is_flat(ob, &flat_axis) &&
+                                            DRW_object_axis_orthogonal_to_view(ob, flat_axis));
+
+    if (pd->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) {
+      int theme_id = DRW_object_wire_theme_get(ob, draw_ctx->view_layer, NULL);
+      shgroup = shgroup_theme_id_to_outline_or_null(pd, theme_id, ob->base_flag);
+    }
+  }
+
+  if (shgroup && geom) {
+    DRW_shgroup_call(shgroup, geom, ob);
+  }
+
+  if (init_dupli) {
+    dupli->outline_shgrp = shgroup;
+    dupli->outline_geom = geom;
+  }
+}
+
+void OVERLAY_outline_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_FramebufferList *fbl = vedata->fbl;
+  OVERLAY_PassList *psl = vedata->psl;
+  float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+  bool do_outlines = psl->outlines_prepass_ps != NULL &&
+                     !DRW_pass_is_empty(psl->outlines_prepass_ps);
+
+  if (DRW_state_is_fbo() && do_outlines) {
+    DRW_stats_group_start("Outlines");
+
+    /* Render filled polygon on a separate framebuffer */
+    GPU_framebuffer_bind(fbl->outlines_prepass_fb);
+    GPU_framebuffer_clear_color_depth(fbl->outlines_prepass_fb, clearcol, 1.0f);
+    DRW_draw_pass(psl->outlines_prepass_ps);
+
+    /* Search outline pixels */
+    GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
+    DRW_draw_pass(psl->outlines_detect_ps);
+
+    /* Expand outline to form a 3px wide line */
+    GPU_framebuffer_bind(fbl->outlines_process_fb[1]);
+    DRW_draw_pass(psl->outlines_expand_ps);
+
+    /* Bleed color so the AA can do it's stuff */
+    GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
+    DRW_draw_pass(psl->outlines_bleed_ps);
+
+    /* restore main framebuffer */
+    GPU_framebuffer_bind(fbl->overlay_default_fb);
+    DRW_draw_pass(psl->outlines_resolve_ps);
+
+    DRW_stats_group_end();
+  }
+  else if (DRW_state_is_select()) {
+    /* Render probes spheres/planes so we can select them. */
+    DRW_draw_pass(psl->outlines_prepass_ps);
+  }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c
new file mode 100644 (file)
index 0000000..4e73770
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_mesh_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
+{
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  struct GPUShader *sh;
+  DRWShadingGroup *grp;
+  DRWState state;
+
+  const bool use_alpha_blending = (draw_ctx->v3d->shading.type == OB_WIRE);
+  const bool draw_contours = (pd->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0;
+  float opacity = 0.0f;
+
+  switch (pd->ctx_mode) {
+    case CTX_MODE_POSE:
+    case CTX_MODE_PAINT_WEIGHT: {
+      opacity = pd->overlay.weight_paint_mode_opacity;
+      if (opacity > 0.0f) {
+        state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
+        state |= use_alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL;
+        DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+        sh = OVERLAY_shader_paint_weight();
+        pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+        DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+        DRW_shgroup_uniform_bool_copy(grp, "drawContours", draw_contours);
+        DRW_shgroup_uniform_bool_copy(grp, "useAlphaBlend", use_alpha_blending);
+        DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+        DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp);
+      }
+      break;
+    }
+    case CTX_MODE_PAINT_VERTEX: {
+      opacity = pd->overlay.vertex_paint_mode_opacity;
+      if (opacity > 0.0f) {
+        state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
+        state |= use_alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL;
+        DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+        sh = OVERLAY_shader_paint_vertcol();
+        pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+        DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+        DRW_shgroup_uniform_bool_copy(grp, "useAlphaBlend", use_alpha_blending);
+        DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+      }
+      break;
+    }
+    case CTX_MODE_PAINT_TEXTURE: {
+      const ImagePaintSettings *imapaint = &draw_ctx->scene->toolsettings->imapaint;
+      const bool mask_enabled = imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL &&
+                                imapaint->stencil != NULL;
+
+      opacity = mask_enabled ? pd->overlay.texture_paint_mode_opacity : 0.0f;
+      if (opacity > 0.0f) {
+        state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+        DRW_PASS_CREATE(psl->paint_color_ps, state | pd->clipping_state);
+
+        GPUTexture *tex = GPU_texture_from_blender(imapaint->stencil, NULL, GL_TEXTURE_2D);
+
+        const bool mask_premult = (imapaint->stencil->alpha_mode == IMA_ALPHA_PREMUL);
+        const bool mask_inverted = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0;
+        sh = OVERLAY_shader_paint_texture();
+        pd->paint_surf_grp = grp = DRW_shgroup_create(sh, psl->paint_color_ps);
+        DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+        DRW_shgroup_uniform_float_copy(grp, "opacity", opacity);
+        DRW_shgroup_uniform_bool_copy(grp, "maskPremult", mask_premult);
+        DRW_shgroup_uniform_vec3_copy(grp, "maskColor", imapaint->stencil_col);
+        DRW_shgroup_uniform_bool_copy(grp, "maskInvertStencil", mask_inverted);
+        DRW_shgroup_uniform_texture(grp, "maskImage", tex);
+      }
+      break;
+    }
+    default:
+      BLI_assert(0);
+      break;
+  }
+
+  if (opacity <= 0.0f) {
+    psl->paint_color_ps = NULL;
+    pd->paint_surf_grp = NULL;
+  }
+
+  {
+    state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+    DRW_PASS_CREATE(psl->paint_overlay_ps, state | pd->clipping_state);
+    sh = OVERLAY_shader_paint_face();
+    pd->paint_face_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+    DRW_shgroup_uniform_vec4_copy(grp, "color", (float[4]){1.0f, 1.0f, 1.0f, 0.2f});
+    DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+    sh = OVERLAY_shader_paint_wire();
+    pd->paint_wire_selected_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_bool_copy(grp, "useSelect", true);
+    DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+    pd->paint_wire_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+    DRW_shgroup_uniform_bool_copy(grp, "useSelect", false);
+    DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+
+    sh = OVERLAY_shader_paint_point();
+    pd->paint_point_grp = grp = DRW_shgroup_create(sh, psl->paint_overlay_ps);
+    DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  }
+}
+
+void OVERLAY_paint_texture_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  struct GPUBatch *geom = NULL;
+
+  const Mesh *me_orig = DEG_get_original_object(ob)->data;
+  const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+
+  if (pd->paint_surf_grp) {
+    geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
+    DRW_shgroup_call(pd->paint_surf_grp, geom, ob);
+  }
+
+  if (use_face_sel) {
+    geom = DRW_cache_mesh_surface_get(ob);
+    DRW_shgroup_call(pd->paint_face_grp, geom, ob);
+  }
+}
+
+void OVERLAY_paint_vertex_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  struct GPUBatch *geom = NULL;
+
+  const Mesh *me = ob->data;
+  const Mesh *me_orig = DEG_get_original_object(ob)->data;
+  const bool use_wire = (pd->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
+  const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+  const bool use_vert_sel = (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+
+  if (pd->paint_surf_grp) {
+    if (ob->mode == OB_MODE_VERTEX_PAINT) {
+      if (me->mloopcol == NULL) {
+        return;
+      }
+      geom = DRW_cache_mesh_surface_vertpaint_get(ob);
+    }
+    else {
+      geom = DRW_cache_mesh_surface_weights_get(ob);
+    }
+    DRW_shgroup_call(pd->paint_surf_grp, geom, ob);
+  }
+
+  if (use_face_sel || use_wire) {
+    geom = DRW_cache_mesh_surface_edges_get(ob);
+    DRW_shgroup_call(use_face_sel ? pd->paint_wire_selected_grp : pd->paint_wire_grp, geom, ob);
+  }
+
+  if (use_face_sel) {
+    geom = DRW_cache_mesh_surface_get(ob);
+    DRW_shgroup_call(pd->paint_face_grp, geom, ob);
+  }
+
+  if (use_vert_sel) {
+    geom = DRW_cache_mesh_all_verts_get(ob);
+    DRW_shgroup_call(pd->paint_point_grp, geom, ob);
+  }
+}
+
+void OVERLAY_paint_weight_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_paint_vertex_cache_populate(vedata, ob);
+}
+
+void OVERLAY_paint_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  if (psl->paint_color_ps) {
+    DRW_view_set_active(NULL);
+    DRW_draw_pass(psl->paint_color_ps);
+  }
+  DRW_draw_pass(psl->paint_overlay_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_particle.c b/source/blender/draw/engines/overlay/overlay_particle.c
new file mode 100644 (file)
index 0000000..f7b6fa7
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_particle_types.h"
+
+#include "BKE_pointcache.h"
+
+#include "ED_particle.h"
+
+#include "overlay_private.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Particles
+ * \{ */
+
+void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+  GPUShader *sh;
+  DRWShadingGroup *grp;
+
+  pd->edit_particle.use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+  pd->edit_particle.select_mode = pset->selectmode;
+
+  DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+  DRW_PASS_CREATE(psl->edit_particle_ps, state | pd->clipping_state);
+
+  sh = OVERLAY_shader_edit_particle_strand();
+  pd->edit_particle_strand_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
+  DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+  DRW_shgroup_uniform_bool_copy(grp, "useWeight", pd->edit_particle.use_weight);
+  DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+
+  sh = OVERLAY_shader_edit_particle_point();
+  pd->edit_particle_point_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
+  DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+}
+
+void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
+
+  /* Usually the edit structure is created by Particle Edit Mode Toggle
+   * operator, but sometimes it's invoked after tagging hair as outdated
+   * (for example, when toggling edit mode). That makes it impossible to
+   * create edit structure for until after next dependency graph evaluation.
+   *
+   * Ideally, the edit structure will be created here already via some
+   * dependency graph callback or so, but currently trying to make it nicer
+   * only causes bad level calls and breaks design from the past.
+   */
+  Object *ob_orig = DEG_get_original_object(ob);
+  PTCacheEdit *edit = PE_create_current(draw_ctx->depsgraph, scene_orig, ob_orig);
+  if (edit == NULL) {
+    /* Happens when trying to edit particles in EMITTER mode without
+     * having them cached.
+     */
+    return;
+  }
+  /* NOTE: We need to pass evaluated particle system, which we need
+   * to find first.
+   */
+  ParticleSystem *psys = ob->particlesystem.first;
+  LISTBASE_FOREACH (ParticleSystem *, psys_orig, &ob_orig->particlesystem) {
+    if (PE_get_current_from_psys(psys_orig) == edit) {
+      break;
+    }
+    psys = psys->next;
+  }
+  if (psys == NULL) {
+    printf("Error getting evaluated particle system for edit.\n");
+    return;
+  }
+
+  struct GPUBatch *geom;
+  {
+    geom = DRW_cache_particles_get_edit_strands(ob, psys, edit, pd->edit_particle.use_weight);
+    DRW_shgroup_call(pd->edit_particle_strand_grp, geom, NULL);
+  }
+
+  if (pd->edit_particle.select_mode == SCE_SELECT_POINT) {
+    geom = DRW_cache_particles_get_edit_inner_points(ob, psys, edit);
+    DRW_shgroup_call(pd->edit_particle_point_grp, geom, NULL);
+  }
+
+  if (ELEM(pd->edit_particle.select_mode, SCE_SELECT_POINT, SCE_SELECT_END)) {
+    geom = DRW_cache_particles_get_edit_tip_points(ob, psys, edit);
+    DRW_shgroup_call(pd->edit_particle_point_grp, geom, NULL);
+  }
+}
+
+void OVERLAY_edit_particle_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->edit_particle_ps);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Particles
+ * \{ */
+
+void OVERLAY_particle_cache_init(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+  GPUShader *sh;
+  DRWShadingGroup *grp;
+
+  pd->edit_particle.use_weight = (pset->brushtype == PE_BRUSH_WEIGHT);
+  pd->edit_particle.select_mode = pset->selectmode;
+
+  DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+  DRW_PASS_CREATE(psl->particle_ps, state | pd->clipping_state);
+
+  sh = OVERLAY_shader_particle_dot();
+  pd->particle_dots_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
+  DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+  DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+
+  sh = OVERLAY_shader_particle_shape();
+  pd->particle_shapes_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
+  DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+  DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+}
+
+void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+  OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+  LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
+    if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+      continue;
+    }
+
+    ParticleSettings *part = psys->part;
+    int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+    if (part->type == PART_HAIR) {
+      /* Hairs should have been rendered by the render engine.*/
+      continue;
+    }
+
+    if (!ELEM(draw_as, PART_DRAW_NOT, PART_DRAW_OB, PART_DRAW_GR)) {
+      struct GPUBatch *geom = DRW_cache_particles_get_dots(ob, psys);
+      struct GPUBatch *shape = NULL;
+      DRWShadingGroup *grp;
+
+      /* TODO(fclem) Here would be a good place for preemptive culling. */
+
+      /* fclem: Is color even usefull in our modern context? */
+      Material *ma = give_current_material(ob, part->omat);
+      float color[4] = {0.6f, 0.6f, 0.6f, part->draw_size};
+      if (ma != NULL) {
+        copy_v3_v3(color, &ma->r);
+      }
+
+      switch (draw_as) {
+        default:
+        case PART_DRAW_DOT:
+          grp = DRW_shgroup_create_sub(pd->particle_dots_grp);
+          DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+          DRW_shgroup_call(grp, geom, NULL);
+          break;
+        case PART_DRAW_AXIS:
+        case PART_DRAW_CIRC:
+        case PART_DRAW_CROSS:
+          grp = DRW_shgroup_create_sub(pd->particle_shapes_grp);
+          DRW_shgroup_uniform_vec4_copy(grp, "color", color);
+          shape = DRW_cache_particles_get_prim(draw_as);
+          DRW_shgroup_call_instances_with_attribs(grp, NULL, shape, geom);
+          break;
+      }
+    }
+  }
+}
+
+void OVERLAY_particle_draw(OVERLAY_Data *vedata)
+{
+  OVERLAY_PassList *psl = vedata->psl;
+
+  DRW_draw_pass(psl->particle_ps);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
new file mode 100644 (file)
index 0000000..6b030b6
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __OVERLAY_PRIVATE_H__
+#define __OVERLAY_PRIVATE_H__
+
+#ifdef __APPLE__
+#  define USE_GEOM_SHADER_WORKAROUND 1
+#else
+#  define USE_GEOM_SHADER_WORKAROUND 0
+#endif
+
+typedef struct OVERLAY_FramebufferList {
+  struct GPUFrameBuffer *overlay_default_fb;
+  struct GPUFrameBuffer *overlay_line_fb;
+  struct GPUFrameBuffer *overlay_color_only_fb;
+  struct GPUFrameBuffer *overlay_in_front_fb;
+  struct GPUFrameBuffer *outlines_prepass_fb;
+  struct GPUFrameBuffer *outlines_process_fb[2];
+} OVERLAY_FramebufferList;
+
+typedef struct OVERLAY_TextureList {
+  struct GPUTexture *temp_depth_tx;
+  struct GPUTexture *dummy_depth_tx;
+  struct GPUTexture *outlines_id_tx;
+  struct GPUTexture *outlines_color_tx[2];
+  struct GPUTexture *overlay_color_tx;
+  struct GPUTexture *overlay_color_history_tx;
+  struct GPUTexture *overlay_line_tx;
+  struct GPUTexture *edit_mesh_occlude_wire_tx;
+} OVERLAY_TextureList;
+
+#define NOT_IN_FRONT 0
+#define IN_FRONT 1
+
+typedef struct OVERLAY_PassList {
+  DRWPass *antialiasing_ps;
+  DRWPass *armature_ps[2];
+  DRWPass *armature_bone_select_ps;
+  DRWPass *armature_transp_ps;
+  DRWPass *edit_curve_wire_ps[2];
+  DRWPass *edit_curve_handle_ps;
+  DRWPass *edit_lattice_ps;
+  DRWPass *edit_mesh_depth_ps[2];
+  DRWPass *edit_mesh_verts_ps[2];
+  DRWPass *edit_mesh_edges_ps[2];
+  DRWPass *edit_mesh_faces_ps[2];
+  DRWPass *edit_mesh_faces_cage_ps[2];
+  DRWPass *edit_mesh_analysis_ps;
+  DRWPass *edit_mesh_normals_ps;
+  DRWPass *edit_mesh_weight_ps;
+  DRWPass *edit_particle_ps;
+  DRWPass *edit_text_overlay_ps;
+  DRWPass *edit_text_wire_ps[2];
+  DRWPass *extra_ps[2];
+  DRWPass *extra_blend_ps;
+  DRWPass *extra_centers_ps;
+  DRWPass *facing_ps;
+  DRWPass *grid_ps;
+  DRWPass *image_background_under_ps;
+  DRWPass *image_background_over_ps;
+  DRWPass *image_empties_ps;
+  DRWPass *image_empties_back_ps;
+  DRWPass *image_empties_blend_ps;
+  DRWPass *image_empties_front_ps;
+  DRWPass *image_foreground_ps;
+  DRWPass *metaball_ps[2];
+  DRWPass *motion_paths_ps;
+  DRWPass *outlines_prepass_ps;
+  DRWPass *outlines_detect_ps;
+  DRWPass *outlines_expand_ps;
+  DRWPass *outlines_bleed_ps;
+  DRWPass *outlines_resolve_ps;
+  DRWPass *paint_color_ps;
+  DRWPass *paint_overlay_ps;
+  DRWPass *particle_ps;
+  DRWPass *sculpt_mask_ps;
+  DRWPass *wireframe_ps;
+  DRWPass *wireframe_xray_ps;
+} OVERLAY_PassList;
+
+/* Data used by GLSL shader. To be used as UBO. */
+typedef struct OVERLAY_ShadingData {
+  /** Grid */
+  float grid_axes[3], grid_distance;
+  float zplane_axes[3], grid_mesh_size;
+  float grid_steps[8];
+  float inv_viewport_size[2];
+  float grid_line_size;
+  int grid_flag;
+  int zpos_flag;
+  int zneg_flag;
+  /** Wireframe */
+  float wire_step_param;
+  /** Edit Curve */
+  float edit_curve_normal_length;
+  /** Edit Mesh */
+  int data_mask[4];
+} OVERLAY_ShadingData;
+
+typedef struct OVERLAY_ExtraCallBuffers {
+  DRWCallBuffer *camera_frame;
+  DRWCallBuffer *camera_tria[2];
+  DRWCallBuffer *camera_distances;
+  DRWCallBuffer *camera_volume;
+  DRWCallBuffer *camera_volume_frame;
+
+  DRWCallBuffer *center_active;
+  DRWCallBuffer *center_selected;
+  DRWCallBuffer *center_deselected;
+  DRWCallBuffer *center_selected_lib;
+  DRWCallBuffer *center_deselected_lib;
+
+  DRWCallBuffer *empty_axes;
+  DRWCallBuffer *empty_capsule_body;
+  DRWCallBuffer *empty_capsule_cap;
+  DRWCallBuffer *empty_circle;
+  DRWCallBuffer *empty_cone;
+  DRWCallBuffer *empty_cube;
+  DRWCallBuffer *empty_cylinder;
+  DRWCallBuffer *empty_image_frame;
+  DRWCallBuffer *empty_plain_axes;
+  DRWCallBuffer *empty_single_arrow;
+  DRWCallBuffer *empty_sphere;
+  DRWCallBuffer *empty_sphere_solid;
+
+  DRWCallBuffer *extra_dashed_lines;
+  DRWCallBuffer *extra_lines;
+
+  DRWCallBuffer *field_curve;
+  DRWCallBuffer *field_force;
+  DRWCallBuffer *field_vortex;
+  DRWCallBuffer *field_wind;
+  DRWCallBuffer *field_cone_limit;
+  DRWCallBuffer *field_sphere_limit;
+  DRWCallBuffer *field_tube_limit;
+
+  DRWCallBuffer *groundline;
+
+  DRWCallBuffer *light_point;
+  DRWCallBuffer *light_sun;
+  DRWCallBuffer *light_spot;
+  DRWCallBuffer *light_spot_cone_back;
+  DRWCallBuffer *light_spot_cone_front;
+  DRWCallBuffer *light_area[2];
+
+  DRWCallBuffer *origin_xform;
+
+  DRWCallBuffer *probe_planar;
+  DRWCallBuffer *probe_cube;
+  DRWCallBuffer *probe_grid;
+
+  DRWCallBuffer *speaker;
+
+  DRWShadingGroup *extra_wire;
+  DRWShadingGroup *extra_loose_points;
+} OVERLAY_ExtraCallBuffers;
+
+typedef struct OVERLAY_ArmatureCallBuffers {
+  DRWCallBuffer *box_outline;
+  DRWCallBuffer *box_solid;
+
+  DRWCallBuffer *dof_lines;
+  DRWCallBuffer *dof_sphere;
+
+  DRWCallBuffer *envelope_distance;
+  DRWCallBuffer *envelope_outline;
+  DRWCallBuffer *envelope_solid;
+
+  DRWCallBuffer *octa_outline;
+  DRWCallBuffer *octa_solid;
+
+  DRWCallBuffer *point_outline;
+  DRWCallBuffer *point_solid;
+
+  DRWCallBuffer *stick;
+
+  DRWCallBuffer *wire;
+
+  DRWShadingGroup *custom_solid;
+  DRWShadingGroup *custom_outline;
+  GHash *custom_shapes_ghash;
+} OVERLAY_ArmatureCallBuffers;
+
+typedef struct OVERLAY_PrivateData {
+  DRWShadingGroup *armature_bone_select_act_grp;
+  DRWShadingGroup *armature_bone_select_grp;
+  DRWShadingGroup *edit_curve_normal_grp[2];
+  DRWShadingGroup *edit_curve_wire_grp[2];
+  DRWShadingGroup *edit_curve_handle_grp;
+  DRWShadingGroup *edit_curve_points_grp;
+  DRWShadingGroup *edit_lattice_points_grp;
+  DRWShadingGroup *edit_lattice_wires_grp;
+  DRWShadingGroup *edit_mesh_depth_grp[2];
+  DRWShadingGroup *edit_mesh_faces_grp[2];
+  DRWShadingGroup *edit_mesh_faces_cage_grp[2];
+  DRWShadingGroup *edit_mesh_verts_grp[2];
+  DRWShadingGroup *edit_mesh_edges_grp[2];
+  DRWShadingGroup *edit_mesh_facedots_grp[2];
+  DRWShadingGroup *edit_mesh_skin_roots_grp[2];
+  DRWShadingGroup *edit_mesh_normals_grp;
+  DRWShadingGroup *edit_mesh_analysis_grp;
+  DRWShadingGroup *edit_mesh_weight_grp;
+  DRWShadingGroup *edit_particle_strand_grp;
+  DRWShadingGroup *edit_particle_point_grp;
+  DRWShadingGroup *edit_text_overlay_grp;
+  DRWShadingGroup *edit_text_wire_grp[2];
+  DRWShadingGroup *facing_grp;
+  DRWShadingGroup *motion_path_lines_grp;
+  DRWShadingGroup *motion_path_points_grp;
+  DRWShadingGroup *outlines_active_grp;
+  DRWShadingGroup *outlines_select_grp;
+  DRWShadingGroup *outlines_select_dupli_grp;
+  DRWShadingGroup *outlines_transform_grp;
+  DRWShadingGroup *outlines_probe_transform_grp;
+  DRWShadingGroup *outlines_probe_select_grp;
+  DRWShadingGroup *outlines_probe_select_dupli_grp;
+  DRWShadingGroup *outlines_probe_active_grp;
+  DRWShadingGroup *outlines_probe_grid_grp;
+  DRWShadingGroup *paint_surf_grp;
+  DRWShadingGroup *paint_wire_grp;
+  DRWShadingGroup *paint_wire_selected_grp;
+  DRWShadingGroup *paint_point_grp;
+  DRWShadingGroup *paint_face_grp;
+  DRWShadingGroup *particle_dots_grp;
+  DRWShadingGroup *particle_shapes_grp;
+  DRWShadingGroup *sculpt_mask_grp;
+  DRWShadingGroup *wires_grp[2][2];     /* With and without coloring. */
+  DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
+  DRWShadingGroup *wires_sculpt_grp[2];
+
+  DRWView *view_default;
+  DRWView *view_wires;
+  DRWView *view_edit_faces;
+  DRWView *view_edit_faces_cage;
+  DRWView *view_edit_edges;
+  DRWView *view_edit_verts;
+  DRWView *view_reference_images;
+
+  /** TODO get rid of this. */
+  ListBase smoke_domains;
+  ListBase bg_movie_clips;
+
+  /** Two instances for in_front option and without. */
+  OVERLAY_ExtraCallBuffers extra_call_buffers[2];
+
+  OVERLAY_ArmatureCallBuffers armature_call_buffers[2];
+
+  View3DOverlay overlay;
+  enum eContextObjectMode ctx_mode;
+  bool clear_in_front;
+  bool wireframe_mode;
+  bool hide_overlays;
+  bool xray_enabled;
+  bool xray_enabled_and_not_wire;
+  short v3d_flag;     /* TODO move to View3DOverlay */
+  short v3d_gridflag; /* TODO move to View3DOverlay */
+  DRWState clipping_state;
+  OVERLAY_ShadingData shdata;
+
+  struct {
+    short sample;
+    short target_sample;
+    float prev_persmat[4][4];
+    bool enabled;
+  } antialiasing;
+  struct {
+    bool show_handles;
+  } edit_curve;
+  struct {
+    int ghost_ob;
+    int edit_ob;
+    bool do_zbufclip;
+    bool do_faces;
+    bool do_edges;
+    bool select_vert;
+    bool select_face;
+    bool select_edge;
+    int flag; /** Copy of v3d->overlay.edit_flag.  */
+  } edit_mesh;
+  struct {
+    bool use_weight;
+    int select_mode;
+  } edit_particle;
+  struct {
+    bool transparent;
+    bool show_relations;
+    bool do_pose_fade_geom;
+  } armature;
+  struct {
+    DRWCallBuffer *handle[2];
+  } mball;
+} OVERLAY_PrivateData; /* Transient data */
+
+typedef struct OVERLAY_StorageList {
+  struct OVERLAY_PrivateData *pd;
+} OVERLAY_StorageList;
+
+typedef struct OVERLAY_Data {
+  void *engine_type;
+  OVERLAY_FramebufferList *fbl;
+  OVERLAY_TextureList *txl;
+  OVERLAY_PassList *psl;
+  OVERLAY_StorageList *stl;
+} OVERLAY_Data;
+
+typedef struct OVERLAY_DupliData {
+  DRWShadingGroup *wire_shgrp;
+  DRWShadingGroup *outline_shgrp;
+  DRWShadingGroup *extra_shgrp;
+  struct GPUBatch *wire_geom;
+  struct GPUBatch *outline_geom;
+  struct GPUBatch *extra_geom;
+  short base_flag;
+} OVERLAY_DupliData;
+
+typedef struct BoneInstanceData {
+  /* Keep sync with bone instance vertex format (OVERLAY_InstanceFormats) */
+  union {
+    float mat[4][4];
+    struct {
+      float _pad0[3], color_hint_a;
+      float _pad1[3], color_hint_b;
+      float _pad2[3], color_a;
+      float _pad3[3], color_b;
+    };
+    struct {
+      float _pad00[3], amin_a;
+      float _pad01[3], amin_b;
+      float _pad02[3], amax_a;
+      float _pad03[3], amax_b;
+    };
+  };
+} BoneInstanceData;
+
+typedef struct OVERLAY_InstanceFormats {
+  struct GPUVertFormat *instance_pos;
+  struct GPUVertFormat *instance_extra;
+  struct GPUVertFormat *instance_bone;
+  struct GPUVertFormat *instance_bone_outline;
+  struct GPUVertFormat *instance_bone_envelope;
+  struct GPUVertFormat *instance_bone_envelope_distance;
+  struct GPUVertFormat *instance_bone_envelope_outline;
+  struct GPUVertFormat *instance_bone_stick;
+  struct GPUVertFormat *pos;
+  struct GPUVertFormat *pos_color;
+  struct GPUVertFormat *wire_extra;
+} OVERLAY_InstanceFormats;
+
+/* Pack data into the last row of the 4x4 matrix. It will be decoded by the vertex shader. */
+BLI_INLINE void pack_data_in_mat4(
+    float rmat[4][4], const float mat[4][4], float a, float b, float c, float d)
+{
+  copy_m4_m4(rmat, mat);
+  rmat[0][3] = a;
+  rmat[1][3] = b;
+  rmat[2][3] = c;
+  rmat[3][3] = d;
+}
+
+BLI_INLINE void pack_v4_in_mat4(float rmat[4][4], const float mat[4][4], const float v[4])
+{
+  pack_data_in_mat4(rmat, mat, v[0], v[1], v[2], v[3]);
+}
+
+BLI_INLINE void pack_fl_in_mat4(float rmat[4][4], const