Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/modes')
-rw-r--r--source/blender/draw/modes/draw_mode_engines.h46
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c183
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c337
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c277
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c617
-rw-r--r--source/blender/draw/modes/edit_mesh_mode_intern.h38
-rw-r--r--source/blender/draw/modes/edit_mesh_mode_text.c352
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c235
-rw-r--r--source/blender/draw/modes/edit_surface_mode.c251
-rw-r--r--source/blender/draw/modes/edit_text_mode.c290
-rw-r--r--source/blender/draw/modes/object_mode.c2394
-rw-r--r--source/blender/draw/modes/overlay_mode.c249
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c398
-rw-r--r--source/blender/draw/modes/paint_vertex_mode.c202
-rw-r--r--source/blender/draw/modes/paint_weight_mode.c244
-rw-r--r--source/blender/draw/modes/particle_mode.c246
-rw-r--r--source/blender/draw/modes/pose_mode.c320
-rw-r--r--source/blender/draw/modes/sculpt_mode.c281
-rw-r--r--source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl38
-rw-r--r--source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl91
-rw-r--r--source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl47
-rw-r--r--source/blender/draw/modes/shaders/armature_axes_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl15
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl156
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl16
-rw-r--r--source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl55
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl87
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl48
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl9
-rw-r--r--source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl37
-rw-r--r--source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl102
-rw-r--r--source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl81
-rw-r--r--source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl82
-rw-r--r--source/blender/draw/modes/shaders/armature_stick_frag.glsl13
-rw-r--r--source/blender/draw/modes/shaders/armature_stick_vert.glsl88
-rw-r--r--source/blender/draw/modes/shaders/common_fullscreen_vert.glsl10
-rw-r--r--source/blender/draw/modes/shaders/common_fxaa_lib.glsl678
-rw-r--r--source/blender/draw/modes/shaders/common_globals_lib.glsl73
-rw-r--r--source/blender/draw/modes/shaders/common_hair_lib.glsl190
-rw-r--r--source/blender/draw/modes/shaders/common_hair_refine_vert.glsl55
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl14
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl79
-rw-r--r--source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl39
-rw-r--r--source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl39
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl51
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl19
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl31
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl7
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl15
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl123
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl113
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl208
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl52
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl38
-rw-r--r--source/blender/draw/modes/shaders/edit_normals_geom.glsl15
-rw-r--r--source/blender/draw/modes/shaders/edit_normals_vert.glsl30
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_frag.glsl21
-rw-r--r--source/blender/draw/modes/shaders/object_empty_image_vert.glsl38
-rw-r--r--source/blender/draw/modes/shaders/object_grid_frag.glsl227
-rw-r--r--source/blender/draw/modes/shaders/object_grid_vert.glsl63
-rw-r--r--source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/object_mball_handles_vert.glsl34
-rw-r--r--source/blender/draw/modes/shaders/object_outline_detect_frag.glsl88
-rw-r--r--source/blender/draw/modes/shaders/object_outline_expand_frag.glsl37
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl10
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl40
-rw-r--r--source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl16
-rw-r--r--source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl27
-rw-r--r--source/blender/draw/modes/shaders/object_particle_dot_frag.glsl52
-rw-r--r--source/blender/draw/modes/shaders/object_particle_dot_vert.glsl35
-rw-r--r--source/blender/draw/modes/shaders/object_particle_prim_vert.glsl56
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl10
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl7
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl53
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl86
-rw-r--r--source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl189
-rw-r--r--source/blender/draw/modes/shaders/paint_texture_frag.glsl11
-rw-r--r--source/blender/draw/modes/shaders/paint_texture_vert.glsl15
-rw-r--r--source/blender/draw/modes/shaders/paint_vert_frag.glsl26
-rw-r--r--source/blender/draw/modes/shaders/paint_vertex_frag.glsl17
-rw-r--r--source/blender/draw/modes/shaders/paint_vertex_vert.glsl21
-rw-r--r--source/blender/draw/modes/shaders/paint_wire_frag.glsl22
-rw-r--r--source/blender/draw/modes/shaders/paint_wire_vert.glsl17
-rw-r--r--source/blender/draw/modes/shaders/particle_strand_frag.glsl12
-rw-r--r--source/blender/draw/modes/shaders/particle_strand_vert.glsl34
88 files changed, 11199 insertions, 0 deletions
diff --git a/source/blender/draw/modes/draw_mode_engines.h b/source/blender/draw/modes/draw_mode_engines.h
new file mode 100644
index 00000000000..f88d49dfa96
--- /dev/null
+++ b/source/blender/draw/modes/draw_mode_engines.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/draw_mode_engines.h
+ * \ingroup draw
+ */
+
+#ifndef __DRAW_MODE_ENGINES_H__
+#define __DRAW_MODE_ENGINES_H__
+
+extern DrawEngineType draw_engine_object_type;
+extern DrawEngineType draw_engine_edit_armature_type;
+extern DrawEngineType draw_engine_edit_curve_type;
+extern DrawEngineType draw_engine_edit_lattice_type;
+extern DrawEngineType draw_engine_edit_mesh_type;
+extern DrawEngineType draw_engine_edit_metaball_type;
+extern DrawEngineType draw_engine_edit_surface_type;
+extern DrawEngineType draw_engine_edit_text_type;
+extern DrawEngineType draw_engine_motion_path_type;
+extern DrawEngineType draw_engine_paint_texture_type;
+extern DrawEngineType draw_engine_paint_vertex_type;
+extern DrawEngineType draw_engine_paint_weight_type;
+extern DrawEngineType draw_engine_particle_type;
+extern DrawEngineType draw_engine_pose_type;
+extern DrawEngineType draw_engine_sculpt_type;
+extern DrawEngineType draw_engine_overlay_type;
+
+#endif /* __DRAW_MODE_ENGINES_H__ */
diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c
new file mode 100644
index 00000000000..285e703afbf
--- /dev/null
+++ b/source/blender/draw/modes/edit_armature_mode.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_armature_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_view3d_types.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+extern GlobalsUboStorage ts;
+
+/* *********** LISTS *********** */
+typedef struct EDIT_ARMATURE_PassList {
+ struct DRWPass *bone_solid;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_outline;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *bone_axes;
+ struct DRWPass *relationship;
+} EDIT_ARMATURE_PassList;
+
+typedef struct EDIT_ARMATURE_StorageList {
+ struct EDIT_ARMATURE_PrivateData *g_data;
+} EDIT_ARMATURE_StorageList;
+
+typedef struct EDIT_ARMATURE_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ EDIT_ARMATURE_PassList *psl;
+ EDIT_ARMATURE_StorageList *stl;
+} EDIT_ARMATURE_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct EDIT_ARMATURE_PrivateData {
+ char pad; /* UNUSED */
+} EDIT_ARMATURE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+static void EDIT_ARMATURE_cache_init(void *vedata)
+{
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+ EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ psl->bone_solid = DRW_pass_create("Bone Solid Pass", state);
+ }
+
+ {
+ /* Bones Outline */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ psl->bone_outline = DRW_pass_create("Bone Outline Pass", state);
+ }
+
+ {
+ /* Wire bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ psl->bone_wire = DRW_pass_create("Bone Wire Pass", state);
+ }
+
+ {
+ /* distance outline around envelope bones */
+ DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_FRONT;
+ psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WIRE_SMOOTH | DRW_STATE_BLEND;
+ psl->bone_axes = DRW_pass_create("Bone Axes Pass", state);
+ }
+
+ {
+ /* Non Meshes Pass (Camera, empties, lamps ...) */
+ DRWState state =
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_WIRE;
+ psl->relationship = DRW_pass_create("Bone Relationship Pass", state);
+ }
+}
+
+static void EDIT_ARMATURE_cache_populate(void *vedata, Object *ob)
+{
+ bArmature *arm = ob->data;
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+
+ if (ob->type == OB_ARMATURE) {
+ if (arm->edbo) {
+ DRWArmaturePasses passes = {
+ .bone_solid = psl->bone_solid,
+ .bone_outline = psl->bone_outline,
+ .bone_wire = psl->bone_wire,
+ .bone_envelope = psl->bone_envelope,
+ .bone_axes = psl->bone_axes,
+ .relationship_lines = psl->relationship,
+ };
+ DRW_shgroup_armature_edit(ob, passes);
+ }
+ }
+}
+
+static void EDIT_ARMATURE_draw_scene(void *vedata)
+{
+ EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0;
+
+ DRW_draw_pass(psl->bone_envelope);
+
+ if (transparent_bones) {
+ DRW_pass_state_add(psl->bone_solid, DRW_STATE_BLEND);
+ DRW_pass_state_remove(psl->bone_solid, DRW_STATE_WRITE_DEPTH);
+ DRW_draw_pass(psl->bone_solid);
+ }
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl)
+
+ if (!transparent_bones) {
+ DRW_draw_pass(psl->bone_solid);
+ }
+
+ DRW_draw_pass(psl->bone_outline);
+ DRW_draw_pass(psl->bone_wire);
+ DRW_draw_pass(psl->relationship);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+
+ /* Draw axes with linesmooth and outside of multisample buffer. */
+ DRW_draw_pass(psl->bone_axes);
+}
+
+static const DrawEngineDataSize EDIT_ARMATURE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_ARMATURE_Data);
+
+DrawEngineType draw_engine_edit_armature_type = {
+ NULL, NULL,
+ N_("EditArmatureMode"),
+ &EDIT_ARMATURE_data_size,
+ NULL,
+ NULL,
+ &EDIT_ARMATURE_cache_init,
+ &EDIT_ARMATURE_cache_populate,
+ NULL,
+ NULL,
+ &EDIT_ARMATURE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
new file mode 100644
index 00000000000..50ce29b7b1a
--- /dev/null
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_curve_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_object.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_batch.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[];
+extern char datatoc_edit_curve_overlay_frag_glsl[];
+extern char datatoc_edit_curve_overlay_handle_geom_glsl[];
+
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_CURVE_engine_init() to
+ * initialize most of them and EDIT_CURVE_cache_init()
+ * for EDIT_CURVE_PassList */
+
+typedef struct EDIT_CURVE_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_CURVE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *wire_pass;
+ struct DRWPass *overlay_edge_pass;
+ struct DRWPass *overlay_vert_pass;
+} EDIT_CURVE_PassList;
+
+typedef struct EDIT_CURVE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_CURVE_FramebufferList;
+
+typedef struct EDIT_CURVE_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_CURVE_TextureList;
+
+typedef struct EDIT_CURVE_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct EDIT_CURVE_PrivateData *g_data;
+} EDIT_CURVE_StorageList;
+
+typedef struct EDIT_CURVE_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_CURVE_FramebufferList *fbl;
+ EDIT_CURVE_TextureList *txl;
+ EDIT_CURVE_PassList *psl;
+ EDIT_CURVE_StorageList *stl;
+} EDIT_CURVE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_CURVE_engine_init();
+ * free in EDIT_CURVE_engine_free(); */
+
+ GPUShader *wire_sh;
+
+ GPUShader *overlay_edge_sh; /* handles and nurbs control cage */
+ GPUShader *overlay_vert_sh;
+
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_CURVE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_CURVE_cache_populate() */
+
+ /* resulting curve as 'wire' for curves (and optionally normals) */
+ DRWShadingGroup *wire_shgrp;
+
+ DRWShadingGroup *overlay_edge_shgrp;
+ DRWShadingGroup *overlay_vert_shgrp;
+} EDIT_CURVE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_CURVE_engine_init(void *vedata)
+{
+ EDIT_CURVE_TextureList *txl = ((EDIT_CURVE_Data *)vedata)->txl;
+ EDIT_CURVE_FramebufferList *fbl = ((EDIT_CURVE_Data *)vedata)->fbl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.wire_sh) {
+ e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.overlay_edge_sh) {
+ e_data.overlay_edge_sh = DRW_shader_create_with_lib(
+ datatoc_edit_curve_overlay_loosevert_vert_glsl,
+ datatoc_edit_curve_overlay_handle_geom_glsl,
+ datatoc_gpu_shader_flat_color_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+
+ if (!e_data.overlay_vert_sh) {
+ e_data.overlay_vert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_curve_overlay_loosevert_vert_glsl, NULL,
+ datatoc_edit_curve_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_CURVE_cache_init(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ DRWShadingGroup *grp;
+
+ /* Center-Line (wire) */
+ psl->wire_pass = DRW_pass_create(
+ "Curve Wire",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE);
+
+ grp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorWireEdit, 1);
+ stl->g_data->wire_shgrp = grp;
+
+
+ psl->overlay_edge_pass = DRW_pass_create(
+ "Curve Handle Overlay",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_WIRE);
+
+ grp = DRW_shgroup_create(e_data.overlay_edge_sh, psl->overlay_edge_pass);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ stl->g_data->overlay_edge_shgrp = grp;
+
+
+ psl->overlay_vert_pass = DRW_pass_create(
+ "Curve Vert Overlay",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT);
+
+ grp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ stl->g_data->overlay_vert_shgrp = grp;
+ }
+
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_CURVE_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_CURVE) {
+#if 0
+ if (ob == draw_ctx->object_edit)
+#else
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob))
+#endif
+ {
+ Curve *cu = ob->data;
+ /* Get geometry cache */
+ struct Gwn_Batch *geom;
+
+ geom = DRW_cache_curve_edge_wire_get(ob);
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+
+ if ((cu->flag & CU_3D) && (cu->drawflag & CU_HIDE_NORMALS) == 0) {
+ geom = DRW_cache_curve_edge_normal_get(ob, v3d->overlay.normals_length);
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+ }
+
+ /* Add geom to a shading group */
+ geom = DRW_cache_curve_edge_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->overlay_edge_shgrp, geom, ob->obmat);
+ }
+
+ geom = DRW_cache_curve_vert_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->overlay_vert_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_CURVE_cache_finish(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_CURVE_draw_scene(void *vedata)
+{
+ EDIT_CURVE_PassList *psl = ((EDIT_CURVE_Data *)vedata)->psl;
+ EDIT_CURVE_FramebufferList *fbl = ((EDIT_CURVE_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl);
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl)
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ /* ... or just render passes on default framebuffer. */
+ DRW_draw_pass(psl->wire_pass);
+ DRW_draw_pass(psl->overlay_edge_pass);
+ DRW_draw_pass(psl->overlay_vert_pass);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_CURVE_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.overlay_edge_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh);
+}
+
+static const DrawEngineDataSize EDIT_CURVE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_CURVE_Data);
+
+DrawEngineType draw_engine_edit_curve_type = {
+ NULL, NULL,
+ N_("EditCurveMode"),
+ &EDIT_CURVE_data_size,
+ &EDIT_CURVE_engine_init,
+ &EDIT_CURVE_engine_free,
+ &EDIT_CURVE_cache_init,
+ &EDIT_CURVE_cache_populate,
+ &EDIT_CURVE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_CURVE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c
new file mode 100644
index 00000000000..870dd14d677
--- /dev/null
+++ b/source/blender/draw/modes/edit_lattice_mode.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_lattice_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BKE_object.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_edit_lattice_overlay_loosevert_vert_glsl[];
+extern char datatoc_edit_lattice_overlay_frag_glsl[];
+
+extern char datatoc_gpu_shader_3D_vert_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_LATTICE_engine_init() to
+ * initialize most of them and EDIT_LATTICE_cache_init()
+ * for EDIT_LATTICE_PassList */
+
+typedef struct EDIT_LATTICE_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_LATTICE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *wire_pass;
+ struct DRWPass *vert_pass;
+} EDIT_LATTICE_PassList;
+
+typedef struct EDIT_LATTICE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_LATTICE_FramebufferList;
+
+typedef struct EDIT_LATTICE_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_LATTICE_TextureList;
+
+typedef struct EDIT_LATTICE_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct EDIT_LATTICE_PrivateData *g_data;
+} EDIT_LATTICE_StorageList;
+
+typedef struct EDIT_LATTICE_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_LATTICE_FramebufferList *fbl;
+ EDIT_LATTICE_TextureList *txl;
+ EDIT_LATTICE_PassList *psl;
+ EDIT_LATTICE_StorageList *stl;
+} EDIT_LATTICE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_LATTICE_engine_init();
+ * free in EDIT_LATTICE_engine_free(); */
+ GPUShader *wire_sh;
+
+ GPUShader *overlay_vert_sh;
+
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_LATTICE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_LATTICE_cache_populate() */
+ DRWShadingGroup *wire_shgrp;
+ DRWShadingGroup *vert_shgrp;
+} EDIT_LATTICE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_LATTICE_engine_init(void *vedata)
+{
+ EDIT_LATTICE_TextureList *txl = ((EDIT_LATTICE_Data *)vedata)->txl;
+ EDIT_LATTICE_FramebufferList *fbl = ((EDIT_LATTICE_Data *)vedata)->fbl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.wire_sh) {
+ e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+
+ if (!e_data.overlay_vert_sh) {
+ e_data.overlay_vert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_lattice_overlay_loosevert_vert_glsl, NULL,
+ datatoc_edit_lattice_overlay_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_LATTICE_cache_init(void *vedata)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ psl->wire_pass = DRW_pass_create(
+ "Lattice Wire",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE);
+ stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+
+ psl->vert_pass = DRW_pass_create(
+ "Lattice Verts",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT);
+ stl->g_data->vert_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->vert_pass);
+
+ DRW_shgroup_uniform_block(stl->g_data->vert_shgrp, "globalsBlock", globals_ubo);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_LATTICE_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ UNUSED_VARS(psl);
+
+ if (ob->type == OB_LATTICE) {
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
+ /* Get geometry cache */
+ struct Gwn_Batch *geom;
+
+ geom = DRW_cache_lattice_wire_get(ob, true);
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+
+ geom = DRW_cache_lattice_vert_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->vert_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_LATTICE_cache_finish(void *vedata)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_LATTICE_draw_scene(void *vedata)
+{
+ EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl;
+ EDIT_LATTICE_FramebufferList *fbl = ((EDIT_LATTICE_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl);
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl)
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ /* ... or just render passes on default framebuffer. */
+ DRW_draw_pass(psl->wire_pass);
+ DRW_draw_pass(psl->vert_pass);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_LATTICE_engine_free(void)
+{
+ // Currently built-in, dont free
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh);
+}
+
+static const DrawEngineDataSize EDIT_LATTICE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_LATTICE_Data);
+
+DrawEngineType draw_engine_edit_lattice_type = {
+ NULL, NULL,
+ N_("EditLatticeMode"),
+ &EDIT_LATTICE_data_size,
+ &EDIT_LATTICE_engine_init,
+ &EDIT_LATTICE_engine_free,
+ &EDIT_LATTICE_cache_init,
+ &EDIT_LATTICE_cache_populate,
+ &EDIT_LATTICE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_LATTICE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c
new file mode 100644
index 00000000000..700132e0ee4
--- /dev/null
+++ b/source/blender/draw/modes/edit_mesh_mode.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_mesh_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_shader.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "edit_mesh_mode_intern.h" /* own include */
+
+#include "BKE_object.h"
+
+#include "BLI_dynstr.h"
+
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_edit_mesh_overlay_common_lib_glsl[];
+extern char datatoc_edit_mesh_overlay_frag_glsl[];
+extern char datatoc_edit_mesh_overlay_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_geom_tri_glsl[];
+extern char datatoc_edit_mesh_overlay_geom_edge_glsl[];
+extern char datatoc_edit_mesh_overlay_loosevert_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_facedot_frag_glsl[];
+extern char datatoc_edit_mesh_overlay_facedot_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_mix_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_mix_frag_glsl[];
+extern char datatoc_edit_mesh_overlay_facefill_vert_glsl[];
+extern char datatoc_edit_mesh_overlay_facefill_frag_glsl[];
+extern char datatoc_edit_normals_vert_glsl[];
+extern char datatoc_edit_normals_geom_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+typedef struct EDIT_MESH_PassList {
+ struct DRWPass *vcolor_faces;
+ struct DRWPass *depth_hidden_wire;
+ struct DRWPass *edit_face_overlay;
+ struct DRWPass *edit_face_occluded;
+ struct DRWPass *mix_occlude;
+ struct DRWPass *facefill_occlude;
+ struct DRWPass *normals;
+} EDIT_MESH_PassList;
+
+typedef struct EDIT_MESH_FramebufferList {
+ struct GPUFrameBuffer *occlude_wire_fb;
+} EDIT_MESH_FramebufferList;
+
+typedef struct EDIT_MESH_StorageList {
+ struct EDIT_MESH_PrivateData *g_data;
+} EDIT_MESH_StorageList;
+
+typedef struct EDIT_MESH_Data {
+ void *engine_type;
+ EDIT_MESH_FramebufferList *fbl;
+ DRWViewportEmptyList *txl;
+ EDIT_MESH_PassList *psl;
+ EDIT_MESH_StorageList *stl;
+} EDIT_MESH_Data;
+
+/* *********** STATIC *********** */
+#define MAX_SHADERS 16
+
+static struct {
+ /* weight/vert-color */
+ GPUShader *vcolor_face_shader;
+
+ /* Geometry */
+ GPUShader *overlay_tri_sh_cache[MAX_SHADERS];
+ GPUShader *overlay_loose_edge_sh_cache[MAX_SHADERS];
+
+ GPUShader *overlay_vert_sh;
+ GPUShader *overlay_facedot_sh;
+ GPUShader *overlay_mix_sh;
+ GPUShader *overlay_facefill_sh;
+ GPUShader *normals_face_sh;
+ GPUShader *normals_loop_sh;
+ GPUShader *normals_sh;
+ GPUShader *depth_sh;
+ /* temp buffer texture */
+ struct GPUTexture *occlude_wire_depth_tx;
+ struct GPUTexture *occlude_wire_color_tx;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_MESH_PrivateData {
+ /* weight/vert-color */
+ DRWShadingGroup *fvcolor_shgrp;
+ DRWShadingGroup *depth_shgrp_hidden_wire;
+
+ DRWShadingGroup *fnormals_shgrp;
+ DRWShadingGroup *vnormals_shgrp;
+ DRWShadingGroup *lnormals_shgrp;
+
+ DRWShadingGroup *face_overlay_shgrp;
+ DRWShadingGroup *ledges_overlay_shgrp;
+ DRWShadingGroup *lverts_overlay_shgrp;
+ DRWShadingGroup *facedot_overlay_shgrp;
+
+ DRWShadingGroup *face_occluded_shgrp;
+ DRWShadingGroup *ledges_occluded_shgrp;
+ DRWShadingGroup *lverts_occluded_shgrp;
+ DRWShadingGroup *facedot_occluded_shgrp;
+ DRWShadingGroup *facefill_occluded_shgrp;
+
+ bool do_zbufclip;
+} EDIT_MESH_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+static int EDIT_MESH_sh_index(ToolSettings *tsettings, RegionView3D *rv3d, bool supports_fast_mode)
+{
+ int result = tsettings->selectmode << 1;
+ if (supports_fast_mode) {
+ SET_FLAG_FROM_TEST(result, (rv3d->rflag & RV3D_NAVIGATING), 1 << 0);
+ }
+ return result;
+}
+
+static char *EDIT_MESH_sh_defines(ToolSettings *tsettings, RegionView3D *rv3d, bool anti_alias)
+{
+ const int selectmode = tsettings->selectmode;
+ const int fast_mode = rv3d->rflag & RV3D_NAVIGATING;
+
+ char *str = NULL;
+ DynStr *ds = BLI_dynstr_new();
+
+ if (selectmode & SCE_SELECT_VERTEX) {
+ BLI_dynstr_append(ds, "#define VERTEX_SELECTION\n");
+ }
+
+ if (selectmode & SCE_SELECT_EDGE) {
+ BLI_dynstr_append(ds, "#define EDGE_SELECTION\n");
+ }
+
+ if (selectmode & SCE_SELECT_FACE) {
+ BLI_dynstr_append(ds, "#define FACE_SELECTION\n");
+ }
+
+ if (!fast_mode) {
+ BLI_dynstr_append(ds, "#define EDGE_FIX\n");
+ }
+
+ if (anti_alias) {
+ BLI_dynstr_append(ds, "#define ANTI_ALIASING\n");
+ }
+ BLI_dynstr_append(ds, "#define VERTEX_FACING\n");
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+static char *EDIT_MESH_sh_lib(void)
+{
+ char *str = NULL;
+ DynStr *ds = BLI_dynstr_new();
+
+ BLI_dynstr_append(ds, datatoc_common_globals_lib_glsl);
+ BLI_dynstr_append(ds, datatoc_edit_mesh_overlay_common_lib_glsl);
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return str;
+}
+
+static GPUShader *EDIT_MESH_ensure_shader(ToolSettings *tsettings, RegionView3D *rv3d, bool fast_mode, bool looseedge)
+{
+ const int index = EDIT_MESH_sh_index(tsettings, rv3d, fast_mode);
+ if (looseedge) {
+ if (!e_data.overlay_loose_edge_sh_cache[index]) {
+ char *defines = EDIT_MESH_sh_defines(tsettings, rv3d, true);
+ char *lib = EDIT_MESH_sh_lib();
+ e_data.overlay_loose_edge_sh_cache[index] = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_edge_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ lib,
+ defines);
+ MEM_freeN(lib);
+ MEM_freeN(defines);
+ }
+ return e_data.overlay_loose_edge_sh_cache[index];
+ }
+ else {
+ if (!e_data.overlay_tri_sh_cache[index]) {
+ char *defines = EDIT_MESH_sh_defines(tsettings, rv3d, true);
+ char *lib = EDIT_MESH_sh_lib();
+ e_data.overlay_tri_sh_cache[index] = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_vert_glsl,
+ datatoc_edit_mesh_overlay_geom_tri_glsl,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ lib,
+ defines);
+ MEM_freeN(lib);
+ MEM_freeN(defines);
+ }
+ return e_data.overlay_tri_sh_cache[index];
+ }
+}
+
+static void EDIT_MESH_engine_init(void *vedata)
+{
+ EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl;
+
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ e_data.occlude_wire_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH_COMPONENT24,
+ &draw_engine_edit_mesh_type);
+ e_data.occlude_wire_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8,
+ &draw_engine_edit_mesh_type);
+
+ GPU_framebuffer_ensure_config(&fbl->occlude_wire_fb, {
+ GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_color_tx)
+ });
+
+ if (!e_data.vcolor_face_shader) {
+ e_data.vcolor_face_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA);
+ }
+
+ if (!e_data.overlay_vert_sh) {
+ char *lib = EDIT_MESH_sh_lib();
+ e_data.overlay_vert_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_loosevert_vert_glsl, NULL,
+ datatoc_edit_mesh_overlay_frag_glsl,
+ lib,
+ "#define VERTEX_SELECTION\n");
+ MEM_freeN(lib);
+ }
+ if (!e_data.overlay_facedot_sh) {
+ e_data.overlay_facedot_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_facedot_vert_glsl, NULL,
+ datatoc_edit_mesh_overlay_facedot_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define VERTEX_FACING\n");
+ }
+ if (!e_data.overlay_mix_sh) {
+ e_data.overlay_mix_sh = DRW_shader_create_fullscreen(datatoc_edit_mesh_overlay_mix_frag_glsl, NULL);
+ }
+ if (!e_data.overlay_facefill_sh) {
+ e_data.overlay_facefill_sh = DRW_shader_create_with_lib(
+ datatoc_edit_mesh_overlay_facefill_vert_glsl, NULL,
+ datatoc_edit_mesh_overlay_facefill_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+ if (!e_data.normals_face_sh) {
+ e_data.normals_face_sh = DRW_shader_create(
+ datatoc_edit_normals_vert_glsl,
+ datatoc_edit_normals_geom_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl,
+ "#define FACE_NORMALS\n");
+ }
+ if (!e_data.normals_loop_sh) {
+ e_data.normals_loop_sh = DRW_shader_create(
+ datatoc_edit_normals_vert_glsl,
+ datatoc_edit_normals_geom_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl,
+ "#define LOOP_NORMALS\n");
+ }
+ if (!e_data.normals_sh) {
+ e_data.normals_sh = DRW_shader_create(
+ datatoc_edit_normals_vert_glsl,
+ datatoc_edit_normals_geom_glsl,
+ datatoc_gpu_shader_uniform_color_frag_glsl, NULL);
+ }
+ if (!e_data.depth_sh) {
+ e_data.depth_sh = DRW_shader_create_3D_depth_only();
+ }
+}
+
+static DRWPass *edit_mesh_create_overlay_pass(
+ float *faceAlpha, DRWState statemod,
+ DRWShadingGroup **r_face_shgrp, DRWShadingGroup **r_ledges_shgrp,
+ DRWShadingGroup **r_lverts_shgrp, DRWShadingGroup **r_facedot_shgrp)
+{
+ GPUShader *tri_sh, *ledge_sh;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *tsettings = scene->toolsettings;
+
+ ledge_sh = EDIT_MESH_ensure_shader(tsettings, rv3d, false, true);
+ tri_sh = EDIT_MESH_ensure_shader(tsettings, rv3d, true, false);
+
+ DRWPass *pass = DRW_pass_create(
+ "Edit Mesh Face Overlay Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_POINT | statemod);
+
+ *r_face_shgrp = DRW_shgroup_create(tri_sh, pass);
+ DRW_shgroup_uniform_block(*r_face_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(*r_face_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_float(*r_face_shgrp, "faceAlphaMod", faceAlpha, 1);
+
+ *r_ledges_shgrp = DRW_shgroup_create(ledge_sh, pass);
+ DRW_shgroup_uniform_block(*r_ledges_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(*r_ledges_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+
+ if ((tsettings->selectmode & (SCE_SELECT_VERTEX)) != 0) {
+ *r_lverts_shgrp = DRW_shgroup_create(e_data.overlay_vert_sh, pass);
+ DRW_shgroup_uniform_block(*r_lverts_shgrp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(*r_lverts_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ }
+
+ if ((tsettings->selectmode & (SCE_SELECT_FACE)) != 0) {
+ *r_facedot_shgrp = DRW_shgroup_create(e_data.overlay_facedot_sh, pass);
+ DRW_shgroup_uniform_block(*r_facedot_shgrp, "globalsBlock", globals_ubo);
+ }
+
+ return pass;
+}
+
+static float backwire_opacity;
+static float face_mod;
+static float size_normal;
+
+static void EDIT_MESH_cache_init(void *vedata)
+{
+ EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl;
+ EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ static float zero = 0.0f;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+
+ const bool xray_enabled = ((draw_ctx->v3d->shading.flag & V3D_SHADING_XRAY) != 0) &&
+ (draw_ctx->v3d->drawtype < OB_MATERIAL);
+ stl->g_data->do_zbufclip = ((v3d->flag & V3D_ZBUF_SELECT) == 0) || xray_enabled;
+
+ {
+ psl->vcolor_faces = DRW_pass_create(
+ "Vert Color Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->fvcolor_shgrp = DRW_shgroup_create(e_data.vcolor_face_shader, psl->vcolor_faces);
+
+ static float light[3] = {-0.3f, 0.5f, 1.0f};
+ static float alpha = 1.0f;
+ static float world_light = 1.0f; /* XXX, see: paint_vertex_mode.c */
+ DRW_shgroup_uniform_vec3(stl->g_data->fvcolor_shgrp, "light", light, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fvcolor_shgrp, "alpha", &alpha, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fvcolor_shgrp, "global", &world_light, 1);
+ }
+
+ {
+ /* Complementary Depth Pass */
+ psl->depth_hidden_wire = DRW_pass_create(
+ "Depth Pass Hidden Wire",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK);
+ stl->g_data->depth_shgrp_hidden_wire = DRW_shgroup_create(e_data.depth_sh, psl->depth_hidden_wire);
+ }
+
+ {
+ /* Normals */
+ psl->normals = DRW_pass_create(
+ "Edit Mesh Normals Pass",
+ DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->fnormals_shgrp = DRW_shgroup_create(e_data.normals_face_sh, psl->normals);
+ DRW_shgroup_uniform_float(stl->g_data->fnormals_shgrp, "normalSize", &size_normal, 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->fnormals_shgrp, "color", ts.colorNormal, 1);
+
+ stl->g_data->vnormals_shgrp = DRW_shgroup_create(e_data.normals_sh, psl->normals);
+ DRW_shgroup_uniform_float(stl->g_data->vnormals_shgrp, "normalSize", &size_normal, 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->vnormals_shgrp, "color", ts.colorVNormal, 1);
+
+ stl->g_data->lnormals_shgrp = DRW_shgroup_create(e_data.normals_loop_sh, psl->normals);
+ DRW_shgroup_uniform_float(stl->g_data->lnormals_shgrp, "normalSize", &size_normal, 1);
+ DRW_shgroup_uniform_vec4(stl->g_data->lnormals_shgrp, "color", ts.colorLNormal, 1);
+ }
+
+ if (!stl->g_data->do_zbufclip) {
+ psl->edit_face_overlay = edit_mesh_create_overlay_pass(
+ &face_mod, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND,
+ &stl->g_data->face_overlay_shgrp, &stl->g_data->ledges_overlay_shgrp,
+ &stl->g_data->lverts_overlay_shgrp, &stl->g_data->facedot_overlay_shgrp);
+ }
+ else {
+ /* We render all wires with depth and opaque to a new fbo and blend the result based on depth values */
+ psl->edit_face_occluded = edit_mesh_create_overlay_pass(
+ &zero, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH,
+ &stl->g_data->face_occluded_shgrp, &stl->g_data->ledges_occluded_shgrp,
+ &stl->g_data->lverts_occluded_shgrp, &stl->g_data->facedot_occluded_shgrp);
+
+ /* however we loose the front faces value (because we need the depth of occluded wires and
+ * faces are alpha blended ) so we recover them in a new pass. */
+ psl->facefill_occlude = DRW_pass_create(
+ "Front Face Color",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+ stl->g_data->facefill_occluded_shgrp = DRW_shgroup_create(e_data.overlay_facefill_sh, psl->facefill_occlude);
+ DRW_shgroup_uniform_block(stl->g_data->facefill_occluded_shgrp, "globalsBlock", globals_ubo);
+
+ /* we need a full screen pass to combine the result */
+ struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+
+ psl->mix_occlude = DRW_pass_create(
+ "Mix Occluded Wires",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+ DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.overlay_mix_sh, psl->mix_occlude);
+ DRW_shgroup_call_add(mix_shgrp, quad, NULL);
+ DRW_shgroup_uniform_float(mix_shgrp, "alpha", &backwire_opacity, 1);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireColor", &e_data.occlude_wire_color_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireDepth", &e_data.occlude_wire_depth_tx);
+ DRW_shgroup_uniform_texture_ref(mix_shgrp, "sceneDepth", &dtxl->depth);
+ }
+}
+
+static void edit_mesh_add_ob_to_pass(
+ Scene *scene, Object *ob, DRWShadingGroup *face_shgrp, DRWShadingGroup *ledges_shgrp,
+ DRWShadingGroup *lverts_shgrp, DRWShadingGroup *facedot_shgrp, DRWShadingGroup *facefill_shgrp)
+{
+ struct Gwn_Batch *geo_ovl_tris, *geo_ovl_ledges, *geo_ovl_lverts, *geo_ovl_fcenter;
+ ToolSettings *tsettings = scene->toolsettings;
+
+ DRW_cache_mesh_wire_overlay_get(ob, &geo_ovl_tris, &geo_ovl_ledges, &geo_ovl_lverts);
+ DRW_shgroup_call_add(face_shgrp, geo_ovl_tris, ob->obmat);
+ DRW_shgroup_call_add(ledges_shgrp, geo_ovl_ledges, ob->obmat);
+
+ if (facefill_shgrp) {
+ DRW_shgroup_call_add(facefill_shgrp, geo_ovl_tris, ob->obmat);
+ }
+
+ if ((tsettings->selectmode & SCE_SELECT_VERTEX) != 0) {
+ DRW_shgroup_call_add(lverts_shgrp, geo_ovl_lverts, ob->obmat);
+ }
+
+ if (facedot_shgrp && (tsettings->selectmode & SCE_SELECT_FACE) != 0 ) {
+ geo_ovl_fcenter = DRW_cache_face_centers_get(ob);
+ DRW_shgroup_call_add(facedot_shgrp, geo_ovl_fcenter, ob->obmat);
+ }
+}
+
+static void EDIT_MESH_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ struct Gwn_Batch *geom;
+
+ if (ob->type == OB_MESH) {
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
+ const Mesh *me = ob->data;
+ bool do_occlude_wire = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
+ bool do_show_weight = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT) != 0;
+
+ /* Updating uniform */
+ backwire_opacity = v3d->overlay.backwire_opacity;
+
+ bool fnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_NORMALS) != 0;
+ bool vnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_VERT_NORMALS) != 0;
+ bool lnormals_do = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_LOOP_NORMALS) != 0;
+ /* Updating uniform */
+ size_normal = v3d->overlay.normals_length;
+
+ face_mod = (do_occlude_wire) ? 0.0f : 1.0f;
+
+ if (do_show_weight) {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ DRW_shgroup_call_add(stl->g_data->fvcolor_shgrp, geom, ob->obmat);
+ }
+
+ if (do_occlude_wire) {
+ geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call_add(stl->g_data->depth_shgrp_hidden_wire, geom, ob->obmat);
+ }
+
+ if (fnormals_do) {
+ geom = DRW_cache_face_centers_get(ob);
+ DRW_shgroup_call_add(stl->g_data->fnormals_shgrp, geom, ob->obmat);
+ }
+
+ if (vnormals_do || lnormals_do) {
+ struct Gwn_Batch *geo_ovl_tris, *geo_ovl_ledges, *geo_ovl_lverts;
+ DRW_cache_mesh_normals_overlay_get(ob, &geo_ovl_tris, &geo_ovl_ledges, &geo_ovl_lverts);
+
+ if (vnormals_do) {
+ DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_tris, ob->obmat);
+ DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_ledges, ob->obmat);
+ DRW_shgroup_call_add(stl->g_data->vnormals_shgrp, geo_ovl_lverts, ob->obmat);
+ }
+
+ if (lnormals_do) {
+ DRW_shgroup_call_add(stl->g_data->lnormals_shgrp, geo_ovl_tris, ob->obmat);
+ }
+ }
+
+ if (stl->g_data->do_zbufclip) {
+ edit_mesh_add_ob_to_pass(
+ scene, ob, stl->g_data->face_occluded_shgrp, stl->g_data->ledges_occluded_shgrp,
+ stl->g_data->lverts_occluded_shgrp, stl->g_data->facedot_occluded_shgrp,
+ stl->g_data->facefill_occluded_shgrp);
+ }
+ else {
+ edit_mesh_add_ob_to_pass(
+ scene, ob, stl->g_data->face_overlay_shgrp, stl->g_data->ledges_overlay_shgrp,
+ stl->g_data->lverts_overlay_shgrp, NULL, NULL);
+ }
+
+ /* 3D text overlay */
+ if (me->drawflag & (ME_DRAWEXTRA_EDGELEN |
+ ME_DRAWEXTRA_FACEAREA |
+ ME_DRAWEXTRA_FACEANG |
+ ME_DRAWEXTRA_EDGEANG |
+ ME_DRAWEXTRA_INDICES))
+ {
+ if (DRW_state_show_text()) {
+ DRW_edit_mesh_mode_text_measure_stats(
+ draw_ctx->ar, v3d, ob, &scene->unit);
+ }
+ }
+ }
+ }
+}
+
+static void EDIT_MESH_draw_scene(void *vedata)
+{
+ EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl;
+ EDIT_MESH_StorageList *stl = ((EDIT_MESH_Data *)vedata)->stl;
+ EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ DRW_draw_pass(psl->vcolor_faces);
+
+ DRW_draw_pass(psl->depth_hidden_wire);
+
+ if (stl->g_data->do_zbufclip) {
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ /* render facefill */
+ DRW_draw_pass(psl->facefill_occlude);
+
+ /* Render wires on a separate framebuffer */
+ GPU_framebuffer_bind(fbl->occlude_wire_fb);
+ GPU_framebuffer_clear_color_depth(fbl->occlude_wire_fb, clearcol, 1.0f);
+ DRW_draw_pass(psl->normals);
+ DRW_draw_pass(psl->edit_face_occluded);
+
+ /* Combine with scene buffer */
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->mix_occlude);
+ }
+ else {
+ DRW_draw_pass(psl->normals);
+ DRW_draw_pass(psl->edit_face_overlay);
+ }
+}
+
+static void EDIT_MESH_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.overlay_vert_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_facedot_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_mix_sh);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_facefill_sh);
+ DRW_SHADER_FREE_SAFE(e_data.normals_loop_sh);
+ DRW_SHADER_FREE_SAFE(e_data.normals_face_sh);
+ DRW_SHADER_FREE_SAFE(e_data.normals_sh);
+
+ for (int i = 0; i < MAX_SHADERS; i++) {
+ DRW_SHADER_FREE_SAFE(e_data.overlay_tri_sh_cache[i]);
+ DRW_SHADER_FREE_SAFE(e_data.overlay_loose_edge_sh_cache[i]);
+ }
+}
+
+static const DrawEngineDataSize EDIT_MESH_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_MESH_Data);
+
+DrawEngineType draw_engine_edit_mesh_type = {
+ NULL, NULL,
+ N_("EditMeshMode"),
+ &EDIT_MESH_data_size,
+ &EDIT_MESH_engine_init,
+ &EDIT_MESH_engine_free,
+ &EDIT_MESH_cache_init,
+ &EDIT_MESH_cache_populate,
+ NULL,
+ NULL,
+ &EDIT_MESH_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_mesh_mode_intern.h b/source/blender/draw/modes/edit_mesh_mode_intern.h
new file mode 100644
index 00000000000..99298bd41f4
--- /dev/null
+++ b/source/blender/draw/modes/edit_mesh_mode_intern.h
@@ -0,0 +1,38 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/draw/modes/edit_mesh_mode_intern.h
+ * \ingroup draw
+ */
+
+#ifndef __EDIT_MESH_MODE_INTERN_H__
+#define __EDIT_MESH_MODE_INTERN_H__
+
+struct ARegion;
+struct Object;
+struct UnitSettings;
+struct View3D;
+
+/* 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);
+
+#endif /* __EDIT_MESH_MODE_INTERN_H__ */
diff --git a/source/blender/draw/modes/edit_mesh_mode_text.c b/source/blender/draw/modes/edit_mesh_mode_text.c
new file mode 100644
index 00000000000..def96e79eba
--- /dev/null
+++ b/source/blender/draw/modes/edit_mesh_mode_text.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_mesh_mode_text.c
+ * \ingroup draw
+ */
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_unit.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_shader.h"
+#include "GPU_viewport.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "UI_resources.h"
+
+#include "draw_manager_text.h"
+
+#include "edit_mesh_mode_intern.h" /* own include */
+
+/* Copied from drawobject.c */
+void DRW_edit_mesh_mode_text_measure_stats(
+ ARegion *ar, View3D *v3d,
+ Object *ob, const UnitSettings *unit)
+{
+ /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square, etc.).
+ * See bug #36090.
+ */
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ const short txt_flag = DRW_TEXT_CACHE_LOCALCLIP | (unit->system ? 0 : DRW_TEXT_CACHE_ASCII);
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ float v1[3], v2[3], v3[3], vmid[3], fvec[3];
+ char numstr[32]; /* Stores the measurement display text here */
+ size_t numstr_len;
+ const char *conv_float; /* Use a float conversion matching the grid size */
+ unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */
+ float area; /* area of the face */
+ float grid = unit->system ? unit->scale_length : v3d->grid;
+ const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
+ const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0;
+ const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0;
+ /* when 2 edge-info options are enabled, space apart */
+ const bool do_edge_textpair = (me->drawflag & ME_DRAWEXTRA_EDGELEN) && (me->drawflag & ME_DRAWEXTRA_EDGEANG);
+ const float edge_texpair_sep = 0.4f;
+ float clip_planes[4][4];
+ /* allow for displaying shape keys and deform mods */
+ BMIter iter;
+
+ /* make the precision of the display value proportionate to the gridsize */
+
+ if (grid <= 0.01f) conv_float = "%.6g";
+ else if (grid <= 0.1f) conv_float = "%.5g";
+ else if (grid <= 1.0f) conv_float = "%.4g";
+ else if (grid <= 10.0f) conv_float = "%.3g";
+ else conv_float = "%.2g";
+
+ if (me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_EDGEANG | ME_DRAWEXTRA_INDICES)) {
+ BoundBox bb;
+ const rcti rect = {0, ar->winx, 0, ar->winy};
+
+ ED_view3d_clipping_calc(&bb, clip_planes, ar, em->ob, &rect);
+ }
+
+ if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
+ BMEdge *eed;
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ /* draw selected edges, or edges next to selected verts while dragging */
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
+ (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))))
+ {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+
+ if (do_edge_textpair) {
+ interp_v3_v3v3(vmid, v1, v2, edge_texpair_sep);
+ }
+ else {
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ }
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ }
+
+ if (unit->system) {
+ numstr_len = bUnit_AsString(
+ numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3,
+ unit->system, B_UNIT_LENGTH, do_split, false);
+ }
+ else {
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2));
+ }
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+
+ if (me->drawflag & ME_DRAWEXTRA_EDGEANG) {
+ const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
+ BMEdge *eed;
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ BMLoop *l_a, *l_b;
+ if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
+ /* draw selected edges, or edges next to selected verts while dragging */
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
+ (do_moving &&
+ (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ||
+ /* special case, this is useful to show when verts connected to
+ * this edge via a face are being transformed */
+ BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)
+ )))
+ {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+ float no_a[3], no_b[3];
+ float angle;
+
+ if (do_edge_textpair) {
+ interp_v3_v3v3(vmid, v2_clip, v1_clip, edge_texpair_sep);
+ }
+ else {
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ }
+
+ copy_v3_v3(no_a, l_a->f->no);
+ copy_v3_v3(no_b, l_b->f->no);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->imat, no_a);
+ mul_mat3_m4_v3(ob->imat, no_b);
+ normalize_v3(no_a);
+ normalize_v3(no_b);
+ }
+
+ angle = angle_normalized_v3v3(no_a, no_b);
+
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+ }
+
+ if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
+ /* would be nice to use BM_face_calc_area, but that is for 2d faces
+ * so instead add up tessellation triangle areas */
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
+
+ int i, n, numtri;
+ BMFace *f = NULL;
+ BM_ITER_MESH_INDEX(f, &iter, em->bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ n = 0;
+ numtri = f->len - 2;
+ area = 0;
+ zero_v3(vmid);
+ BMLoop *(*l)[3] = &em->looptris[poly_to_tri_count(i, BM_elem_index_get(f->l_first))];
+ for (int j = 0; j < numtri; j++) {
+ copy_v3_v3(v1, l[j][0]->v->co);
+ copy_v3_v3(v2, l[j][1]->v->co);
+ copy_v3_v3(v3, l[j][2]->v->co);
+
+ add_v3_v3(vmid, v1);
+ add_v3_v3(vmid, v2);
+ add_v3_v3(vmid, v3);
+ n += 3;
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
+ }
+
+ area += area_tri_v3(v1, v2, v3);
+ }
+
+ mul_v3_fl(vmid, 1.0f / (float)n);
+
+ if (unit->system) {
+ numstr_len = bUnit_AsString(
+ numstr, sizeof(numstr),
+ (double)(area * unit->scale_length * unit->scale_length),
+ 3, unit->system, B_UNIT_AREA, do_split, false);
+ }
+ else {
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area);
+ }
+
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, txt_flag, col);
+ }
+ }
+ }
+
+ if (me->drawflag & ME_DRAWEXTRA_FACEANG) {
+ BMFace *efa;
+ const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS);
+
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
+
+ if (is_face_sel || do_moving) {
+ BMIter liter;
+ BMLoop *loop;
+ bool is_first = true;
+
+ BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (is_face_sel ||
+ (do_moving &&
+ (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT))))
+ {
+ float v2_local[3];
+
+ /* lazy init center calc */
+ if (is_first) {
+ BM_face_calc_center_bounds(efa, vmid);
+ is_first = false;
+ }
+ copy_v3_v3(v1, loop->prev->v->co);
+ copy_v3_v3(v2, loop->v->co);
+ copy_v3_v3(v3, loop->next->v->co);
+
+ copy_v3_v3(v2_local, v2);
+
+ if (do_global) {
+ mul_mat3_m4_v3(ob->obmat, v1);
+ mul_mat3_m4_v3(ob->obmat, v2);
+ mul_mat3_m4_v3(ob->obmat, v3);
+ }
+
+ float angle = angle_v3v3v3(v1, v2, v3);
+
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
+ interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
+ DRW_text_cache_add(dt, fvec, numstr, numstr_len, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+ }
+
+ /* This option is for mesh ops and addons debugging; only available in UI if Blender starts with --debug */
+ if (me->drawflag & ME_DRAWEXTRA_INDICES) {
+ int i;
+
+ /* For now, reuse an appropriate theme color */
+ UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+
+ if (em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *v;
+
+ BM_ITER_MESH_INDEX(v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, v->co, numstr, numstr_len, 0, txt_flag, col);
+ }
+ }
+ }
+
+ if (em->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *e;
+
+ BM_ITER_MESH_INDEX(e, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float v1_clip[3], v2_clip[3];
+
+ copy_v3_v3(v1, e->v1->co);
+ copy_v3_v3(v2, e->v2->co);
+
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
+ mid_v3_v3v3(vmid, v1_clip, v2_clip);
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, vmid, numstr, numstr_len, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+
+ if (em->selectmode & SCE_SELECT_FACE) {
+ BMFace *f;
+
+ BM_ITER_MESH_INDEX(f, &iter, em->bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_face_calc_center_mean(f, v1);
+
+ numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
+ DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, txt_flag, col);
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c
new file mode 100644
index 00000000000..20539295fd2
--- /dev/null
+++ b/source/blender/draw/modes/edit_metaball_mode.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_metaball_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_meta_types.h"
+
+#include "BKE_object.h"
+#include "BKE_mball.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_select.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_METABALL_engine_init() to
+ * initialize most of them and EDIT_METABALL_cache_init()
+ * for EDIT_METABALL_PassList */
+
+typedef struct EDIT_METABALL_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_METABALL_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *pass;
+} EDIT_METABALL_PassList;
+
+typedef struct EDIT_METABALL_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_METABALL_FramebufferList;
+
+typedef struct EDIT_METABALL_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_METABALL_TextureList;
+
+typedef struct EDIT_METABALL_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ // struct CustomStruct *block;
+ struct EDIT_METABALL_PrivateData *g_data;
+} EDIT_METABALL_StorageList;
+
+typedef struct EDIT_METABALL_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_METABALL_FramebufferList *fbl;
+ EDIT_METABALL_TextureList *txl;
+ EDIT_METABALL_PassList *psl;
+ EDIT_METABALL_StorageList *stl;
+} EDIT_METABALL_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct EDIT_METABALL_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_METABALL_cache_populate() */
+ DRWShadingGroup *group;
+} EDIT_METABALL_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_METABALL_cache_init(void *vedata)
+{
+ EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ DRWState state = (
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_WIRE);
+ psl->pass = DRW_pass_create("My Pass", state);
+
+ /* Create a shadingGroup using a function in draw_common.c or custom one */
+ stl->g_data->group = shgroup_instance_mball_handles(psl->pass);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_METABALL_cache_populate(void *vedata, Object *ob)
+{
+ //EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ EDIT_METABALL_StorageList *stl = ((EDIT_METABALL_Data *)vedata)->stl;
+
+ if (ob->type == OB_MBALL) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ DRWShadingGroup *group = stl->g_data->group;
+
+ if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) {
+ MetaBall *mb = ob->data;
+
+ const float *color;
+ const float col_radius[3] = {0.63, 0.19, 0.19}; /* 0x3030A0 */
+ const float col_radius_select[3] = {0.94, 0.63, 0.63}; /* 0xA0A0F0 */
+ const float col_stiffness[3] = {0.19, 0.63, 0.19}; /* 0x30A030 */
+ const float col_stiffness_select[3] = {0.63, 0.94, 0.63}; /* 0xA0F0A0 */
+
+ const bool is_select = DRW_state_is_select();
+
+ int selection_id = 0;
+
+ float draw_scale_xform[3][4]; /* Matrix of Scale and Translation */
+ {
+ float scamat[3][3];
+ copy_m3_m4(scamat, ob->obmat);
+ /* Get the normalized inverse matrix to extract only
+ * the scale of Scamat */
+ float iscamat[3][3];
+ invert_m3_m3(iscamat, scamat);
+ normalize_m3(iscamat);
+ mul_m3_m3_post(scamat, iscamat);
+
+ copy_v3_v3(draw_scale_xform[0], scamat[0]);
+ copy_v3_v3(draw_scale_xform[1], scamat[1]);
+ copy_v3_v3(draw_scale_xform[2], scamat[2]);
+ }
+
+ for (MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ float world_pos[3];
+ mul_v3_m4v3(world_pos, ob->obmat, &ml->x);
+ draw_scale_xform[0][3] = world_pos[0];
+ draw_scale_xform[1][3] = world_pos[1];
+ draw_scale_xform[2][3] = world_pos[2];
+
+ float draw_stiffness_radius = ml->rad * atanf(ml->s) / (float)M_PI_2;
+
+ if ((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) color = col_radius_select;
+ else color = col_radius;
+
+ if (is_select) {
+ ml->selcol1 = ++selection_id;
+ DRW_select_load_id(selection_id);
+ }
+
+ DRW_shgroup_call_dynamic_add(group, draw_scale_xform, &ml->rad, color);
+
+ if ((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) color = col_stiffness_select;
+ else color = col_stiffness;
+
+ if (is_select) {
+ ml->selcol2 = ++selection_id;
+ DRW_select_load_id(selection_id);
+ }
+
+ DRW_shgroup_call_dynamic_add(group, draw_scale_xform, &draw_stiffness_radius, color);
+ }
+ }
+ }
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_METABALL_draw_scene(void *vedata)
+{
+ EDIT_METABALL_PassList *psl = ((EDIT_METABALL_Data *)vedata)->psl;
+ /* render passes on default framebuffer. */
+ DRW_draw_pass(psl->pass);
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_METABALL_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+static const DrawEngineDataSize EDIT_METABALL_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_METABALL_Data);
+
+DrawEngineType draw_engine_edit_metaball_type = {
+ NULL, NULL,
+ N_("EditMetaballMode"),
+ &EDIT_METABALL_data_size,
+ NULL,
+ &EDIT_METABALL_engine_free,
+ &EDIT_METABALL_cache_init,
+ &EDIT_METABALL_cache_populate,
+ NULL,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_METABALL_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_surface_mode.c b/source/blender/draw/modes/edit_surface_mode.c
new file mode 100644
index 00000000000..7074ba3d024
--- /dev/null
+++ b/source/blender/draw/modes/edit_surface_mode.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_surface_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_SURFACE_engine_init() to
+ * initialize most of them and EDIT_SURFACE_cache_init()
+ * for EDIT_SURFACE_PassList */
+
+typedef struct EDIT_SURFACE_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_SURFACE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *pass;
+} EDIT_SURFACE_PassList;
+
+typedef struct EDIT_SURFACE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_SURFACE_FramebufferList;
+
+typedef struct EDIT_SURFACE_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_SURFACE_TextureList;
+
+typedef struct EDIT_SURFACE_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct EDIT_SURFACE_PrivateData *g_data;
+} EDIT_SURFACE_StorageList;
+
+typedef struct EDIT_SURFACE_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_SURFACE_FramebufferList *fbl;
+ EDIT_SURFACE_TextureList *txl;
+ EDIT_SURFACE_PassList *psl;
+ EDIT_SURFACE_StorageList *stl;
+} EDIT_SURFACE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_SURFACE_engine_init();
+ * free in EDIT_SURFACE_engine_free(); */
+ struct GPUShader *custom_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_SURFACE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in EDIT_SURFACE_cache_populate() */
+ DRWShadingGroup *group;
+} EDIT_SURFACE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_SURFACE_engine_init(void *vedata)
+{
+ EDIT_SURFACE_TextureList *txl = ((EDIT_SURFACE_Data *)vedata)->txl;
+ EDIT_SURFACE_FramebufferList *fbl = ((EDIT_SURFACE_Data *)vedata)->fbl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.custom_shader) {
+ e_data.custom_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_SURFACE_cache_init(void *vedata)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ DRWState state = (
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_WIRE);
+ psl->pass = DRW_pass_create("My Pass", state);
+
+ /* Create a shadingGroup using a function in draw_common.c or custom one */
+ /*
+ * stl->g_data->group = shgroup_dynlines_uniform_color(psl->pass, ts.colorWire);
+ * -- or --
+ * stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass);
+ */
+ stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass);
+
+ /* Uniforms need a pointer to it's value so be sure it's accessible at
+ * any given time (i.e. use static vars) */
+ static float color[4] = {0.0f, 0.0f, 1.0f, 1.0};
+ DRW_shgroup_uniform_vec4(stl->g_data->group, "color", color, 1);
+ }
+
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_SURFACE_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_Data *)vedata)->stl;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_MESH) {
+ /* Get geometry cache */
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+
+ /* Add geom to a shading group */
+ DRW_shgroup_call_add(stl->g_data->group, geom, ob->obmat);
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_SURFACE_cache_finish(void *vedata)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_StorageList *stl = ((EDIT_SURFACE_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_SURFACE_draw_scene(void *vedata)
+{
+ EDIT_SURFACE_PassList *psl = ((EDIT_SURFACE_Data *)vedata)->psl;
+ EDIT_SURFACE_FramebufferList *fbl = ((EDIT_SURFACE_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl, dfbl, dtxl);
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ /* ... or just render passes on default framebuffer. */
+ DRW_draw_pass(psl->pass);
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_SURFACE_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+static const DrawEngineDataSize EDIT_SURFACE_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_SURFACE_Data);
+
+DrawEngineType draw_engine_edit_surface_type = {
+ NULL, NULL,
+ N_("EditSurfaceMode"),
+ &EDIT_SURFACE_data_size,
+ &EDIT_SURFACE_engine_init,
+ &EDIT_SURFACE_engine_free,
+ &EDIT_SURFACE_cache_init,
+ &EDIT_SURFACE_cache_populate,
+ &EDIT_SURFACE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_SURFACE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c
new file mode 100644
index 00000000000..5750dc8a0b9
--- /dev/null
+++ b/source/blender/draw/modes/edit_text_mode.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/edit_text_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_curve_types.h"
+
+#include "BIF_glutil.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_batch.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use EDIT_TEXT_engine_init() to
+ * initialize most of them and EDIT_TEXT_cache_init()
+ * for EDIT_TEXT_PassList */
+
+typedef struct EDIT_TEXT_PassList {
+ /* Declare all passes here and init them in
+ * EDIT_TEXT_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *wire_pass;
+ struct DRWPass *overlay_select_pass;
+ struct DRWPass *overlay_cursor_pass;
+} EDIT_TEXT_PassList;
+
+typedef struct EDIT_TEXT_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} EDIT_TEXT_FramebufferList;
+
+typedef struct EDIT_TEXT_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} EDIT_TEXT_TextureList;
+
+typedef struct EDIT_TEXT_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct EDIT_TEXT_PrivateData *g_data;
+} EDIT_TEXT_StorageList;
+
+typedef struct EDIT_TEXT_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ EDIT_TEXT_FramebufferList *fbl;
+ EDIT_TEXT_TextureList *txl;
+ EDIT_TEXT_PassList *psl;
+ EDIT_TEXT_StorageList *stl;
+} EDIT_TEXT_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in EDIT_TEXT_engine_init();
+ * free in EDIT_TEXT_engine_free(); */
+ GPUShader *wire_sh;
+ GPUShader *overlay_select_sh;
+ GPUShader *overlay_cursor_sh;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct EDIT_TEXT_PrivateData {
+ /* resulting curve as 'wire' for fast editmode drawing */
+ DRWShadingGroup *wire_shgrp;
+ DRWShadingGroup *overlay_select_shgrp;
+ DRWShadingGroup *overlay_cursor_shgrp;
+} EDIT_TEXT_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void EDIT_TEXT_engine_init(void *vedata)
+{
+ EDIT_TEXT_TextureList *txl = ((EDIT_TEXT_Data *)vedata)->txl;
+ EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.wire_sh) {
+ e_data.wire_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.overlay_select_sh) {
+ e_data.overlay_select_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.overlay_cursor_sh) {
+ e_data.overlay_cursor_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void EDIT_TEXT_cache_init(void *vedata)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Text outline (fast drawing!) */
+ psl->wire_pass = DRW_pass_create(
+ "Font Wire",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE);
+ stl->g_data->wire_shgrp = DRW_shgroup_create(e_data.wire_sh, psl->wire_pass);
+
+ psl->overlay_select_pass = DRW_pass_create(
+ "Font Select",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
+ stl->g_data->overlay_select_shgrp = DRW_shgroup_create(e_data.overlay_select_sh, psl->overlay_select_pass);
+
+ psl->overlay_cursor_pass = DRW_pass_create(
+ "Font Cursor",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH);
+ stl->g_data->overlay_cursor_shgrp = DRW_shgroup_create(e_data.overlay_cursor_sh, psl->overlay_cursor_pass);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void EDIT_TEXT_cache_populate(void *vedata, Object *ob)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_FONT) {
+ if (ob == draw_ctx->object_edit) {
+ const Curve *cu = ob->data;
+ /* Get geometry cache */
+ struct Gwn_Batch *geom;
+
+ if (cu->flag & CU_FAST) {
+ geom = DRW_cache_text_edge_wire_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->wire_shgrp, geom, ob->obmat);
+ }
+ }
+ else {
+ /* object mode draws */
+ }
+
+ geom = DRW_cache_text_select_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->overlay_select_shgrp, geom, ob->obmat);
+ }
+
+ geom = DRW_cache_text_cursor_overlay_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(stl->g_data->overlay_cursor_shgrp, geom, ob->obmat);
+ }
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void EDIT_TEXT_cache_finish(void *vedata)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void EDIT_TEXT_draw_scene(void *vedata)
+{
+ EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl;
+ EDIT_TEXT_FramebufferList *fbl = ((EDIT_TEXT_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl, dfbl, dtxl);
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ DRW_draw_pass(psl->wire_pass);
+
+ set_inverted_drawing(1);
+ DRW_draw_pass(psl->overlay_select_pass);
+ DRW_draw_pass(psl->overlay_cursor_pass);
+ set_inverted_drawing(0);
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void EDIT_TEXT_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+static const DrawEngineDataSize EDIT_TEXT_data_size = DRW_VIEWPORT_DATA_SIZE(EDIT_TEXT_Data);
+
+DrawEngineType draw_engine_edit_text_type = {
+ NULL, NULL,
+ N_("EditTextMode"),
+ &EDIT_TEXT_data_size,
+ &EDIT_TEXT_engine_init,
+ &EDIT_TEXT_engine_free,
+ &EDIT_TEXT_cache_init,
+ &EDIT_TEXT_cache_populate,
+ &EDIT_TEXT_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &EDIT_TEXT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
new file mode 100644
index 00000000000..887a1cb7721
--- /dev/null
+++ b/source/blender/draw/modes/object_mode.c
@@ -0,0 +1,2394 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/object_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_userdef_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_force_types.h"
+#include "DNA_lightprobe_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BIF_gl.h"
+
+#include "BLI_string_utils.h"
+
+#include "BKE_anim.h"
+#include "BKE_camera.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_image.h"
+#include "BKE_texture.h"
+
+#include "ED_view3d.h"
+
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "UI_resources.h"
+
+#include "draw_mode_engines.h"
+#include "draw_manager_text.h"
+#include "draw_common.h"
+
+#include "DEG_depsgraph_query.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GPUTexture *globals_ramp; /* draw_common.c */
+extern GlobalsUboStorage ts;
+
+extern char datatoc_object_outline_prepass_vert_glsl[];
+extern char datatoc_object_outline_prepass_geom_glsl[];
+extern char datatoc_object_outline_prepass_frag_glsl[];
+extern char datatoc_object_outline_resolve_frag_glsl[];
+extern char datatoc_object_outline_detect_frag_glsl[];
+extern char datatoc_object_outline_expand_frag_glsl[];
+extern char datatoc_object_grid_frag_glsl[];
+extern char datatoc_object_grid_vert_glsl[];
+extern char datatoc_object_empty_image_frag_glsl[];
+extern char datatoc_object_empty_image_vert_glsl[];
+extern char datatoc_object_lightprobe_grid_vert_glsl[];
+extern char datatoc_object_particle_prim_vert_glsl[];
+extern char datatoc_object_particle_dot_vert_glsl[];
+extern char datatoc_object_particle_dot_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_common_fxaa_lib_glsl[];
+extern char datatoc_gpu_shader_flat_color_frag_glsl[];
+extern char datatoc_gpu_shader_flat_id_frag_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
+
+/* *********** LISTS *********** */
+typedef struct OBJECT_PassList {
+ struct DRWPass *non_meshes;
+ struct DRWPass *ob_center;
+ struct DRWPass *outlines;
+ struct DRWPass *outlines_search;
+ struct DRWPass *outlines_expand;
+ struct DRWPass *outlines_bleed;
+ struct DRWPass *outlines_resolve;
+ struct DRWPass *grid;
+ struct DRWPass *bone_solid;
+ struct DRWPass *bone_outline;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *bone_axes;
+ struct DRWPass *particle;
+ struct DRWPass *lightprobes;
+ /* use for empty/background images */
+ struct DRWPass *reference_image;
+} OBJECT_PassList;
+
+typedef struct OBJECT_FramebufferList {
+ struct GPUFrameBuffer *outlines_fb;
+ struct GPUFrameBuffer *blur_fb;
+ struct GPUFrameBuffer *expand_fb;
+} OBJECT_FramebufferList;
+
+typedef struct OBJECT_StorageList {
+ struct OBJECT_PrivateData *g_data;
+} OBJECT_StorageList;
+
+typedef struct OBJECT_Data {
+ void *engine_type;
+ OBJECT_FramebufferList *fbl;
+ DRWViewportEmptyList *txl;
+ OBJECT_PassList *psl;
+ OBJECT_StorageList *stl;
+} OBJECT_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct OBJECT_PrivateData {
+ /* Empties */
+ DRWShadingGroup *plain_axes;
+ DRWShadingGroup *cube;
+ DRWShadingGroup *circle;
+ DRWShadingGroup *sphere;
+ DRWShadingGroup *cone;
+ DRWShadingGroup *single_arrow;
+ DRWShadingGroup *single_arrow_line;
+ DRWShadingGroup *arrows;
+ DRWShadingGroup *axis_names;
+ /* GPUTexture -> EmptyImageShadingGroupData */
+ GHash *image_plane_map;
+
+ /* Force Field */
+ DRWShadingGroup *field_wind;
+ DRWShadingGroup *field_force;
+ DRWShadingGroup *field_vortex;
+ DRWShadingGroup *field_curve_sta;
+ DRWShadingGroup *field_curve_end;
+ DRWShadingGroup *field_tube_limit;
+ DRWShadingGroup *field_cone_limit;
+
+ /* Speaker */
+ DRWShadingGroup *speaker;
+
+ /* Probe */
+ DRWShadingGroup *probe_cube;
+ DRWShadingGroup *probe_planar;
+ DRWShadingGroup *probe_grid;
+
+ /* MetaBalls */
+ DRWShadingGroup *mball_handle;
+
+ /* Lamps */
+ DRWShadingGroup *lamp_center;
+ DRWShadingGroup *lamp_groundpoint;
+ DRWShadingGroup *lamp_groundline;
+ DRWShadingGroup *lamp_circle;
+ DRWShadingGroup *lamp_circle_shadow;
+ DRWShadingGroup *lamp_sunrays;
+ DRWShadingGroup *lamp_distance;
+ DRWShadingGroup *lamp_buflimit;
+ DRWShadingGroup *lamp_buflimit_points;
+ DRWShadingGroup *lamp_area_sphere;
+ DRWShadingGroup *lamp_area_square;
+ DRWShadingGroup *lamp_area_disk;
+ DRWShadingGroup *lamp_hemi;
+ DRWShadingGroup *lamp_spot_cone;
+ DRWShadingGroup *lamp_spot_blend;
+ DRWShadingGroup *lamp_spot_pyramid;
+ DRWShadingGroup *lamp_spot_blend_rect;
+
+ /* Helpers */
+ DRWShadingGroup *relationship_lines;
+
+ /* Objects Centers */
+ DRWShadingGroup *center_active;
+ DRWShadingGroup *center_selected;
+ DRWShadingGroup *center_deselected;
+ DRWShadingGroup *center_selected_lib;
+ DRWShadingGroup *center_deselected_lib;
+
+ /* Camera */
+ DRWShadingGroup *camera;
+ DRWShadingGroup *camera_frame;
+ DRWShadingGroup *camera_tria;
+ DRWShadingGroup *camera_focus;
+ DRWShadingGroup *camera_clip;
+ DRWShadingGroup *camera_clip_points;
+ DRWShadingGroup *camera_mist;
+ DRWShadingGroup *camera_mist_points;
+
+ /* Outlines */
+ DRWShadingGroup *outlines_active;
+ DRWShadingGroup *outlines_select;
+ DRWShadingGroup *outlines_transform;
+
+ /* Lightprobes */
+ DRWShadingGroup *lightprobes_cube_select;
+ DRWShadingGroup *lightprobes_cube_active;
+ DRWShadingGroup *lightprobes_cube_transform;
+
+ DRWShadingGroup *lightprobes_planar_select;
+ DRWShadingGroup *lightprobes_planar_active;
+ DRWShadingGroup *lightprobes_planar_transform;
+
+ /* Wire */
+ DRWShadingGroup *wire;
+ DRWShadingGroup *wire_active;
+ DRWShadingGroup *wire_select;
+ DRWShadingGroup *wire_transform;
+
+ /* Points */
+ DRWShadingGroup *points;
+ DRWShadingGroup *points_active;
+ DRWShadingGroup *points_select;
+ DRWShadingGroup *points_transform;
+
+ /* Texture Space */
+ DRWShadingGroup *texspace;
+
+ /* Outlines id offset */
+ int id_ofs_active;
+ int id_ofs_select;
+ int id_ofs_transform;
+ int id_ofs_prb_active;
+ int id_ofs_prb_select;
+ int id_ofs_prb_transform;
+} OBJECT_PrivateData; /* Transient data */
+
+static struct {
+ /* Instance Data format */
+ struct Gwn_VertFormat *particle_format;
+ struct Gwn_VertFormat *empty_image_format;
+ struct Gwn_VertFormat *empty_image_wire_format;
+
+ /* fullscreen shaders */
+ GPUShader *outline_prepass_sh;
+ GPUShader *outline_prepass_wire_sh;
+ GPUShader *outline_resolve_sh;
+ GPUShader *outline_resolve_aa_sh;
+ GPUShader *outline_detect_sh;
+ GPUShader *outline_detect_wire_sh;
+ GPUShader *outline_fade_sh;
+
+ /* regular shaders */
+ GPUShader *object_empty_image_sh;
+ GPUShader *object_empty_image_wire_sh;
+ GPUShader *grid_sh;
+ GPUShader *part_dot_sh;
+ GPUShader *part_prim_sh;
+ GPUShader *part_axis_sh;
+ GPUShader *lightprobe_grid_sh;
+ float camera_pos[3];
+ float screenvecs[3][4];
+ float grid_settings[5];
+ int grid_flag;
+ float grid_normal[3];
+ float grid_axes[3];
+ int zpos_flag;
+ int zneg_flag;
+ float zplane_normal[3];
+ float zplane_axes[3];
+ float inv_viewport_size[2];
+ bool draw_grid;
+ /* Temp buffer textures */
+ struct GPUTexture *outlines_depth_tx;
+ struct GPUTexture *outlines_id_tx;
+ struct GPUTexture *outlines_color_tx;
+ struct GPUTexture *outlines_blur_tx;
+} e_data = {NULL}; /* Engine data */
+
+
+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),
+};
+
+/* *********** FUNCTIONS *********** */
+
+static void OBJECT_engine_init(void *vedata)
+{
+ OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl;
+
+ const float *viewport_size = DRW_viewport_size_get();
+ const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
+ if (DRW_state_is_fbo()) {
+ e_data.outlines_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH_COMPONENT24,
+ &draw_engine_object_type);
+ /* 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 */
+ e_data.outlines_id_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R16UI,
+ &draw_engine_object_type);
+
+ GPU_framebuffer_ensure_config(&fbl->outlines_fb, {
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_id_tx)
+ });
+
+ e_data.outlines_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8,
+ &draw_engine_object_type);
+
+ GPU_framebuffer_ensure_config(&fbl->expand_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_color_tx)
+ });
+
+ e_data.outlines_blur_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA8,
+ &draw_engine_object_type);
+
+ GPU_framebuffer_ensure_config(&fbl->blur_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(e_data.outlines_blur_tx)
+ });
+ }
+
+ /* Shaders */
+ if (!e_data.outline_resolve_sh) {
+ /* Outline */
+ e_data.outline_prepass_sh = DRW_shader_create_3D(datatoc_object_outline_prepass_frag_glsl, NULL);
+
+ e_data.outline_prepass_wire_sh = DRW_shader_create(
+ datatoc_object_outline_prepass_vert_glsl,
+ datatoc_object_outline_prepass_geom_glsl,
+ datatoc_object_outline_prepass_frag_glsl, NULL);
+
+ e_data.outline_resolve_sh = DRW_shader_create_fullscreen(datatoc_object_outline_resolve_frag_glsl, NULL);
+
+ e_data.outline_resolve_aa_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_object_outline_resolve_frag_glsl,
+ datatoc_common_fxaa_lib_glsl,
+ "#define FXAA_ALPHA\n"
+ "#define USE_FXAA\n");
+
+ e_data.outline_detect_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_object_outline_detect_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#extension GL_ARB_texture_gather : enable\n");
+
+ e_data.outline_detect_wire_sh = DRW_shader_create_with_lib(
+ datatoc_common_fullscreen_vert_glsl, NULL,
+ datatoc_object_outline_detect_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define WIRE\n"
+ "#extension GL_ARB_texture_gather : enable\n");
+
+
+ e_data.outline_fade_sh = DRW_shader_create_fullscreen(datatoc_object_outline_expand_frag_glsl, NULL);
+
+ /* Empty images */
+ e_data.object_empty_image_sh = DRW_shader_create_with_lib(
+ datatoc_object_empty_image_vert_glsl, NULL,
+ datatoc_object_empty_image_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+
+ e_data.object_empty_image_wire_sh = DRW_shader_create_with_lib(
+ datatoc_object_empty_image_vert_glsl, NULL,
+ datatoc_object_empty_image_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define USE_WIRE\n");
+
+ /* Grid */
+ e_data.grid_sh = DRW_shader_create_with_lib(
+ datatoc_object_grid_vert_glsl, NULL,
+ datatoc_object_grid_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+
+ /* Particles */
+ e_data.part_prim_sh = DRW_shader_create(
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, NULL);
+
+ e_data.part_axis_sh = DRW_shader_create(
+ datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl,
+ "#define USE_AXIS\n");
+
+ e_data.part_dot_sh = DRW_shader_create(
+ datatoc_object_particle_dot_vert_glsl, NULL, datatoc_object_particle_dot_frag_glsl, NULL);
+
+ /* Lightprobes */
+ e_data.lightprobe_grid_sh = DRW_shader_create(
+ datatoc_object_lightprobe_grid_vert_glsl, NULL, datatoc_gpu_shader_flat_id_frag_glsl, NULL);
+ }
+
+ {
+ /* Grid precompute */
+ float invviewmat[4][4], invwinmat[4][4];
+ float viewmat[4][4], winmat[4][4];
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ float grid_scale = ED_view3d_grid_scale(scene, v3d, NULL);
+ float grid_res;
+
+ const bool show_axis_x = (v3d->gridflag & V3D_SHOW_X) != 0;
+ const bool show_axis_y = (v3d->gridflag & V3D_SHOW_Y) != 0;
+ const bool show_axis_z = (v3d->gridflag & V3D_SHOW_Z) != 0;
+ const bool show_floor = (v3d->gridflag & V3D_SHOW_FLOOR) != 0;
+ e_data.draw_grid = show_axis_x || show_axis_y || show_axis_z || show_floor;
+
+ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+ DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+ DRW_viewport_matrix_get(invwinmat, DRW_MAT_WININV);
+ DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV);
+
+ /* Setup camera pos */
+ copy_v3_v3(e_data.camera_pos, invviewmat[3]);
+
+ /* if perps */
+ if (winmat[3][3] == 0.0f) {
+ float fov;
+ float viewvecs[2][4] = {
+ {1.0f, -1.0f, -1.0f, 1.0f},
+ {-1.0f, 1.0f, -1.0f, 1.0f}
+ };
+
+ /* convert the view vectors to view space */
+ for (int i = 0; i < 2; i++) {
+ mul_m4_v4(invwinmat, viewvecs[i]);
+ mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); /* perspective divide */
+ }
+
+ fov = angle_v3v3(viewvecs[0], viewvecs[1]) / 2.0f;
+ grid_res = fabsf(tanf(fov)) / grid_scale;
+
+ e_data.grid_flag = (1 << 4); /* XY plane */
+ if (show_axis_x)
+ e_data.grid_flag |= SHOW_AXIS_X;
+ if (show_axis_y)
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ if (show_floor)
+ e_data.grid_flag |= SHOW_GRID;
+
+ }
+ else {
+ float viewdist = 1.0f / max_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
+ grid_res = viewdist / grid_scale;
+
+ if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) {
+ e_data.grid_flag = PLANE_YZ;
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ e_data.grid_flag |= SHOW_AXIS_Z;
+ e_data.grid_flag |= SHOW_GRID;
+ e_data.grid_flag |= GRID_BACK;
+ }
+ else if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
+ e_data.grid_flag = PLANE_XY;
+ e_data.grid_flag |= SHOW_AXIS_X;
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ e_data.grid_flag |= SHOW_GRID;
+ e_data.grid_flag |= GRID_BACK;
+ }
+ else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
+ e_data.grid_flag = PLANE_XZ;
+ e_data.grid_flag |= SHOW_AXIS_X;
+ e_data.grid_flag |= SHOW_AXIS_Z;
+ e_data.grid_flag |= SHOW_GRID;
+ e_data.grid_flag |= GRID_BACK;
+ }
+ else { /* RV3D_VIEW_USER */
+ e_data.grid_flag = PLANE_XY;
+ if (show_axis_x)
+ e_data.grid_flag |= SHOW_AXIS_X;
+ if (show_axis_y)
+ e_data.grid_flag |= SHOW_AXIS_Y;
+ if (show_floor)
+ e_data.grid_flag |= SHOW_GRID;
+ }
+ }
+
+ e_data.grid_normal[0] = (float)((e_data.grid_flag & PLANE_YZ) != 0);
+ e_data.grid_normal[1] = (float)((e_data.grid_flag & PLANE_XZ) != 0);
+ e_data.grid_normal[2] = (float)((e_data.grid_flag & PLANE_XY) != 0);
+
+ e_data.grid_axes[0] = (float)((e_data.grid_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ e_data.grid_axes[1] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ e_data.grid_axes[2] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+
+ /* Vectors to recover pixel world position. Fix grid precision issue. */
+ /* Using pixel at z = 0.0f in ndc space : gives average precision between
+ * near and far plane. Note that it might not be the best choice. */
+ copy_v4_fl4(e_data.screenvecs[0], 1.0f, -1.0f, 0.0f, 1.0f);
+ copy_v4_fl4(e_data.screenvecs[1], -1.0f, 1.0f, 0.0f, 1.0f);
+ copy_v4_fl4(e_data.screenvecs[2], -1.0f, -1.0f, 0.0f, 1.0f);
+
+ for (int i = 0; i < 3; i++) {
+ /* Doing 2 steps to recover world position of the corners of the frustum.
+ * Using the inverse perspective matrix is giving very low precision output. */
+ mul_m4_v4(invwinmat, e_data.screenvecs[i]);
+ e_data.screenvecs[i][0] /= e_data.screenvecs[i][3]; /* perspective divide */
+ e_data.screenvecs[i][1] /= e_data.screenvecs[i][3]; /* perspective divide */
+ e_data.screenvecs[i][2] /= e_data.screenvecs[i][3]; /* perspective divide */
+ e_data.screenvecs[i][3] = 1.0f;
+ /* main instability come from this one */
+ /* TODO : to make things even more stable, don't use
+ * invviewmat and derive vectors from camera properties */
+ mul_m4_v4(invviewmat, e_data.screenvecs[i]);
+ }
+
+ sub_v3_v3(e_data.screenvecs[0], e_data.screenvecs[2]);
+ sub_v3_v3(e_data.screenvecs[1], e_data.screenvecs[2]);
+
+ /* Z axis if needed */
+ if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
+ e_data.zpos_flag = SHOW_AXIS_Z;
+
+ float zvec[4] = {0.0f, 0.0f, -1.0f, 0.0f};
+ mul_m4_v4(invviewmat, zvec);
+
+ /* z axis : chose the most facing plane */
+ if (fabsf(zvec[0]) < fabsf(zvec[1])) {
+ e_data.zpos_flag |= PLANE_XZ;
+ }
+ else {
+ e_data.zpos_flag |= PLANE_YZ;
+ }
+
+ e_data.zneg_flag = e_data.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) && (e_data.camera_pos[2] > 0.0f)) ||
+ ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f)))
+ {
+ e_data.zpos_flag |= CLIP_ZPOS;
+ e_data.zneg_flag |= CLIP_ZNEG;
+ }
+ else {
+ e_data.zpos_flag |= CLIP_ZNEG;
+ e_data.zneg_flag |= CLIP_ZPOS;
+ }
+
+ e_data.zplane_normal[0] = (float)((e_data.zpos_flag & PLANE_YZ) != 0);
+ e_data.zplane_normal[1] = (float)((e_data.zpos_flag & PLANE_XZ) != 0);
+ e_data.zplane_normal[2] = (float)((e_data.zpos_flag & PLANE_XY) != 0);
+
+ e_data.zplane_axes[0] = (float)((e_data.zpos_flag & (PLANE_XZ | PLANE_XY)) != 0);
+ e_data.zplane_axes[1] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XY)) != 0);
+ e_data.zplane_axes[2] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0);
+
+ }
+ else {
+ e_data.zneg_flag = e_data.zpos_flag = CLIP_ZNEG | CLIP_ZPOS;
+ }
+
+ float dist;
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ dist = ((Camera *)camera_object)->clipend;
+ }
+ else {
+ dist = v3d->far;
+ }
+
+ e_data.grid_settings[0] = dist / 2.0f; /* gridDistance */
+ e_data.grid_settings[1] = grid_res; /* gridResolution */
+ e_data.grid_settings[2] = grid_scale; /* gridScale */
+ e_data.grid_settings[3] = v3d->gridsubdiv; /* gridSubdiv */
+ e_data.grid_settings[4] = (v3d->gridsubdiv > 1) ? 1.0f / logf(v3d->gridsubdiv) : 0.0f; /* 1/log(gridSubdiv) */
+ }
+
+ copy_v2_v2(e_data.inv_viewport_size, DRW_viewport_size_get());
+ invert_v2(e_data.inv_viewport_size);
+}
+
+static void OBJECT_engine_free(void)
+{
+ MEM_SAFE_FREE(e_data.particle_format);
+ MEM_SAFE_FREE(e_data.empty_image_format);
+ MEM_SAFE_FREE(e_data.empty_image_wire_format);
+ DRW_SHADER_FREE_SAFE(e_data.outline_prepass_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_prepass_wire_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_resolve_aa_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_detect_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_detect_wire_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_fade_sh);
+ DRW_SHADER_FREE_SAFE(e_data.object_empty_image_sh);
+ DRW_SHADER_FREE_SAFE(e_data.object_empty_image_wire_sh);
+ DRW_SHADER_FREE_SAFE(e_data.grid_sh);
+ DRW_SHADER_FREE_SAFE(e_data.part_prim_sh);
+ DRW_SHADER_FREE_SAFE(e_data.part_axis_sh);
+ DRW_SHADER_FREE_SAFE(e_data.part_dot_sh);
+ DRW_SHADER_FREE_SAFE(e_data.lightprobe_grid_sh);
+}
+
+static DRWShadingGroup *shgroup_outline(DRWPass *pass, const int *ofs, GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_int(grp, "baseId", ofs, 1);
+
+ return grp;
+}
+
+/* currently same as 'shgroup_outline', new function to avoid confustion */
+static DRWShadingGroup *shgroup_wire(DRWPass *pass, const float col[4], GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", col, 1);
+
+ return grp;
+}
+
+/* currently same as 'shgroup_outline', new function to avoid confustion */
+static DRWShadingGroup *shgroup_points(DRWPass *pass, const float col[4], GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_vec4(grp, "color", col, 1);
+
+ return grp;
+}
+
+static int *shgroup_theme_id_to_probe_outline_counter(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return &stl->g_data->id_ofs_prb_active;
+ case TH_SELECT:
+ return &stl->g_data->id_ofs_prb_select;
+ case TH_TRANSFORM:
+ default:
+ return &stl->g_data->id_ofs_prb_transform;
+ }
+}
+
+static int *shgroup_theme_id_to_outline_counter(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return &stl->g_data->id_ofs_active;
+ case TH_SELECT:
+ return &stl->g_data->id_ofs_select;
+ case TH_TRANSFORM:
+ default:
+ return &stl->g_data->id_ofs_transform;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_probe_planar_outline_shgrp(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ /* does not increment counter */
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->lightprobes_planar_active;
+ case TH_SELECT:
+ return stl->g_data->lightprobes_planar_select;
+ case TH_TRANSFORM:
+ default:
+ return stl->g_data->lightprobes_planar_transform;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_probe_cube_outline_shgrp(
+ OBJECT_StorageList *stl, int theme_id)
+{
+ /* does not increment counter */
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->lightprobes_cube_active;
+ case TH_SELECT:
+ return stl->g_data->lightprobes_cube_select;
+ case TH_TRANSFORM:
+ default:
+ return stl->g_data->lightprobes_cube_transform;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_outline_or(
+ OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
+{
+ int *counter = shgroup_theme_id_to_outline_counter(stl, theme_id);
+ *counter += 1;
+
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->outlines_active;
+ case TH_SELECT:
+ return stl->g_data->outlines_select;
+ case TH_TRANSFORM:
+ return stl->g_data->outlines_transform;
+ default:
+ return fallback;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_wire_or(
+ OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->wire_active;
+ case TH_SELECT:
+ return stl->g_data->wire_select;
+ case TH_TRANSFORM:
+ return stl->g_data->wire_transform;
+ default:
+ return fallback;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_point_or(
+ OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback)
+{
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return stl->g_data->points_active;
+ case TH_SELECT:
+ return stl->g_data->points_select;
+ case TH_TRANSFORM:
+ return stl->g_data->points_transform;
+ default:
+ return fallback;
+ }
+}
+
+static void image_calc_aspect(Image *ima, ImageUser *iuser, float r_image_aspect[2])
+{
+ float ima_x, ima_y;
+ if (ima) {
+ int w, h;
+ BKE_image_get_size(ima, iuser, &w, &h);
+ ima_x = w;
+ ima_y = h;
+ }
+ 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;
+ }
+}
+
+/* per-image shading groups for image-type empty objects */
+struct EmptyImageShadingGroupData {
+ DRWShadingGroup *shgrp_image;
+ DRWShadingGroup *shgrp_wire;
+ float image_aspect[2];
+};
+
+static void DRW_shgroup_empty_image(
+ OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, const float color[3])
+{
+ /* TODO: 'StereoViews', see draw_empty_image. */
+
+ if (stl->g_data->image_plane_map == NULL) {
+ stl->g_data->image_plane_map = BLI_ghash_ptr_new(__func__);
+ }
+
+ struct EmptyImageShadingGroupData *empty_image_data;
+
+ GPUTexture *tex = ob->data ?
+ GPU_texture_from_blender(ob->data, ob->iuser, GL_TEXTURE_2D, false, 0.0f) : NULL;
+ void **val_p;
+
+ /* Create on demand, 'tex' may be NULL. */
+ if (BLI_ghash_ensure_p(stl->g_data->image_plane_map, tex, &val_p)) {
+ empty_image_data = *val_p;
+ }
+ else {
+ empty_image_data = MEM_mallocN(sizeof(*empty_image_data), __func__);
+
+ image_calc_aspect(ob->data, ob->iuser, empty_image_data->image_aspect);
+
+ if (tex) {
+ DRW_shgroup_instance_format(e_data.empty_image_format, {
+ {"objectColor", DRW_ATTRIB_FLOAT, 4},
+ {"size", DRW_ATTRIB_FLOAT, 1},
+ {"offset", DRW_ATTRIB_FLOAT, 2},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16},
+ });
+
+ struct Gwn_Batch *geom = DRW_cache_image_plane_get();
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ e_data.object_empty_image_sh, psl->non_meshes, geom, e_data.empty_image_format);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1);
+
+ empty_image_data->shgrp_image = grp;
+ }
+ else {
+ empty_image_data->shgrp_image = NULL;
+ }
+
+ {
+ DRW_shgroup_instance_format(e_data.empty_image_wire_format, {
+ {"objectColor", DRW_ATTRIB_FLOAT, 4},
+ {"size", DRW_ATTRIB_FLOAT, 1},
+ {"offset", DRW_ATTRIB_FLOAT, 2},
+ {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}
+ });
+
+ struct Gwn_Batch *geom = DRW_cache_image_plane_wire_get();
+ DRWShadingGroup *grp = DRW_shgroup_instance_create(
+ e_data.object_empty_image_wire_sh, psl->non_meshes, geom, e_data.empty_image_wire_format);
+ DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1);
+
+ empty_image_data->shgrp_wire = grp;
+ }
+
+ *val_p = empty_image_data;
+ }
+
+ if (empty_image_data->shgrp_image != NULL) {
+ DRW_shgroup_call_dynamic_add(
+ empty_image_data->shgrp_image,
+ ob->col,
+ &ob->empty_drawsize,
+ ob->ima_ofs,
+ ob->obmat);
+ }
+
+ DRW_shgroup_call_dynamic_add(
+ empty_image_data->shgrp_wire,
+ color,
+ &ob->empty_drawsize,
+ ob->ima_ofs,
+ ob->obmat);
+}
+
+static void OBJECT_cache_init(void *vedata)
+{
+ OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
+ OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ OBJECT_PrivateData *g_data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool xray_enabled = ((draw_ctx->v3d->shading.flag & V3D_SHADING_XRAY) != 0) &&
+ (draw_ctx->v3d->drawtype < OB_MATERIAL);
+ /* TODO : use dpi setting for enabling the second pass */
+ const bool do_outline_expand = false;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ g_data = stl->g_data;
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE;
+ psl->outlines = DRW_pass_create("Outlines Depth Pass", state);
+
+ GPUShader *sh = e_data.outline_prepass_sh;
+
+ if (xray_enabled) {
+ sh = e_data.outline_prepass_wire_sh;
+ }
+
+ g_data->outlines_select = shgroup_outline(psl->outlines, &g_data->id_ofs_select, sh);
+ g_data->outlines_transform = shgroup_outline(psl->outlines, &g_data->id_ofs_transform, sh);
+ g_data->outlines_active = shgroup_outline(psl->outlines, &g_data->id_ofs_active, sh);
+
+ g_data->id_ofs_select = 0;
+ g_data->id_ofs_active = 0;
+ g_data->id_ofs_transform = 0;
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRWPass *pass = psl->lightprobes = DRW_pass_create("Object Probe Pass", state);
+ struct Gwn_Batch *sphere = DRW_cache_sphere_get();
+ struct Gwn_Batch *quad = DRW_cache_quad_get();
+
+ /* Cubemap */
+ g_data->lightprobes_cube_select = shgroup_instance_outline(pass, sphere, &g_data->id_ofs_prb_select);
+ g_data->lightprobes_cube_active = shgroup_instance_outline(pass, sphere, &g_data->id_ofs_prb_active);
+ g_data->lightprobes_cube_transform = shgroup_instance_outline(pass, sphere, &g_data->id_ofs_prb_transform);
+
+ /* Planar */
+ g_data->lightprobes_planar_select = shgroup_instance_outline(pass, quad, &g_data->id_ofs_prb_select);
+ g_data->lightprobes_planar_active = shgroup_instance_outline(pass, quad, &g_data->id_ofs_prb_active);
+ g_data->lightprobes_planar_transform = shgroup_instance_outline(pass, quad, &g_data->id_ofs_prb_transform);
+
+ g_data->id_ofs_prb_select = 0;
+ g_data->id_ofs_prb_active = 0;
+ g_data->id_ofs_prb_transform = 0;
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+ /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
+ float alphaOcclu = (xray_enabled) ? 1.0f : 0.35f;
+ /* Reminder : bool uniforms need to be 4 bytes. */
+ static const int bTrue = true;
+ static const int bFalse = false;
+
+ psl->outlines_search = DRW_pass_create("Outlines Detect Pass", state);
+
+ GPUShader *sh = (xray_enabled) ? e_data.outline_detect_wire_sh : e_data.outline_detect_sh;
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->outlines_search);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineId", &e_data.outlines_id_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &e_data.outlines_depth_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", alphaOcclu);
+ DRW_shgroup_uniform_int(grp, "idOffsets", &stl->g_data->id_ofs_active, 3);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_expand = DRW_pass_create("Outlines Expand Pass", state);
+
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_expand);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_blur_tx);
+ DRW_shgroup_uniform_bool(grp, "doExpand", (do_outline_expand) ? &bTrue : &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->outlines_bleed = DRW_pass_create("Outlines Bleed Pass", state);
+
+ if (do_outline_expand) {
+ grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_bleed);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_color_tx);
+ DRW_shgroup_uniform_bool(grp, "doExpand", &bFalse, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND;
+ psl->outlines_resolve = DRW_pass_create("Outlines Resolve Pass", state);
+
+ struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+ GPUTexture **outline_tx = (do_outline_expand) ? &e_data.outlines_blur_tx : &e_data.outlines_color_tx;
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.outline_resolve_aa_sh, psl->outlines_resolve);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx);
+ DRW_shgroup_uniform_vec2(grp, "rcpDimensions", e_data.inv_viewport_size, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
+ /* Grid pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND;
+ psl->grid = DRW_pass_create("Infinite Grid Pass", state);
+
+ struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get();
+ static float mat[4][4];
+ unit_m4(mat);
+
+ /* Create 3 quads to render ordered transparency Z axis */
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zneg_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.zplane_normal, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1);
+ DRW_shgroup_uniform_vec3(grp, "cameraPos", e_data.camera_pos, 1);
+ DRW_shgroup_uniform_vec4(grp, "screenvecs[0]", e_data.screenvecs[0], 3);
+ DRW_shgroup_uniform_vec4(grp, "gridSettings", e_data.grid_settings, 1);
+ DRW_shgroup_uniform_float(grp, "gridOneOverLogSubdiv", &e_data.grid_settings[4], 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, quad, mat);
+
+ grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.grid_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.grid_normal, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.grid_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, quad, mat);
+
+ grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
+ DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zpos_flag, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.zplane_normal, 1);
+ DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
+ DRW_shgroup_call_add(grp, quad, mat);
+ }
+
+ {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ psl->bone_solid = DRW_pass_create("Bone Solid Pass", state);
+ psl->bone_outline = DRW_pass_create("Bone Outline Pass", state);
+ }
+
+ {
+ /* Wire bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ psl->bone_wire = DRW_pass_create("Bone Wire Pass", state);
+ }
+
+ {
+ /* distance outline around envelope bones */
+ DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_FRONT;
+ psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WIRE;
+ psl->bone_axes = DRW_pass_create("Bone Axes Pass", state);
+ }
+
+ {
+ /* Non Meshes Pass (Camera, empties, lamps ...) */
+ struct Gwn_Batch *geom;
+
+ DRWState state =
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND | DRW_STATE_POINT;
+ state |= DRW_STATE_WIRE;
+ psl->non_meshes = DRW_pass_create("Non Meshes Pass", state);
+
+ /* Empties */
+ geom = DRW_cache_plain_axes_get();
+ stl->g_data->plain_axes = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_cube_get();
+ stl->g_data->cube = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_circle_get();
+ stl->g_data->circle = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_empty_sphere_get();
+ stl->g_data->sphere = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_empty_cone_get();
+ stl->g_data->cone = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_arrow_get();
+ stl->g_data->single_arrow = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ stl->g_data->single_arrow_line = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_arrows_get();
+ stl->g_data->arrows = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_axis_names_get();
+ stl->g_data->axis_names = shgroup_instance_axis_names(psl->non_meshes, geom);
+
+ /* initialize on first use */
+ stl->g_data->image_plane_map = NULL;
+
+ /* Force Field */
+ geom = DRW_cache_field_wind_get();
+ stl->g_data->field_wind = shgroup_instance_scaled(psl->non_meshes, geom);
+
+ geom = DRW_cache_field_force_get();
+ stl->g_data->field_force = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+
+ geom = DRW_cache_field_vortex_get();
+ stl->g_data->field_vortex = shgroup_instance_scaled(psl->non_meshes, geom);
+
+ geom = DRW_cache_screenspace_circle_get();
+ stl->g_data->field_curve_sta = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+
+ /* Speaker */
+ geom = DRW_cache_speaker_get();
+ stl->g_data->speaker = shgroup_instance(psl->non_meshes, geom);
+
+ /* Probe */
+ static float probeSize = 14.0f;
+ geom = DRW_cache_lightprobe_cube_get();
+ stl->g_data->probe_cube = shgroup_instance_screenspace(psl->non_meshes, geom, &probeSize);
+
+ geom = DRW_cache_lightprobe_grid_get();
+ stl->g_data->probe_grid = shgroup_instance_screenspace(psl->non_meshes, geom, &probeSize);
+
+ static float probePlanarSize = 20.0f;
+ geom = DRW_cache_lightprobe_planar_get();
+ stl->g_data->probe_planar = shgroup_instance_screenspace(psl->non_meshes, geom, &probePlanarSize);
+
+ /* Camera */
+ geom = DRW_cache_camera_get();
+ stl->g_data->camera = shgroup_camera_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_camera_frame_get();
+ stl->g_data->camera_frame = shgroup_camera_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_camera_tria_get();
+ stl->g_data->camera_tria = shgroup_camera_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_plain_axes_get();
+ stl->g_data->camera_focus = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ stl->g_data->camera_clip = shgroup_distance_lines_instance(psl->non_meshes, geom);
+ stl->g_data->camera_mist = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_endpoints_get();
+ stl->g_data->camera_clip_points = shgroup_distance_lines_instance(psl->non_meshes, geom);
+ stl->g_data->camera_mist_points = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ /* Texture Space */
+ geom = DRW_cache_cube_get();
+ stl->g_data->texspace = shgroup_instance(psl->non_meshes, geom);
+ }
+
+ {
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* Unselected */
+ stl->g_data->wire = shgroup_wire(psl->non_meshes, ts.colorWire, sh);
+
+ /* Select */
+ stl->g_data->wire_select = shgroup_wire(psl->non_meshes, ts.colorSelect, sh);
+
+ /* Transform */
+ stl->g_data->wire_transform = shgroup_wire(psl->non_meshes, ts.colorTransform, sh);
+
+ /* Active */
+ stl->g_data->wire_active = shgroup_wire(psl->non_meshes, ts.colorActive, sh);
+ }
+
+
+ {
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
+
+ /* Unselected */
+ stl->g_data->points = shgroup_points(psl->non_meshes, ts.colorWire, sh);
+
+ /* Select */
+ stl->g_data->points_select = shgroup_points(psl->non_meshes, ts.colorSelect, sh);
+
+ /* Transform */
+ stl->g_data->points_transform = shgroup_points(psl->non_meshes, ts.colorTransform, sh);
+
+ /* Active */
+ stl->g_data->points_active = shgroup_points(psl->non_meshes, ts.colorActive, sh);
+ }
+
+ {
+ /* Metaballs Handles */
+ stl->g_data->mball_handle = shgroup_instance_mball_handles(psl->non_meshes);
+ }
+
+ {
+ /* Lamps */
+ /* TODO
+ * for now we create multiple times the same VBO with only lamp center coordinates
+ * but ideally we would only create it once */
+ struct Gwn_Batch *geom;
+
+ /* start with buflimit because we don't want stipples */
+ geom = DRW_cache_single_line_get();
+ stl->g_data->lamp_buflimit = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ stl->g_data->lamp_center = shgroup_dynpoints_uniform_color(psl->non_meshes, ts.colorLampNoAlpha, &ts.sizeLampCenter);
+
+ geom = DRW_cache_lamp_get();
+ stl->g_data->lamp_circle = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircle);
+ geom = DRW_cache_lamp_shadows_get();
+ stl->g_data->lamp_circle_shadow = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircleShadow);
+
+ geom = DRW_cache_lamp_sunrays_get();
+ stl->g_data->lamp_sunrays = shgroup_instance_screenspace(psl->non_meshes, geom, &ts.sizeLampCircle);
+
+ stl->g_data->lamp_groundline = shgroup_groundlines_uniform_color(psl->non_meshes, ts.colorLamp);
+ stl->g_data->lamp_groundpoint = shgroup_groundpoints_uniform_color(psl->non_meshes, ts.colorLamp);
+
+ geom = DRW_cache_screenspace_circle_get();
+ stl->g_data->lamp_area_sphere = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_area_square_get();
+ stl->g_data->lamp_area_square = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_area_disk_get();
+ stl->g_data->lamp_area_disk = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_hemi_get();
+ stl->g_data->lamp_hemi = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_get();
+ stl->g_data->lamp_distance = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_single_line_endpoints_get();
+ stl->g_data->lamp_buflimit_points = shgroup_distance_lines_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_spot_get();
+ stl->g_data->lamp_spot_cone = shgroup_spot_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_circle_get();
+ stl->g_data->lamp_spot_blend = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_lamp_spot_square_get();
+ stl->g_data->lamp_spot_pyramid = shgroup_instance(psl->non_meshes, geom);
+
+ geom = DRW_cache_square_get();
+ stl->g_data->lamp_spot_blend_rect = shgroup_instance(psl->non_meshes, geom);
+ }
+
+ {
+ /* -------- STIPPLES ------- */
+ struct Gwn_Batch *geom;
+
+ /* Relationship Lines */
+ stl->g_data->relationship_lines = shgroup_dynlines_dashed_uniform_color(psl->non_meshes, ts.colorWire);
+
+ /* Force Field Curve Guide End (here because of stipple) */
+ /* TODO port to shader stipple */
+ geom = DRW_cache_screenspace_circle_get();
+ stl->g_data->field_curve_end = shgroup_instance_screen_aligned(psl->non_meshes, geom);
+
+ /* Force Field Limits */
+ /* TODO port to shader stipple */
+ geom = DRW_cache_field_tube_limit_get();
+ stl->g_data->field_tube_limit = shgroup_instance_scaled(psl->non_meshes, geom);
+
+ /* TODO port to shader stipple */
+ geom = DRW_cache_field_cone_limit_get();
+ stl->g_data->field_cone_limit = shgroup_instance_scaled(psl->non_meshes, geom);
+ }
+
+ {
+ /* Object Center pass grouped by State */
+ DRWShadingGroup *grp;
+ static float outlineWidth, size;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_POINT;
+ psl->ob_center = DRW_pass_create("Obj Center Pass", state);
+
+ outlineWidth = 1.0f * U.pixelsize;
+ size = U.obcenter_dia * U.pixelsize + outlineWidth;
+
+ GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+
+ /* Active */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_float(grp, "size", &size, 1);
+ DRW_shgroup_uniform_float(grp, "outlineWidth", &outlineWidth, 1);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorActive, 1);
+ DRW_shgroup_uniform_vec4(grp, "outlineColor", ts.colorOutline, 1);
+ stl->g_data->center_active = grp;
+
+ /* Select */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorSelect, 1);
+ stl->g_data->center_selected = grp;
+
+ /* Deselect */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorDeselect, 1);
+ stl->g_data->center_deselected = grp;
+
+ /* Select (library) */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorLibrarySelect, 1);
+ stl->g_data->center_selected_lib = grp;
+
+ /* Deselect (library) */
+ grp = DRW_shgroup_point_batch_create(sh, psl->ob_center);
+ DRW_shgroup_uniform_vec4(grp, "color", ts.colorLibrary, 1);
+ stl->g_data->center_deselected_lib = grp;
+ }
+
+ {
+ /* Particle Pass */
+ psl->particle = DRW_pass_create(
+ "Particle Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_POINT | DRW_STATE_BLEND);
+ }
+
+ {
+ /* Empty/Background Image Pass */
+ psl->reference_image = DRW_pass_create(
+ "Refrence Image Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+ }
+}
+
+static void DRW_shgroup_mball_handles(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer)
+{
+ MetaBall *mb = ob->data;
+
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ float draw_scale_xform[3][4]; /* Matrix of Scale and Translation */
+ {
+ float scamat[3][3];
+ copy_m3_m4(scamat, ob->obmat);
+ /* Get the normalized inverse matrix to extract only
+ * the scale of Scamat */
+ float iscamat[3][3];
+ invert_m3_m3(iscamat, scamat);
+ normalize_m3(iscamat);
+ mul_m3_m3_post(scamat, iscamat);
+
+ copy_v3_v3(draw_scale_xform[0], scamat[0]);
+ copy_v3_v3(draw_scale_xform[1], scamat[1]);
+ copy_v3_v3(draw_scale_xform[2], scamat[2]);
+ }
+
+ for (MetaElem *ml = mb->elems.first; ml != NULL; ml = ml->next) {
+ /* draw radius */
+ float world_pos[3];
+ mul_v3_m4v3(world_pos, ob->obmat, &ml->x);
+ draw_scale_xform[0][3] = world_pos[0];
+ draw_scale_xform[1][3] = world_pos[1];
+ draw_scale_xform[2][3] = world_pos[2];
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->mball_handle, draw_scale_xform, &ml->rad, color);
+ }
+}
+
+static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer)
+{
+ Lamp *la = ob->data;
+ float *color;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
+ static float zero = 0.0f;
+
+ typedef struct LampEngineData {
+ ObjectEngineData engine_data;
+ float shape_mat[4][4];
+ float spot_blend_mat[4][4];
+ } LampEngineData;
+
+ LampEngineData *lamp_engine_data =
+ (LampEngineData *)DRW_object_engine_data_ensure(
+ ob,
+ &draw_engine_object_type,
+ sizeof(LampEngineData),
+ NULL,
+ NULL);
+
+ float (*shapemat)[4] = lamp_engine_data->shape_mat;
+ float (*spotblendmat)[4] = lamp_engine_data->spot_blend_mat;
+
+ /* Don't draw the center if it's selected or active */
+ if (theme_id == TH_LAMP)
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_center, ob->obmat[3]);
+
+ /* First circle */
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_circle, ob->obmat[3], color);
+
+ /* draw dashed outer circle for shadow */
+ if (la->type != LA_HEMI) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_circle_shadow, ob->obmat[3], color);
+ }
+
+ /* Distance */
+ if (ELEM(la->type, LA_HEMI, LA_SUN, LA_AREA)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_distance, color, &zero, &la->dist, ob->obmat);
+ }
+
+ copy_m4_m4(shapemat, ob->obmat);
+
+ if (la->type == LA_SUN) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_sunrays, ob->obmat[3], color);
+ }
+ else if (la->type == LA_SPOT) {
+ float size[3], sizemat[4][4];
+ static float one = 1.0f;
+ float blend = 1.0f - pow2f(la->spotblend);
+
+ size[0] = size[1] = sinf(la->spotsize * 0.5f) * la->dist;
+ size[2] = cosf(la->spotsize * 0.5f) * la->dist;
+
+ size_to_mat4(sizemat, size);
+ mul_m4_m4m4(shapemat, ob->obmat, sizemat);
+
+ size[0] = size[1] = blend; size[2] = 1.0f;
+ size_to_mat4(sizemat, size);
+ translate_m4(sizemat, 0.0f, 0.0f, -1.0f);
+ rotate_m4(sizemat, 'X', (float)(M_PI / 2));
+ mul_m4_m4m4(spotblendmat, shapemat, sizemat);
+
+ if (la->mode & LA_SQUARE) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_spot_pyramid, color, &one, shapemat);
+
+ /* hide line if it is zero size or overlaps with outer border,
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
+ if (blend != 0.0f && blend != 1.0f) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_spot_blend_rect, color, &one, spotblendmat);
+ }
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_spot_cone, color, shapemat);
+
+ /* hide line if it is zero size or overlaps with outer border,
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
+ if (blend != 0.0f && blend != 1.0f) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_spot_blend, color, &one, spotblendmat);
+ }
+ }
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_buflimit, color, &la->clipsta, &la->clipend, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_buflimit_points, color, &la->clipsta, &la->clipend, ob->obmat);
+ }
+ else if (la->type == LA_HEMI) {
+ static float hemisize = 2.0f;
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_hemi, color, &hemisize, shapemat);
+ }
+ else if (la->type == LA_AREA) {
+ float size[3] = {1.0f, 1.0f, 1.0f}, sizemat[4][4];
+
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) {
+ size[1] = la->area_sizey / la->area_size;
+ size_to_mat4(sizemat, size);
+ mul_m4_m4m4(shapemat, shapemat, sizemat);
+ }
+
+ if (ELEM(la->area_shape, LA_AREA_DISK, LA_AREA_ELLIPSE)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_area_disk, color, &la->area_size, shapemat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_area_square, color, &la->area_size, shapemat);
+ }
+ }
+
+ if (ELEM(la->type, LA_LOCAL, LA_SPOT)) {
+ /* We only want position not scale. */
+ shapemat[0][0] = shapemat[1][1] = shapemat[2][2] = 1.0f;
+ shapemat[0][1] = shapemat[0][2] = 0.0f;
+ shapemat[1][0] = shapemat[1][2] = 0.0f;
+ shapemat[2][0] = shapemat[2][1] = 0.0f;
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_area_sphere, color, &la->area_size, shapemat);
+ }
+
+ /* Line and point going to the ground */
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_groundline, ob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_groundpoint, ob->obmat[3]);
+}
+
+static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Scene *scene = draw_ctx->scene;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
+ Camera *cam = ob->data;
+ const Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera);
+ const bool is_active = (ob == camera_object);
+ const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB));
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ float vec[4][3], asp[2], shift[2], scale[3], drawsize;
+
+ scale[0] = 1.0f / len_v3(ob->obmat[0]);
+ scale[1] = 1.0f / len_v3(ob->obmat[1]);
+ scale[2] = 1.0f / len_v3(ob->obmat[2]);
+
+ BKE_camera_view_frame_ex(scene, cam, cam->drawsize, false, scale,
+ asp, shift, &drawsize, vec);
+
+ /* Frame coords */
+ copy_v2_v2(cam->drwcorners[0], vec[0]);
+ copy_v2_v2(cam->drwcorners[1], vec[1]);
+ copy_v2_v2(cam->drwcorners[2], vec[2]);
+ copy_v2_v2(cam->drwcorners[3], vec[3]);
+
+ /* depth */
+ cam->drwdepth = vec[0][2];
+
+ /* tria */
+ cam->drwtria[0][0] = shift[0] + ((0.7f * drawsize) * scale[0]);
+ cam->drwtria[0][1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]);
+ cam->drwtria[1][0] = shift[0];
+ cam->drwtria[1][1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]);
+
+ if (look_through) {
+ /* Only draw the frame. */
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_frame, color, cam->drwcorners,
+ &cam->drwdepth, cam->drwtria, ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera, color, cam->drwcorners,
+ &cam->drwdepth, cam->drwtria, ob->obmat);
+
+ /* Active cam */
+ if (is_active) {
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_tria, color,
+ cam->drwcorners, &cam->drwdepth, cam->drwtria, ob->obmat);
+ }
+ }
+
+ /* draw the rest in normalize object space */
+ copy_m4_m4(cam->drwnormalmat, ob->obmat);
+ normalize_m4(cam->drwnormalmat);
+
+ if (cam->flag & CAM_SHOWLIMITS) {
+ static float col[3] = {0.5f, 0.5f, 0.25f}, col_hi[3] = {1.0f, 1.0f, 0.5f};
+ float sizemat[4][4], size[3] = {1.0f, 1.0f, 0.0f};
+ float focusdist = BKE_camera_object_dof_distance(ob);
+
+ copy_m4_m4(cam->drwfocusmat, cam->drwnormalmat);
+ translate_m4(cam->drwfocusmat, 0.0f, 0.0f, -focusdist);
+ size_to_mat4(sizemat, size);
+ mul_m4_m4m4(cam->drwfocusmat, cam->drwfocusmat, sizemat);
+
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_focus, (is_active ? col_hi : col),
+ &cam->drawsize, cam->drwfocusmat);
+
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_clip, color,
+ &cam->clipsta, &cam->clipend, cam->drwnormalmat);
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_clip_points, (is_active ? col_hi : col),
+ &cam->clipsta, &cam->clipend, cam->drwnormalmat);
+ }
+
+ if (cam->flag & CAM_SHOWMIST) {
+ World *world = scene->world;
+
+ if (world) {
+ static float col[3] = {0.5f, 0.5f, 0.5f}, col_hi[3] = {1.0f, 1.0f, 1.0f};
+ world->mistend = world->miststa + world->mistdist;
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_mist, color,
+ &world->miststa, &world->mistend, cam->drwnormalmat);
+ DRW_shgroup_call_dynamic_add(
+ stl->g_data->camera_mist_points, (is_active ? col_hi : col),
+ &world->miststa, &world->mistend, cam->drwnormalmat);
+ }
+ }
+}
+
+static void DRW_shgroup_empty(OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, ViewLayer *view_layer)
+{
+ float *color;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ switch (ob->empty_drawtype) {
+ case OB_PLAINAXES:
+ DRW_shgroup_call_dynamic_add(stl->g_data->plain_axes, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_SINGLE_ARROW:
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow, color, &ob->empty_drawsize, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow_line, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_CUBE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_CIRCLE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->circle, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_EMPTY_SPHERE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->sphere, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_EMPTY_CONE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->cone, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_ARROWS:
+ DRW_shgroup_call_dynamic_add(stl->g_data->arrows, color, &ob->empty_drawsize, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->axis_names, color, &ob->empty_drawsize, ob->obmat);
+ break;
+ case OB_EMPTY_IMAGE:
+ DRW_shgroup_empty_image(stl, psl, ob, color);
+ break;
+ }
+}
+
+static void DRW_shgroup_forcefield(OBJECT_StorageList *stl, 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;
+
+ /* TODO Move this to depsgraph */
+ float tmp[3];
+ copy_v3_fl(pd->drawvec1, ob->empty_drawsize);
+
+ switch (pd->forcefield) {
+ case PFIELD_WIND:
+ pd->drawvec1[2] = pd->f_strength;
+ break;
+ case PFIELD_VORTEX:
+ if (pd->f_strength < 0.0f) {
+ pd->drawvec1[1] = -pd->drawvec1[1];
+ }
+ break;
+ case PFIELD_GUIDE:
+ if (cu && (cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) {
+ where_on_path(ob, 0.0f, pd->drawvec1, tmp, NULL, NULL, NULL);
+ where_on_path(ob, 1.0f, pd->drawvec2, tmp, NULL, NULL, NULL);
+ }
+ break;
+ }
+
+ if (pd->falloff == PFIELD_FALL_TUBE) {
+ pd->drawvec_falloff_max[0] = pd->drawvec_falloff_max[1] = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f;
+ pd->drawvec_falloff_max[2] = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+
+ pd->drawvec_falloff_min[0] = pd->drawvec_falloff_min[1] = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f;
+ pd->drawvec_falloff_min[2] = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+ }
+ else if (pd->falloff == PFIELD_FALL_CONE) {
+ float radius, distance;
+
+ radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f);
+ distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f;
+ pd->drawvec_falloff_max[0] = pd->drawvec_falloff_max[1] = distance * sinf(radius);
+ pd->drawvec_falloff_max[2] = distance * cosf(radius);
+
+ radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f);
+ distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f;
+
+ pd->drawvec_falloff_min[0] = pd->drawvec_falloff_min[1] = distance * sinf(radius);
+ pd->drawvec_falloff_min[2] = distance * cosf(radius);
+ }
+ /* End of things that should go to depthgraph */
+
+ switch (pd->forcefield) {
+ case PFIELD_WIND:
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_wind, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_FORCE:
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_force, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_VORTEX:
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_vortex, color, &pd->drawvec1, ob->obmat);
+ break;
+ case PFIELD_GUIDE:
+ if (cu && (cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_curve_sta, color, &pd->f_strength, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_curve_end, color, &pd->f_strength, ob->obmat);
+ }
+ break;
+ }
+
+ if (pd->falloff == PFIELD_FALL_SPHERE) {
+ /* as last, guide curve alters it */
+ if ((pd->flag & PFIELD_USEMAX) != 0) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_curve_end, color, &pd->maxdist, ob->obmat);
+ }
+
+ if ((pd->flag & PFIELD_USEMIN) != 0) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_curve_end, color, &pd->mindist, ob->obmat);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_TUBE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_tube_limit, color, &pd->drawvec_falloff_max, ob->obmat);
+ }
+
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_tube_limit, color, &pd->drawvec_falloff_min, ob->obmat);
+ }
+ }
+ else if (pd->falloff == PFIELD_FALL_CONE) {
+ if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_cone_limit, color, &pd->drawvec_falloff_max, ob->obmat);
+ }
+
+ if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->field_cone_limit, color, &pd->drawvec_falloff_min, ob->obmat);
+ }
+ }
+}
+
+static void DRW_shgroup_speaker(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer)
+{
+ float *color;
+ static float one = 1.0f;
+ DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->speaker, color, &one, ob->obmat);
+}
+
+typedef struct OBJECT_LightProbeEngineData {
+ ObjectEngineData engine_data;
+
+ float prb_mats[6][4][4];
+ float probe_cube_mat[4][4];
+ float draw_size;
+ float increment_x[3];
+ float increment_y[3];
+ float increment_z[3];
+ float corner[3];
+ uint cell_count;
+} OBJECT_LightProbeEngineData;
+
+static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, ViewLayer *view_layer)
+{
+ float *color;
+ static float one = 1.0f;
+ LightProbe *prb = (LightProbe *)ob->data;
+ bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0);
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
+
+ OBJECT_LightProbeEngineData *prb_data =
+ (OBJECT_LightProbeEngineData *)DRW_object_engine_data_ensure(
+ ob,
+ &draw_engine_object_type,
+ sizeof(OBJECT_LightProbeEngineData),
+ NULL,
+ NULL);
+
+ if ((DRW_state_is_select() || do_outlines) && ((prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) != 0)) {
+ int *call_id = shgroup_theme_id_to_probe_outline_counter(stl, theme_id);
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ /* 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(prb_data->corner, -1.0f);
+ add_v3_v3(prb_data->corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, prb_data->corner);
+
+ /* Opposite neighbor cell. */
+ copy_v3_fl3(prb_data->increment_x, cell_dim[0], 0.0f, 0.0f);
+ add_v3_v3(prb_data->increment_x, half_cell_dim);
+ add_v3_fl(prb_data->increment_x, -1.0f);
+ mul_m4_v3(ob->obmat, prb_data->increment_x);
+ sub_v3_v3(prb_data->increment_x, prb_data->corner);
+
+ copy_v3_fl3(prb_data->increment_y, 0.0f, cell_dim[1], 0.0f);
+ add_v3_v3(prb_data->increment_y, half_cell_dim);
+ add_v3_fl(prb_data->increment_y, -1.0f);
+ mul_m4_v3(ob->obmat, prb_data->increment_y);
+ sub_v3_v3(prb_data->increment_y, prb_data->corner);
+
+ copy_v3_fl3(prb_data->increment_z, 0.0f, 0.0f, cell_dim[2]);
+ add_v3_v3(prb_data->increment_z, half_cell_dim);
+ add_v3_fl(prb_data->increment_z, -1.0f);
+ mul_m4_v3(ob->obmat, prb_data->increment_z);
+ sub_v3_v3(prb_data->increment_z, prb_data->corner);
+
+ prb_data->cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.lightprobe_grid_sh, psl->lightprobes);
+ DRW_shgroup_uniform_int_copy(grp, "call_id", *call_id);
+ DRW_shgroup_uniform_int(grp, "baseId", call_id, 1); /* that's correct */
+ DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_y", prb_data->increment_y, 1);
+ DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1);
+ DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1);
+ DRW_shgroup_uniform_float(grp, "sphere_size", &prb->data_draw_size, 1);
+ DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, &prb_data->cell_count);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ prb_data->draw_size = prb->data_draw_size * 0.1f;
+ unit_m4(prb_data->probe_cube_mat);
+ copy_v3_v3(prb_data->probe_cube_mat[3], ob->obmat[3]);
+
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_cube_outline_shgrp(stl, theme_id);
+ DRW_shgroup_call_dynamic_add(grp, call_id, &prb_data->draw_size, prb_data->probe_cube_mat);
+ }
+ else {
+ prb_data->draw_size = 1.0f;
+
+ DRWShadingGroup *grp = shgroup_theme_id_to_probe_planar_outline_shgrp(stl, theme_id);
+ DRW_shgroup_call_dynamic_add(grp, call_id, &prb_data->draw_size, ob->obmat);
+ }
+
+ *call_id += 1;
+ }
+
+ switch (prb->type) {
+ case LIGHTPROBE_TYPE_PLANAR:
+ DRW_shgroup_call_dynamic_add(stl->g_data->probe_planar, ob->obmat[3], color);
+ break;
+ case LIGHTPROBE_TYPE_GRID:
+ DRW_shgroup_call_dynamic_add(stl->g_data->probe_grid, ob->obmat[3], color);
+ break;
+ case LIGHTPROBE_TYPE_CUBE:
+ default:
+ DRW_shgroup_call_dynamic_add(stl->g_data->probe_cube, ob->obmat[3], color);
+ break;
+ }
+
+
+
+ if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
+ float (*mat)[4];
+ mat = (float (*)[4])(prb_data->prb_mats[0]);
+ copy_m4_m4(mat, ob->obmat);
+ normalize_m4(mat);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow, color, &ob->empty_drawsize, mat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->single_arrow_line, color, &ob->empty_drawsize, mat);
+
+ mat = (float (*)[4])(prb_data->prb_mats[1]);
+ copy_m4_m4(mat, ob->obmat);
+ zero_v3(mat[2]);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &one, mat);
+ }
+
+ if ((prb->flag & LIGHTPROBE_FLAG_SHOW_INFLUENCE) != 0) {
+
+ prb->distfalloff = (1.0f - prb->falloff) * prb->distinf;
+ prb->distgridinf = prb->distinf;
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ prb->distfalloff += 1.0f;
+ prb->distgridinf += 1.0f;
+ }
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID ||
+ prb->attenuation_type == LIGHTPROBE_SHAPE_BOX)
+ {
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &prb->distgridinf, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &prb->distfalloff, ob->obmat);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR) {
+ float (*rangemat)[4];
+ rangemat = (float (*)[4])(prb_data->prb_mats[2]);
+ copy_m4_m4(rangemat, ob->obmat);
+ normalize_v3(rangemat[2]);
+ mul_v3_fl(rangemat[2], prb->distinf);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &one, rangemat);
+
+ rangemat = (float (*)[4])(prb_data->prb_mats[3]);
+ copy_m4_m4(rangemat, ob->obmat);
+ normalize_v3(rangemat[2]);
+ mul_v3_fl(rangemat[2], prb->distfalloff);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, &one, rangemat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->sphere, color, &prb->distgridinf, ob->obmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->sphere, color, &prb->distfalloff, ob->obmat);
+ }
+ }
+
+ if ((prb->flag & LIGHTPROBE_FLAG_SHOW_PARALLAX) != 0) {
+ if (prb->type != LIGHTPROBE_TYPE_PLANAR) {
+ float (*obmat)[4], *dist;
+
+ if ((prb->flag & LIGHTPROBE_FLAG_CUSTOM_PARALLAX) != 0) {
+ dist = &prb->distpar;
+ /* TODO object parallax */
+ obmat = ob->obmat;
+ }
+ else {
+ dist = &prb->distinf;
+ obmat = ob->obmat;
+ }
+
+ if (prb->parallax_type == LIGHTPROBE_SHAPE_BOX) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->cube, color, dist, obmat);
+ }
+ else {
+ DRW_shgroup_call_dynamic_add(stl->g_data->sphere, color, dist, obmat);
+ }
+ }
+ }
+
+ if ((prb->flag & LIGHTPROBE_FLAG_SHOW_CLIP_DIST) != 0) {
+ if (prb->type != LIGHTPROBE_TYPE_PLANAR) {
+ static const float cubefacemat[6][4][4] = {
+ {{0.0, 0.0, -1.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{0.0, 0.0, 1.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, -1.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{1.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{1.0, 0.0, 0.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {0.0, 0.0, -1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ {{-1.0, 0.0, 0.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}},
+ };
+
+ for (int i = 0; i < 6; ++i) {
+ float (*clipmat)[4];
+ clipmat = (float (*)[4])(prb_data->prb_mats[i]);
+
+ normalize_m4_m4(clipmat, ob->obmat);
+ mul_m4_m4m4(clipmat, clipmat, cubefacemat[i]);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_buflimit, color, &prb->clipsta, &prb->clipend, clipmat);
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_buflimit_points, color, &prb->clipsta, &prb->clipend, clipmat);
+ }
+ }
+ }
+
+ /* Line and point going to the ground */
+ if (prb->type == LIGHTPROBE_TYPE_CUBE) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_groundline, ob->obmat[3]);
+ DRW_shgroup_call_dynamic_add(stl->g_data->lamp_groundpoint, ob->obmat[3]);
+ }
+}
+
+static void DRW_shgroup_relationship_lines(OBJECT_StorageList *stl, Object *ob)
+{
+ if (ob->parent && DRW_check_object_visible_within_active_context(ob->parent)) {
+ /* Only draw relationship lines when object or its parent are selected
+ * as a way of reducing visual clutter.
+ */
+ if ((ob->base_flag & BASE_SELECTED) || (ob->parent->base_flag & BASE_SELECTED)) {
+ DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->parent->obmat[3]);
+ DRW_shgroup_call_dynamic_add(stl->g_data->relationship_lines, ob->obmat[3]);
+ }
+ }
+}
+
+static void DRW_shgroup_object_center(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer, View3D *v3d)
+{
+ const bool is_library = ob->id.us > 1 || ID_IS_LINKED(ob);
+ DRWShadingGroup *shgroup;
+
+ if (ob == OBACT(view_layer)) {
+ shgroup = stl->g_data->center_active;
+ }
+ else if (ob->base_flag & BASE_SELECTED) {
+ if (is_library) {
+ shgroup = stl->g_data->center_selected_lib;
+ }
+ else {
+ shgroup = stl->g_data->center_selected;
+ }
+ }
+ else if (v3d->flag & V3D_DRAW_CENTERS) {
+ if (is_library) {
+ shgroup = stl->g_data->center_deselected_lib;
+ }
+ else {
+ shgroup = stl->g_data->center_deselected;
+ }
+ }
+ else {
+ return;
+ }
+
+ DRW_shgroup_call_dynamic_add(shgroup, ob->obmat[3]);
+}
+
+static void DRW_shgroup_texture_space(OBJECT_StorageList *stl, Object *ob, int theme_id)
+{
+ if (ob->data == NULL) {
+ return;
+ }
+
+ ID *ob_data = ob->data;
+ float *texcoloc = NULL;
+ float *texcosize = NULL;
+ if (ob->data != NULL) {
+ switch (GS(ob_data->name)) {
+ case ID_ME:
+ BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize);
+ break;
+ case ID_CU:
+ {
+ Curve *cu = (Curve *)ob_data;
+ if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(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 tmp[4][4] = {{0.0f}}, one = 1.0f;
+ tmp[0][0] = texcosize[0];
+ tmp[1][1] = texcosize[1];
+ tmp[2][2] = texcosize[2];
+ tmp[3][0] = texcoloc[0];
+ tmp[3][1] = texcoloc[1];
+ tmp[3][2] = texcoloc[2];
+ tmp[3][3] = 1.0f;
+
+ mul_m4_m4m4(tmp, ob->obmat, tmp);
+
+ float color[4];
+ UI_GetThemeColor4fv(theme_id, color);
+
+ DRW_shgroup_call_dynamic_add(stl->g_data->texspace, color, &one, tmp);
+}
+
+static void OBJECT_cache_populate_particles(Object *ob,
+ OBJECT_PassList *psl)
+{
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ if (!psys_check_enabled(ob, psys, false)) {
+ continue;
+ }
+ if (!DRW_check_psys_visible_within_active_context(ob, psys)) {
+ continue;
+ }
+
+ ParticleSettings *part = psys->part;
+ int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ static float mat[4][4];
+ unit_m4(mat);
+
+ if (draw_as != PART_DRAW_PATH) {
+ struct Gwn_Batch *geom = DRW_cache_particles_get_dots(ob, psys);
+ DRWShadingGroup *shgrp = NULL;
+ static int screen_space[2] = {0, 1};
+ static float def_prim_col[3] = {0.5f, 0.5f, 0.5f};
+ static float def_sec_col[3] = {1.0f, 1.0f, 1.0f};
+
+ /* Dummy particle format for instancing to work. */
+ DRW_shgroup_instance_format(e_data.particle_format, {{"dummy", DRW_ATTRIB_FLOAT, 1}});
+
+ Material *ma = give_current_material(ob, part->omat);
+
+ switch (draw_as) {
+ case PART_DRAW_DOT:
+ shgrp = DRW_shgroup_create(e_data.part_dot_sh, psl->particle);
+ DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "outlineColor", ma ? &ma->specr : def_sec_col, 1);
+ DRW_shgroup_uniform_float(shgrp, "pixel_size", DRW_viewport_pixelsize_get(), 1);
+ DRW_shgroup_uniform_float(shgrp, "size", &part->draw_size, 1);
+ DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
+ DRW_shgroup_call_add(shgrp, geom, mat);
+ break;
+ case PART_DRAW_CROSS:
+ shgrp = DRW_shgroup_instance_create(
+ e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CROSS),
+ e_data.particle_format);
+ DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
+ DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
+ DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1);
+ break;
+ case PART_DRAW_CIRC:
+ shgrp = DRW_shgroup_instance_create(
+ e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CIRC),
+ e_data.particle_format);
+ DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp);
+ DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1);
+ DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[1], 1);
+ break;
+ case PART_DRAW_AXIS:
+ shgrp = DRW_shgroup_instance_create(
+ e_data.part_axis_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_AXIS),
+ e_data.particle_format);
+ DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1);
+ break;
+ default:
+ break;
+ }
+
+ if (shgrp) {
+ if (draw_as != PART_DRAW_DOT) {
+ DRW_shgroup_uniform_float(shgrp, "draw_size", &part->draw_size, 1);
+ DRW_shgroup_instance_batch(shgrp, geom);
+ }
+ }
+ }
+ }
+}
+
+static void OBJECT_cache_populate(void *vedata, Object *ob)
+{
+ OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
+ OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ View3D *v3d = draw_ctx->v3d;
+ int theme_id = TH_UNDEFINED;
+
+ /* Handle particles first in case the emitter itself shouldn't be rendered. */
+ if (ob->type == OB_MESH) {
+ OBJECT_cache_populate_particles(ob, psl);
+ }
+
+ if (DRW_check_object_visible_within_active_context(ob) == false) {
+ return;
+ }
+
+ bool do_outlines = (draw_ctx->v3d->flag & V3D_SELECT_OUTLINE) && ((ob->base_flag & BASE_SELECTED) != 0);
+ bool show_relations = ((draw_ctx->v3d->flag & V3D_HIDE_HELPLINES) == 0);
+
+ if (do_outlines) {
+ if ((ob != draw_ctx->object_edit) && !((ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT))) {
+ struct Gwn_Batch *geom;
+ const bool xray_enabled = ((v3d->shading.flag & V3D_SHADING_XRAY) != 0) &&
+ (v3d->drawtype < OB_MATERIAL);
+ if (xray_enabled) {
+ geom = DRW_cache_object_edge_detection_get(ob, NULL);
+ }
+ else {
+ geom = DRW_cache_object_surface_get(ob);
+ }
+ if (geom) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_outline_or(stl, theme_id, NULL);
+ if (shgroup != NULL) {
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ }
+ }
+ }
+
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ if (ob != draw_ctx->object_edit) {
+ Mesh *me = ob->data;
+ if (me->totedge == 0) {
+ struct Gwn_Batch *geom = DRW_cache_mesh_verts_get(ob);
+ if (geom) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_point_or(stl, theme_id, stl->g_data->points);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ }
+ else {
+ struct Gwn_Batch *geom = DRW_cache_mesh_loose_edges_get(ob);
+ if (geom) {
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ }
+ }
+ break;
+ }
+ case OB_SURF:
+ break;
+ case OB_LATTICE:
+ {
+ if (ob != draw_ctx->object_edit) {
+ struct Gwn_Batch *geom = DRW_cache_lattice_wire_get(ob, false);
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ break;
+ }
+
+ case OB_CURVE:
+ {
+ if (ob != draw_ctx->object_edit) {
+ struct Gwn_Batch *geom = DRW_cache_curve_edge_wire_get(ob);
+ if (theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+ DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire);
+ DRW_shgroup_call_object_add(shgroup, geom, ob);
+ }
+ break;
+ }
+ case OB_MBALL:
+ {
+ if (ob != draw_ctx->object_edit) {
+ DRW_shgroup_mball_handles(stl, ob, view_layer);
+ }
+ break;
+ }
+ case OB_LAMP:
+ DRW_shgroup_lamp(stl, ob, view_layer);
+ break;
+ case OB_CAMERA:
+ DRW_shgroup_camera(stl, ob, view_layer);
+ break;
+ case OB_EMPTY:
+ DRW_shgroup_empty(stl, psl, ob, view_layer);
+ break;
+ case OB_SPEAKER:
+ DRW_shgroup_speaker(stl, ob, view_layer);
+ break;
+ case OB_LIGHTPROBE:
+ DRW_shgroup_lightprobe(stl, psl, ob, view_layer);
+ break;
+ case OB_ARMATURE:
+ {
+ bArmature *arm = ob->data;
+ if (arm->edbo == NULL) {
+ if (DRW_state_is_select() || !DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+ DRWArmaturePasses passes = {
+ .bone_solid = psl->bone_solid,
+ .bone_outline = psl->bone_outline,
+ .bone_wire = psl->bone_wire,
+ .bone_envelope = psl->bone_envelope,
+ .bone_axes = psl->bone_axes,
+ .relationship_lines = NULL, /* Don't draw relationship lines */
+ };
+ DRW_shgroup_armature_object(ob, view_layer, passes);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (ob->pd && ob->pd->forcefield) {
+ DRW_shgroup_forcefield(stl, ob, view_layer);
+ }
+
+ /* don't show object extras in set's */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROMDUPLI)) == 0) {
+
+ DRW_shgroup_object_center(stl, ob, view_layer, v3d);
+
+ if (show_relations) {
+ DRW_shgroup_relationship_lines(stl, ob);
+ }
+
+ if ((ob->dtx != 0) && theme_id == TH_UNDEFINED) {
+ theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ }
+
+ if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+
+ unsigned char 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, DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, color);
+ }
+
+ if ((ob->dtx & OB_TEXSPACE) && ELEM(ob->type, OB_MESH, OB_CURVE, OB_MBALL)) {
+ DRW_shgroup_texture_space(stl, ob, theme_id);
+ }
+ }
+}
+
+static void OBJECT_draw_scene(void *vedata)
+{
+
+ OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl;
+ OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl;
+ OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl;
+ OBJECT_PrivateData *g_data = stl->g_data;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ int id_ct_select = g_data->id_ofs_select;
+ int id_ct_active = g_data->id_ofs_active;
+ int id_ct_transform = g_data->id_ofs_transform;
+
+ int id_ct_prb_select = g_data->id_ofs_prb_select;
+ int id_ct_prb_active = g_data->id_ofs_prb_active;
+ int id_ct_prb_transform = g_data->id_ofs_prb_transform;
+
+ int outline_calls = id_ct_select + id_ct_active + id_ct_transform;
+ outline_calls += id_ct_prb_select + id_ct_prb_active + id_ct_prb_transform;
+
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+// DRW_draw_pass(psl->bone_envelope); /* Never drawn in Object mode currently. */
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl)
+
+ /* This needs to be drawn after the oultine */
+ DRW_draw_pass(psl->bone_solid);
+ DRW_draw_pass(psl->bone_wire);
+ DRW_draw_pass(psl->bone_outline);
+ DRW_draw_pass(psl->non_meshes);
+ DRW_draw_pass(psl->particle);
+ DRW_draw_pass(psl->reference_image);
+ DRW_draw_pass(psl->bone_axes);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+
+ if (DRW_state_is_fbo() && outline_calls > 0) {
+ DRW_stats_group_start("Outlines");
+
+ g_data->id_ofs_active = 1;
+ g_data->id_ofs_select = g_data->id_ofs_active + id_ct_active + id_ct_prb_active + 1;
+ g_data->id_ofs_transform = g_data->id_ofs_select + id_ct_select + id_ct_prb_select + 1;
+
+ g_data->id_ofs_prb_active = g_data->id_ofs_active + id_ct_active;
+ g_data->id_ofs_prb_select = g_data->id_ofs_select + id_ct_select;
+ g_data->id_ofs_prb_transform = g_data->id_ofs_transform + id_ct_transform;
+
+ /* Render filled polygon on a separate framebuffer */
+ GPU_framebuffer_bind(fbl->outlines_fb);
+ GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f);
+ DRW_draw_pass(psl->outlines);
+ DRW_draw_pass(psl->lightprobes);
+
+ /* Search outline pixels */
+ GPU_framebuffer_bind(fbl->blur_fb);
+ DRW_draw_pass(psl->outlines_search);
+
+ /* Expand outline to form a 3px wide line */
+ GPU_framebuffer_bind(fbl->expand_fb);
+ DRW_draw_pass(psl->outlines_expand);
+
+ /* Bleed color so the AA can do it's stuff */
+ GPU_framebuffer_bind(fbl->blur_fb);
+ DRW_draw_pass(psl->outlines_bleed);
+
+ /* restore main framebuffer */
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_stats_group_end();
+ }
+ else if (DRW_state_is_select()) {
+ /* Render probes spheres/planes so we can select them. */
+ DRW_draw_pass(psl->lightprobes);
+ }
+
+ DRW_draw_pass(psl->ob_center);
+
+ if (DRW_state_is_fbo()) {
+ if (e_data.draw_grid) {
+ GPU_framebuffer_bind(dfbl->color_only_fb);
+ DRW_draw_pass(psl->grid);
+ }
+
+ /* Combine with scene buffer last */
+ if (outline_calls > 0) {
+ DRW_draw_pass(psl->outlines_resolve);
+ }
+ }
+
+ /* This has to be freed only after drawing empties! */
+ if (stl->g_data->image_plane_map) {
+ BLI_ghash_free(stl->g_data->image_plane_map, NULL, MEM_freeN);
+ stl->g_data->image_plane_map = NULL;
+ }
+}
+
+static const DrawEngineDataSize OBJECT_data_size = DRW_VIEWPORT_DATA_SIZE(OBJECT_Data);
+
+DrawEngineType draw_engine_object_type = {
+ NULL, NULL,
+ N_("ObjectMode"),
+ &OBJECT_data_size,
+ &OBJECT_engine_init,
+ &OBJECT_engine_free,
+ &OBJECT_cache_init,
+ &OBJECT_cache_populate,
+ NULL,
+ NULL,
+ &OBJECT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/overlay_mode.c b/source/blender/draw/modes/overlay_mode.c
new file mode 100644
index 00000000000..97403b14ac5
--- /dev/null
+++ b/source/blender/draw/modes/overlay_mode.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file overlay_mode.c
+ * \ingroup draw_engine
+ */
+
+#include "DNA_view3d_types.h"
+
+#include "BKE_object.h"
+
+#include "GPU_shader.h"
+#include "GPU_extensions.h"
+#include "DRW_render.h"
+
+#include "draw_mode_engines.h"
+
+/* Structures */
+typedef struct OVERLAY_StorageList {
+ struct OVERLAY_PrivateData *g_data;
+} OVERLAY_StorageList;
+
+typedef struct OVERLAY_PassList {
+ struct DRWPass *face_orientation_pass;
+ struct DRWPass *face_wireframe_pass;
+} OVERLAY_PassList;
+
+typedef struct OVERLAY_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ OVERLAY_PassList *psl;
+ OVERLAY_StorageList *stl;
+} OVERLAY_Data;
+
+typedef struct OVERLAY_PrivateData {
+ GPUShader *wire_sh; /* reference */
+ DRWShadingGroup *face_orientation_shgrp;
+ View3DOverlay overlay;
+ float wire_step_param[2];
+} OVERLAY_PrivateData; /* Transient data */
+
+/* *********** STATIC *********** */
+static struct {
+ /* Face orientation shader */
+ struct GPUShader *face_orientation_sh;
+ /* Wireframe shader */
+ struct GPUShader *face_wireframe_sh;
+ struct GPUShader *face_wireframe_pretty_sh;
+} e_data = {NULL};
+
+/* Shaders */
+extern char datatoc_overlay_face_orientation_frag_glsl[];
+extern char datatoc_overlay_face_orientation_vert_glsl[];
+
+extern char datatoc_overlay_face_wireframe_vert_glsl[];
+extern char datatoc_overlay_face_wireframe_geom_glsl[];
+extern char datatoc_overlay_face_wireframe_frag_glsl[];
+
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* Functions */
+static void overlay_engine_init(void *vedata)
+{
+ OVERLAY_Data * data = (OVERLAY_Data *)vedata;
+ OVERLAY_StorageList *stl = data->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ if (!e_data.face_orientation_sh) {
+ /* Face orientation */
+ e_data.face_orientation_sh = DRW_shader_create(
+ datatoc_overlay_face_orientation_vert_glsl, NULL,
+ datatoc_overlay_face_orientation_frag_glsl, NULL);
+ }
+
+ if (!e_data.face_wireframe_sh) {
+ bool use_geom = GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY);
+
+ e_data.face_wireframe_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ use_geom ? "#define USE_GEOM_SHADER\n"
+ : NULL);
+
+ e_data.face_wireframe_pretty_sh = DRW_shader_create(
+ datatoc_overlay_face_wireframe_vert_glsl,
+ use_geom ? datatoc_overlay_face_wireframe_geom_glsl : NULL,
+ datatoc_overlay_face_wireframe_frag_glsl,
+ use_geom ? "#define USE_GEOM_SHADER\n"
+ "#define LIGHT_EDGES\n"
+ : "#define LIGHT_EDGES\n");
+ }
+}
+
+static void overlay_cache_init(void *vedata)
+{
+ OVERLAY_Data * data = (OVERLAY_Data *)vedata;
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_StorageList *stl = data->stl;
+
+ const DRWContextState *DCS = DRW_context_state_get();
+
+ View3D *v3d = DCS->v3d;
+ if (v3d) {
+ stl->g_data->overlay = v3d->overlay;
+ }
+ else {
+ memset(&stl->g_data->overlay, 0, sizeof(stl->g_data->overlay));
+ }
+
+ /* Face Orientation Pass */
+ if (stl->g_data->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND;
+ psl->face_orientation_pass = DRW_pass_create("Face Orientation", state);
+ stl->g_data->face_orientation_shgrp = DRW_shgroup_create(
+ e_data.face_orientation_sh, psl->face_orientation_pass);
+ }
+ if (stl->g_data->overlay.flag & V3D_OVERLAY_WIREFRAMES) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ psl->face_wireframe_pass = DRW_pass_create("Face Wires", state);
+ /* Sticky uniforms (don't need to respecify each time since shader does not change). */
+ stl->g_data->wire_sh = (stl->g_data->overlay.wireframe_threshold == 1.0f) ? e_data.face_wireframe_sh
+ : e_data.face_wireframe_pretty_sh;
+ DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass);
+ DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
+ DRW_shgroup_uniform_vec2(shgrp, "wireStepParam", stl->g_data->wire_step_param, 1);
+
+ /**
+ * The wireframe threshold ranges from 0.0 to 1.0
+ * When 1.0 we show all the edges, when 0.5 we show as many as 2.7.
+ *
+ * If we wanted 0.0 to match 2.7, factor would need to be 0.003f.
+ * The range controls the falloff effect. If range was 0.0f we would get a hard cut (as in 2.7).
+ * That said we are using a different algorithm so the results will always differ.
+ */
+ const float factor = 0.0045f;
+ const float range = 0.00125f;
+ stl->g_data->wire_step_param[1] = (1.0f - factor) + stl->g_data->overlay.wireframe_threshold * factor;
+ stl->g_data->wire_step_param[0] = stl->g_data->wire_step_param[1] + range;
+ }
+}
+
+static void overlay_cache_populate(void *vedata, Object *ob)
+{
+ OVERLAY_Data * data = (OVERLAY_Data *)vedata;
+ OVERLAY_StorageList *stl = data->stl;
+ OVERLAY_PrivateData *pd = stl->g_data;
+ OVERLAY_PassList *psl = data->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (!DRW_object_is_renderable(ob))
+ return;
+
+ if (stl->g_data->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) {
+ struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ DRW_shgroup_call_add(pd->face_orientation_shgrp, geom, ob->obmat);
+ }
+ }
+
+ if (stl->g_data->overlay.flag & V3D_OVERLAY_WIREFRAMES) {
+ /* Don't do that in edit mode. */
+ if ((ob != draw_ctx->object_edit) && !BKE_object_is_in_editmode(ob)) {
+ int tri_count;
+ GPUTexture *verts = NULL, *faceids;
+ DRW_cache_object_face_wireframe_get(ob, &verts, &faceids, &tri_count);
+ if (verts) {
+ float *rim_col = ts.colorWire;
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ rim_col = (ob == draw_ctx->obact) ? ts.colorActive : ts.colorSelect;
+ }
+ DRWShadingGroup *shgrp = DRW_shgroup_create(stl->g_data->wire_sh, psl->face_wireframe_pass);
+ DRW_shgroup_uniform_texture(shgrp, "vertData", verts);
+ DRW_shgroup_uniform_texture(shgrp, "faceIds", faceids);
+ DRW_shgroup_uniform_vec3(shgrp, "wireColor", ts.colorWire, 1);
+ DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
+ DRW_shgroup_call_object_procedural_triangles_culled_add(shgrp, tri_count, ob);
+ }
+ }
+ }
+}
+
+static void overlay_cache_finish(void *UNUSED(vedata))
+{
+}
+
+static void overlay_draw_scene(void *vedata)
+{
+ OVERLAY_Data * data = (OVERLAY_Data *)vedata;
+ OVERLAY_PassList *psl = data->psl;
+ OVERLAY_StorageList *stl = data->stl;
+ OVERLAY_PrivateData *pd = stl->g_data;
+
+ if (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) {
+ DRW_draw_pass(psl->face_orientation_pass);
+ }
+ if (pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) {
+ DRW_draw_pass(psl->face_wireframe_pass);
+ }
+}
+
+static void overlay_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.face_orientation_sh);
+ DRW_SHADER_FREE_SAFE(e_data.face_wireframe_sh);
+ DRW_SHADER_FREE_SAFE(e_data.face_wireframe_pretty_sh);
+}
+
+static const DrawEngineDataSize overlay_data_size = DRW_VIEWPORT_DATA_SIZE(OVERLAY_Data);
+
+DrawEngineType draw_engine_overlay_type = {
+ NULL, NULL,
+ N_("OverlayEngine"),
+ &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,
+};
+
diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c
new file mode 100644
index 00000000000..85cff28b313
--- /dev/null
+++ b/source/blender/draw/modes/paint_texture_mode.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/paint_texture_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "BIF_gl.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "DNA_mesh_types.h"
+
+extern char datatoc_common_globals_lib_glsl[];
+extern char datatoc_paint_texture_vert_glsl[];
+extern char datatoc_paint_texture_frag_glsl[];
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_paint_wire_frag_glsl[];
+
+/* If needed, contains all global/Theme colors
+ * Add needed theme colors / values to DRW_globals_update() and update UBO
+ * Not needed for constant color. */
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use PAINT_TEXTURE_engine_init() to
+ * initialize most of them and PAINT_TEXTURE_cache_init()
+ * for PAINT_TEXTURE_PassList */
+
+typedef struct PAINT_TEXTURE_PassList {
+ /* Declare all passes here and init them in
+ * PAINT_TEXTURE_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *image_faces;
+
+ struct DRWPass *wire_overlay;
+ struct DRWPass *face_overlay;
+} PAINT_TEXTURE_PassList;
+
+typedef struct PAINT_TEXTURE_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} PAINT_TEXTURE_FramebufferList;
+
+typedef struct PAINT_TEXTURE_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} PAINT_TEXTURE_TextureList;
+
+typedef struct PAINT_TEXTURE_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct PAINT_TEXTURE_PrivateData *g_data;
+} PAINT_TEXTURE_StorageList;
+
+typedef struct PAINT_TEXTURE_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ PAINT_TEXTURE_FramebufferList *fbl;
+ PAINT_TEXTURE_TextureList *txl;
+ PAINT_TEXTURE_PassList *psl;
+ PAINT_TEXTURE_StorageList *stl;
+} PAINT_TEXTURE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in PAINT_TEXTURE_engine_init();
+ * free in PAINT_TEXTURE_engine_free(); */
+ struct GPUShader *fallback_sh;
+ struct GPUShader *image_sh;
+
+ struct GPUShader *wire_overlay_shader;
+ struct GPUShader *face_overlay_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PAINT_TEXTURE_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in PAINT_TEXTURE_cache_populate() */
+ DRWShadingGroup *shgroup_fallback;
+ DRWShadingGroup **shgroup_image_array;
+
+ /* face-mask */
+ DRWShadingGroup *lwire_shgrp;
+ DRWShadingGroup *face_shgrp;
+} PAINT_TEXTURE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void PAINT_TEXTURE_engine_init(void *vedata)
+{
+ PAINT_TEXTURE_TextureList *txl = ((PAINT_TEXTURE_Data *)vedata)->txl;
+ PAINT_TEXTURE_FramebufferList *fbl = ((PAINT_TEXTURE_Data *)vedata)->fbl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.fallback_sh) {
+ e_data.fallback_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+ if (!e_data.image_sh) {
+ e_data.image_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ e_data.image_sh = DRW_shader_create_with_lib(
+ datatoc_paint_texture_vert_glsl, NULL,
+ datatoc_paint_texture_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+
+ }
+
+ if (!e_data.wire_overlay_shader) {
+ e_data.wire_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_wire_frag_glsl,
+ datatoc_common_globals_lib_glsl,
+ "#define VERTEX_MODE\n");
+ }
+
+ if (!e_data.face_overlay_shader) {
+ e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void PAINT_TEXTURE_cache_init(void *vedata)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ stl->g_data->shgroup_image_array = NULL;
+ }
+
+ {
+ /* Create a pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND;
+ psl->image_faces = DRW_pass_create("Image Color Pass", state);
+
+ stl->g_data->shgroup_fallback = DRW_shgroup_create(e_data.fallback_sh, psl->image_faces);
+
+ /* Uniforms need a pointer to it's value so be sure it's accessible at
+ * any given time (i.e. use static vars) */
+ static float color[4] = {1.0f, 0.0f, 1.0f, 1.0};
+ DRW_shgroup_uniform_vec4(stl->g_data->shgroup_fallback, "color", color, 1);
+
+ MEM_SAFE_FREE(stl->g_data->shgroup_image_array);
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Object *ob = draw_ctx->obact;
+ if (ob && ob->type == OB_MESH) {
+ Scene *scene = draw_ctx->scene;
+ const bool use_material_slots = (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
+ const Mesh *me = ob->data;
+
+ stl->g_data->shgroup_image_array = MEM_mallocN(
+ sizeof(*stl->g_data->shgroup_image_array) * (use_material_slots ? me->totcol : 1), __func__);
+
+ if (use_material_slots) {
+ for (int i = 0; i < me->totcol; i++) {
+ Material *ma = give_current_material(ob, i + 1);
+ Image *ima = (ma && ma->texpaintslot) ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+ GPUTexture *tex = ima ?
+ GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, 0.0f) : NULL;
+
+ if (tex) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
+ stl->g_data->shgroup_image_array[i] = grp;
+ }
+ else {
+ stl->g_data->shgroup_image_array[i] = NULL;
+ }
+ }
+ }
+ else {
+ Image *ima = scene->toolsettings->imapaint.canvas;
+ GPUTexture *tex = ima ?
+ GPU_texture_from_blender(ima, NULL, GL_TEXTURE_2D, false, 0.0f) : NULL;
+
+ if (tex) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.image_sh, psl->image_faces);
+ DRW_shgroup_uniform_texture(grp, "image", tex);
+ DRW_shgroup_uniform_float(grp, "alpha", &draw_ctx->v3d->overlay.texture_paint_mode_opacity, 1);
+ stl->g_data->shgroup_image_array[0] = grp;
+ }
+ else {
+ stl->g_data->shgroup_image_array[0] = NULL;
+ }
+ }
+ }
+ }
+
+ /* Face Mask */
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->face_shgrp = DRW_shgroup_create(e_data.face_overlay_shader, psl->face_overlay);
+
+ static float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+ DRW_shgroup_uniform_vec4(stl->g_data->face_shgrp, "color", col, 1);
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void PAINT_TEXTURE_cache_populate(void *vedata, Object *ob)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ UNUSED_VARS(psl, stl);
+
+ if ((ob->type == OB_MESH) && (draw_ctx->obact == ob)) {
+ /* Get geometry cache */
+ const Mesh *me = ob->data;
+ Scene *scene = draw_ctx->scene;
+ const bool use_surface = draw_ctx->v3d->overlay.texture_paint_mode_opacity != 0.0; //DRW_object_is_mode_shade(ob) == true;
+ const bool use_material_slots = (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
+ bool ok = false;
+
+ if (use_surface) {
+ if (me->mloopuv != NULL) {
+ if (use_material_slots) {
+ struct Gwn_Batch **geom_array = me->totcol ? DRW_cache_mesh_surface_texpaint_get(ob) : NULL;
+ if ((me->totcol == 0) || (geom_array == NULL)) {
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat);
+ ok = true;
+ }
+ else {
+ for (int i = 0; i < me->totcol; i++) {
+ if (stl->g_data->shgroup_image_array[i]) {
+ DRW_shgroup_call_add(stl->g_data->shgroup_image_array[i], geom_array[i], ob->obmat);
+ }
+ else {
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom_array[i], ob->obmat);
+ }
+ ok = true;
+ }
+ }
+ }
+ else {
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob);
+ if (geom && stl->g_data->shgroup_image_array[0]) {
+ DRW_shgroup_call_add(stl->g_data->shgroup_image_array[0], geom, ob->obmat);
+ ok = true;
+ }
+ }
+ }
+
+ if (!ok) {
+ struct Gwn_Batch *geom = DRW_cache_mesh_surface_get(ob);
+ DRW_shgroup_call_add(stl->g_data->shgroup_fallback, geom, ob->obmat);
+ }
+ }
+
+ /* Face Mask */
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ if (use_face_sel) {
+ struct Gwn_Batch *geom;
+ /* Note: ideally selected faces wouldn't show interior wire. */
+ const bool use_wire = true;
+ geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat);
+
+ geom = DRW_cache_mesh_faces_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void PAINT_TEXTURE_cache_finish(void *vedata)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_StorageList *stl = ((PAINT_TEXTURE_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl);
+
+ MEM_SAFE_FREE(stl->g_data->shgroup_image_array);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void PAINT_TEXTURE_draw_scene(void *vedata)
+{
+ PAINT_TEXTURE_PassList *psl = ((PAINT_TEXTURE_Data *)vedata)->psl;
+ PAINT_TEXTURE_FramebufferList *fbl = ((PAINT_TEXTURE_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl, dfbl, dtxl);
+
+ DRW_draw_pass(psl->image_faces);
+
+ DRW_draw_pass(psl->face_overlay);
+ DRW_draw_pass(psl->wire_overlay);
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void PAINT_TEXTURE_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.image_sh);
+ DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader);
+}
+
+static const DrawEngineDataSize PAINT_TEXTURE_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_TEXTURE_Data);
+
+DrawEngineType draw_engine_paint_texture_type = {
+ NULL, NULL,
+ N_("PaintTextureMode"),
+ &PAINT_TEXTURE_data_size,
+ &PAINT_TEXTURE_engine_init,
+ &PAINT_TEXTURE_engine_free,
+ &PAINT_TEXTURE_cache_init,
+ &PAINT_TEXTURE_cache_populate,
+ &PAINT_TEXTURE_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &PAINT_TEXTURE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c
new file mode 100644
index 00000000000..9cf6ea52d33
--- /dev/null
+++ b/source/blender/draw/modes/paint_vertex_mode.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/paint_vertex_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_paint_vertex_vert_glsl[];
+extern char datatoc_paint_vertex_frag_glsl[];
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_paint_wire_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+/* *********** LISTS *********** */
+
+typedef struct PAINT_VERTEX_PassList {
+ struct DRWPass *vcolor_faces;
+ struct DRWPass *wire_overlay;
+ struct DRWPass *face_overlay;
+} PAINT_VERTEX_PassList;
+
+typedef struct PAINT_VERTEX_StorageList {
+ struct PAINT_VERTEX_PrivateData *g_data;
+} PAINT_VERTEX_StorageList;
+
+typedef struct PAINT_VERTEX_Data {
+ void *engine_type; /* Required */
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ PAINT_VERTEX_PassList *psl;
+ PAINT_VERTEX_StorageList *stl;
+} PAINT_VERTEX_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ struct GPUShader *vcolor_face_shader;
+ struct GPUShader *wire_overlay_shader;
+ struct GPUShader *face_overlay_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PAINT_VERTEX_PrivateData {
+ DRWShadingGroup *fvcolor_shgrp;
+ DRWShadingGroup *lwire_shgrp;
+ DRWShadingGroup *face_shgrp;
+} PAINT_VERTEX_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+static void PAINT_VERTEX_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.vcolor_face_shader) {
+ e_data.vcolor_face_shader = DRW_shader_create(
+ datatoc_paint_vertex_vert_glsl, NULL,
+ datatoc_paint_vertex_frag_glsl, NULL);
+
+ e_data.wire_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_wire_frag_glsl,
+ datatoc_common_globals_lib_glsl, "#define VERTEX_MODE\n");
+
+ e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+static void PAINT_VERTEX_cache_init(void *vedata)
+{
+ PAINT_VERTEX_PassList *psl = ((PAINT_VERTEX_Data *)vedata)->psl;
+ PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ psl->vcolor_faces = DRW_pass_create(
+ "Vert Color Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->fvcolor_shgrp = DRW_shgroup_create(e_data.vcolor_face_shader, psl->vcolor_faces);
+ DRW_shgroup_uniform_float(stl->g_data->fvcolor_shgrp, "alpha", &v3d->overlay.vertex_paint_mode_opacity, 1);
+ }
+
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->face_shgrp = DRW_shgroup_create(e_data.face_overlay_shader, psl->face_overlay);
+
+ static float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+ DRW_shgroup_uniform_vec4(stl->g_data->face_shgrp, "color", col, 1);
+ }
+}
+
+static void PAINT_VERTEX_cache_populate(void *vedata, Object *ob)
+{
+ PAINT_VERTEX_StorageList *stl = ((PAINT_VERTEX_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) {
+ const Mesh *me = ob->data;
+ const bool use_wire = (v3d->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
+ const bool use_surface = v3d->overlay.vertex_paint_mode_opacity != 0.0f;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ struct Gwn_Batch *geom;
+
+ if (use_surface) {
+ geom = DRW_cache_mesh_surface_vert_colors_get(ob);
+ DRW_shgroup_call_add(stl->g_data->fvcolor_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel || use_wire) {
+ geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_faces_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+static void PAINT_VERTEX_draw_scene(void *vedata)
+{
+ PAINT_VERTEX_PassList *psl = ((PAINT_VERTEX_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->vcolor_faces);
+ DRW_draw_pass(psl->face_overlay);
+ DRW_draw_pass(psl->wire_overlay);
+}
+
+static void PAINT_VERTEX_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.vcolor_face_shader);
+ DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader);
+}
+
+static const DrawEngineDataSize PAINT_VERTEX_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_VERTEX_Data);
+
+DrawEngineType draw_engine_paint_vertex_type = {
+ NULL, NULL,
+ N_("PaintVertexMode"),
+ &PAINT_VERTEX_data_size,
+ &PAINT_VERTEX_engine_init,
+ &PAINT_VERTEX_engine_free,
+ &PAINT_VERTEX_cache_init,
+ &PAINT_VERTEX_cache_populate,
+ NULL,
+ NULL,
+ &PAINT_VERTEX_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c
new file mode 100644
index 00000000000..2b510a9a4c9
--- /dev/null
+++ b/source/blender/draw/modes/paint_weight_mode.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/paint_weight_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_mesh.h"
+
+extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */
+extern struct GlobalsUboStorage ts; /* draw_common.c */
+
+extern char datatoc_paint_wire_vert_glsl[];
+extern char datatoc_paint_wire_frag_glsl[];
+extern char datatoc_paint_vert_frag_glsl[];
+extern char datatoc_common_globals_lib_glsl[];
+
+/* *********** LISTS *********** */
+
+typedef struct PAINT_WEIGHT_PassList {
+ struct DRWPass *weight_faces;
+ struct DRWPass *wire_overlay;
+ struct DRWPass *face_overlay;
+ struct DRWPass *vert_overlay;
+} PAINT_WEIGHT_PassList;
+
+typedef struct PAINT_WEIGHT_StorageList {
+ struct PAINT_WEIGHT_PrivateData *g_data;
+} PAINT_WEIGHT_StorageList;
+
+typedef struct PAINT_WEIGHT_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ PAINT_WEIGHT_PassList *psl;
+ PAINT_WEIGHT_StorageList *stl;
+} PAINT_WEIGHT_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ struct GPUShader *weight_face_shader;
+ struct GPUShader *wire_overlay_shader;
+ struct GPUShader *face_overlay_shader;
+ struct GPUShader *vert_overlay_shader;
+ int actdef;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PAINT_WEIGHT_PrivateData {
+ DRWShadingGroup *fweights_shgrp;
+ DRWShadingGroup *lwire_shgrp;
+ DRWShadingGroup *face_shgrp;
+ DRWShadingGroup *vert_shgrp;
+} PAINT_WEIGHT_PrivateData;
+
+/* *********** FUNCTIONS *********** */
+
+static void PAINT_WEIGHT_engine_init(void *UNUSED(vedata))
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (e_data.actdef != draw_ctx->obact->actdef) {
+ e_data.actdef = draw_ctx->obact->actdef;
+
+ BKE_mesh_batch_cache_dirty(draw_ctx->obact->data, BKE_MESH_BATCH_DIRTY_ALL);
+ }
+
+ if (!e_data.weight_face_shader) {
+ e_data.weight_face_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA);
+ }
+
+ if (!e_data.wire_overlay_shader) {
+ e_data.wire_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_wire_frag_glsl,
+ datatoc_common_globals_lib_glsl, "#define WEIGHT_MODE\n");
+ }
+
+ if (!e_data.face_overlay_shader) {
+ e_data.face_overlay_shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+
+ if (!e_data.vert_overlay_shader) {
+ e_data.vert_overlay_shader = DRW_shader_create_with_lib(
+ datatoc_paint_wire_vert_glsl, NULL,
+ datatoc_paint_vert_frag_glsl,
+ datatoc_common_globals_lib_glsl, NULL);
+ }
+}
+
+static void PAINT_WEIGHT_cache_init(void *vedata)
+{
+ PAINT_WEIGHT_PassList *psl = ((PAINT_WEIGHT_Data *)vedata)->psl;
+ PAINT_WEIGHT_StorageList *stl = ((PAINT_WEIGHT_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ psl->weight_faces = DRW_pass_create(
+ "Weight Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->fweights_shgrp = DRW_shgroup_create(e_data.weight_face_shader, psl->weight_faces);
+
+ static float light[3] = {-0.3f, 0.5f, 1.0f};
+ static float world_light = 1.0f;
+ DRW_shgroup_uniform_vec3(stl->g_data->fweights_shgrp, "light", light, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fweights_shgrp, "alpha", &v3d->overlay.weight_paint_mode_opacity, 1);
+ DRW_shgroup_uniform_float(stl->g_data->fweights_shgrp, "global", &world_light, 1);
+ }
+
+ {
+ psl->wire_overlay = DRW_pass_create(
+ "Wire Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->lwire_shgrp = DRW_shgroup_create(e_data.wire_overlay_shader, psl->wire_overlay);
+ }
+
+ {
+ psl->face_overlay = DRW_pass_create(
+ "Face Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND);
+
+ stl->g_data->face_shgrp = DRW_shgroup_create(e_data.face_overlay_shader, psl->face_overlay);
+
+ static float col[4] = {1.0f, 1.0f, 1.0f, 0.2f};
+ DRW_shgroup_uniform_vec4(stl->g_data->face_shgrp, "color", col, 1);
+ }
+
+ {
+ psl->vert_overlay = DRW_pass_create(
+ "Vert Mask Pass",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL);
+
+ stl->g_data->vert_shgrp = DRW_shgroup_create(e_data.vert_overlay_shader, psl->vert_overlay);
+ }
+}
+
+static void PAINT_WEIGHT_cache_populate(void *vedata, Object *ob)
+{
+ PAINT_WEIGHT_StorageList *stl = ((PAINT_WEIGHT_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+
+ if ((ob->type == OB_MESH) && (ob == draw_ctx->obact)) {
+ const Mesh *me = ob->data;
+ const bool use_wire = (v3d->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
+ const bool use_surface = v3d->overlay.weight_paint_mode_opacity != 0.0f;
+ const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+ const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ struct Gwn_Batch *geom;
+
+ if (use_surface) {
+ geom = DRW_cache_mesh_surface_weights_get(ob);
+ DRW_shgroup_call_add(stl->g_data->fweights_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel || use_wire) {
+ geom = DRW_cache_mesh_edges_paint_overlay_get(ob, use_wire, use_face_sel);
+ DRW_shgroup_call_add(stl->g_data->lwire_shgrp, geom, ob->obmat);
+ }
+
+ if (use_face_sel) {
+ geom = DRW_cache_mesh_faces_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->face_shgrp, geom, ob->obmat);
+ }
+
+ if (use_vert_sel) {
+ geom = DRW_cache_mesh_verts_weight_overlay_get(ob);
+ DRW_shgroup_call_add(stl->g_data->vert_shgrp, geom, ob->obmat);
+ }
+ }
+}
+
+static void PAINT_WEIGHT_draw_scene(void *vedata)
+{
+ PAINT_WEIGHT_PassList *psl = ((PAINT_WEIGHT_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->weight_faces);
+ DRW_draw_pass(psl->face_overlay);
+ DRW_draw_pass(psl->wire_overlay);
+ DRW_draw_pass(psl->vert_overlay);
+}
+
+static void PAINT_WEIGHT_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.wire_overlay_shader);
+ DRW_SHADER_FREE_SAFE(e_data.vert_overlay_shader);
+}
+
+static const DrawEngineDataSize PAINT_WEIGHT_data_size = DRW_VIEWPORT_DATA_SIZE(PAINT_WEIGHT_Data);
+
+DrawEngineType draw_engine_paint_weight_type = {
+ NULL, NULL,
+ N_("PaintWeightMode"),
+ &PAINT_WEIGHT_data_size,
+ &PAINT_WEIGHT_engine_init,
+ &PAINT_WEIGHT_engine_free,
+ &PAINT_WEIGHT_cache_init,
+ &PAINT_WEIGHT_cache_populate,
+ NULL,
+ NULL,
+ &PAINT_WEIGHT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
new file mode 100644
index 00000000000..19c3ddd4b50
--- /dev/null
+++ b/source/blender/draw/modes/particle_mode.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/particle_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+
+#include "GPU_shader.h"
+#include "GPU_batch.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+#include "ED_particle.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "draw_cache_impl.h"
+
+extern char datatoc_particle_strand_vert_glsl[];
+extern char datatoc_particle_strand_frag_glsl[];
+
+/* *********** LISTS *********** */
+
+typedef struct PARTICLE_PassList {
+ struct DRWPass *psys_edit_pass;
+} PARTICLE_PassList;
+
+typedef struct PARTICLE_FramebufferList {
+ struct GPUFrameBuffer *fb;
+} PARTICLE_FramebufferList;
+
+typedef struct PARTICLE_TextureList {
+ struct GPUTexture *texture;
+} PARTICLE_TextureList;
+
+typedef struct PARTICLE_StorageList {
+ struct CustomStruct *block;
+ struct PARTICLE_PrivateData *g_data;
+} PARTICLE_StorageList;
+
+typedef struct PARTICLE_Data {
+ void *engine_type; /* Required */
+ PARTICLE_FramebufferList *fbl;
+ PARTICLE_TextureList *txl;
+ PARTICLE_PassList *psl;
+ PARTICLE_StorageList *stl;
+} PARTICLE_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ struct GPUShader *strands_shader;
+ struct GPUShader *points_shader;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct PARTICLE_PrivateData {
+ DRWShadingGroup *strands_group;
+ DRWShadingGroup *inner_points_group;
+ DRWShadingGroup *tip_points_group;
+} PARTICLE_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+static void particle_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.strands_shader) {
+ e_data.strands_shader = DRW_shader_create(
+ datatoc_particle_strand_vert_glsl,
+ NULL,
+ datatoc_particle_strand_frag_glsl,
+ "");
+ }
+ if (!e_data.points_shader) {
+ e_data.points_shader = GPU_shader_get_builtin_shader(
+ GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+ }
+}
+
+static void particle_cache_init(void *vedata)
+{
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+ PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ /* Create a pass */
+ psl->psys_edit_pass = DRW_pass_create("PSys Edit Pass",
+ (DRW_STATE_WRITE_COLOR |
+ DRW_STATE_WRITE_DEPTH |
+ DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_WIRE |
+ DRW_STATE_POINT));
+
+ stl->g_data->strands_group = DRW_shgroup_create(
+ e_data.strands_shader, psl->psys_edit_pass);
+ stl->g_data->inner_points_group = DRW_shgroup_create(
+ e_data.points_shader, psl->psys_edit_pass);
+ stl->g_data->tip_points_group = DRW_shgroup_create(
+ e_data.points_shader, psl->psys_edit_pass);
+
+ static float size = 5.0f;
+ static float outline_width = 1.0f;
+ DRW_shgroup_uniform_float(stl->g_data->inner_points_group, "size", &size, 1);
+ DRW_shgroup_uniform_float(stl->g_data->inner_points_group, "outlineWidth", &outline_width, 1);
+ DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "size", &size, 1);
+ DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "outlineWidth", &outline_width, 1);
+}
+
+static void particle_edit_cache_populate(void *vedata,
+ Object *object,
+ ParticleSystem *psys,
+ PTCacheEdit *edit)
+{
+ PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
+ {
+ struct Gwn_Batch *strands =
+ DRW_cache_particles_get_edit_strands(object, psys, edit);
+ DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL);
+ }
+ if (pset->selectmode == SCE_SELECT_POINT) {
+ struct Gwn_Batch *points =
+ DRW_cache_particles_get_edit_inner_points(object, psys, edit);
+ DRW_shgroup_call_add(stl->g_data->inner_points_group, points, NULL);
+ }
+ if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) {
+ struct Gwn_Batch *points =
+ DRW_cache_particles_get_edit_tip_points(object, psys, edit);
+ DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL);
+ }
+}
+
+static void particle_cache_populate(void *vedata, Object *object)
+{
+ if (object->mode != OB_MODE_PARTICLE_EDIT) {
+ return;
+ }
+ 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 *object_orig = DEG_get_original_object(object);
+ PTCacheEdit *edit = PE_create_current(
+ draw_ctx->depsgraph, scene_orig, object_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 = object->particlesystem.first;
+ ParticleSystem *psys_orig = object_orig->particlesystem.first;
+ while (psys_orig != NULL) {
+ if (PE_get_current_from_psys(psys_orig) == edit) {
+ break;
+ }
+ psys = psys->next;
+ psys_orig = psys_orig->next;
+ }
+ if (psys == NULL) {
+ printf("Error getting evaluated particle system for edit.\n");
+ return;
+ }
+ particle_edit_cache_populate(vedata, object, psys, edit);
+}
+
+/* Optional: Post-cache_populate callback */
+static void particle_cache_finish(void *UNUSED(vedata))
+{
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void particle_draw_scene(void *vedata)
+{
+
+ PARTICLE_PassList *psl = ((PARTICLE_Data *)vedata)->psl;
+
+ DRW_draw_pass(psl->psys_edit_pass);
+}
+
+static void particle_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.strands_shader);
+}
+
+static const DrawEngineDataSize particle_data_size =
+ DRW_VIEWPORT_DATA_SIZE(PARTICLE_Data);
+
+DrawEngineType draw_engine_particle_type = {
+ NULL, NULL,
+ N_("Particle Mode"),
+ &particle_data_size,
+ &particle_engine_init,
+ &particle_engine_free,
+ &particle_cache_init,
+ &particle_cache_populate,
+ &particle_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &particle_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c
new file mode 100644
index 00000000000..ad9567cd9c0
--- /dev/null
+++ b/source/blender/draw/modes/pose_mode.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/pose_mode.c
+ * \ingroup draw
+ */
+#include "BKE_modifier.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_view3d_types.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+extern GlobalsUboStorage ts;
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use POSE_engine_init() to
+ * initialize most of them and POSE_cache_init()
+ * for POSE_PassList */
+
+typedef struct POSE_PassList {
+ struct DRWPass *bone_solid;
+ struct DRWPass *bone_outline;
+ struct DRWPass *bone_wire;
+ struct DRWPass *bone_envelope;
+ struct DRWPass *bone_axes;
+ struct DRWPass *relationship;
+ struct DRWPass *bone_selection;
+} POSE_PassList;
+
+typedef struct POSE_StorageList {
+ struct POSE_PrivateData *g_data;
+} POSE_StorageList;
+
+typedef struct POSE_Data {
+ void *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ POSE_PassList *psl;
+ POSE_StorageList *stl;
+} POSE_Data;
+
+/* *********** STATIC *********** */
+
+typedef struct POSE_PrivateData {
+ DRWShadingGroup *bone_selection_shgrp;
+ DRWShadingGroup *bone_selection_invert_shgrp;
+ float blend_color[4];
+ float blend_color_invert[4];
+} POSE_PrivateData; /* Transient data */
+
+static struct {
+ struct GPUShader *bone_selection_sh;
+} e_data = {NULL};
+
+
+/* *********** FUNCTIONS *********** */
+static bool POSE_is_bone_selection_overlay_active(void)
+{
+ const DRWContextState *dcs = DRW_context_state_get();
+ const View3D *v3d = dcs->v3d;
+ return v3d && (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECTION);
+}
+
+static void POSE_engine_init(void *UNUSED(vedata))
+{
+ if (!e_data.bone_selection_sh) {
+ e_data.bone_selection_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ }
+}
+
+static void POSE_engine_free(void)
+{
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void POSE_cache_init(void *vedata)
+{
+ POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
+ POSE_StorageList *stl = ((POSE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+ POSE_PrivateData *ppd = stl->g_data;
+
+ {
+ /* Solid bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
+ psl->bone_solid = DRW_pass_create("Bone Solid Pass", state);
+ }
+
+ {
+ /* Bones Outline */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ psl->bone_outline = DRW_pass_create("Bone Outline Pass", state);
+ }
+
+ {
+ /* Wire bones */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND;
+ psl->bone_wire = DRW_pass_create("Bone Wire Pass", state);
+ }
+
+ {
+ /* distance outline around envelope bones */
+ DRWState state = DRW_STATE_ADDITIVE | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_FRONT;
+ psl->bone_envelope = DRW_pass_create("Bone Envelope Outline Pass", state);
+ }
+
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WIRE_SMOOTH | DRW_STATE_BLEND;
+ psl->bone_axes = DRW_pass_create("Bone Axes Pass", state);
+ }
+
+ {
+ /* Non Meshes Pass (Camera, empties, lamps ...) */
+ DRWState state =
+ DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND | DRW_STATE_WIRE;
+ psl->relationship = DRW_pass_create("Bone Relationship Pass", state);
+ }
+
+ {
+ if (POSE_is_bone_selection_overlay_active()) {
+ copy_v4_fl4(ppd->blend_color, 0.0f, 0.0f, 0.0f, v3d->overlay.bone_selection_alpha);
+ copy_v4_fl4(ppd->blend_color_invert, 0.0f, 0.0f, 0.0f, pow(v3d->overlay.bone_selection_alpha, 4));
+ DRWShadingGroup *grp;
+ psl->bone_selection = DRW_pass_create(
+ "Bone Selection",
+ DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND);
+ grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
+ DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color, 1);
+ stl->g_data->bone_selection_shgrp = grp;
+ grp = DRW_shgroup_create(e_data.bone_selection_sh, psl->bone_selection);
+ DRW_shgroup_uniform_vec4(grp, "color", ppd->blend_color_invert, 1);
+ stl->g_data->bone_selection_invert_shgrp = grp;
+ }
+ }
+}
+
+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 = DRW_pose_mode_armature(ob_arm, draw_ctx->obact);
+ if (!is_active && ob_arm->proxy_from) {
+ is_active = DRW_pose_mode_armature(ob_arm->proxy_from, draw_ctx->obact);
+ }
+ return is_active;
+ }
+ else {
+ Object *ob_mesh_deform = modifiers_isDeformedByMeshDeform(ob);
+ if (ob_mesh_deform) {
+ return POSE_is_driven_by_active_armature(ob_mesh_deform);
+ }
+ }
+ return false;
+}
+
+/* Add geometry to shading groups. Execute for each objects */
+static void POSE_cache_populate(void *vedata, Object *ob)
+{
+ POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
+ POSE_StorageList *stl = ((POSE_Data *)vedata)->stl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ /* In the future this will allow us to implement face manipulators,
+ * and similar functionalities. For now we handle only pose bones. */
+
+ if (ob->type == OB_ARMATURE) {
+ if (DRW_pose_mode_armature(ob, draw_ctx->obact)) {
+ DRWArmaturePasses passes = {
+ .bone_solid = psl->bone_solid,
+ .bone_outline = psl->bone_outline,
+ .bone_wire = psl->bone_wire,
+ .bone_envelope = psl->bone_envelope,
+ .bone_axes = psl->bone_axes,
+ .relationship_lines = psl->relationship,
+ };
+ DRW_shgroup_armature_pose(ob, passes);
+ }
+ }
+ else if (ob->type == OB_MESH &&
+ !DRW_state_is_select() &&
+ POSE_is_bone_selection_overlay_active())
+ {
+ struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob);
+ if (geom) {
+ if (POSE_is_driven_by_active_armature(ob)) {
+ DRW_shgroup_call_object_add(stl->g_data->bone_selection_shgrp, geom, ob);
+ }
+ else {
+ DRW_shgroup_call_object_add(stl->g_data->bone_selection_invert_shgrp, geom, ob);
+ }
+ }
+ }
+}
+
+/**
+ * Return true if armature should be handled by the pose mode engine.
+ */
+bool DRW_pose_mode_armature(Object *ob, Object *active_ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ /* 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;
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void POSE_draw_scene(void *vedata)
+{
+ POSE_PassList *psl = ((POSE_Data *)vedata)->psl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const bool transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0;
+ const bool bone_selection_overlay = POSE_is_bone_selection_overlay_active();
+
+ if (DRW_state_is_select()) {
+ DRW_draw_pass(psl->bone_solid);
+ DRW_draw_pass(psl->bone_wire);
+ return;
+ }
+
+ if (bone_selection_overlay) {
+ GPU_framebuffer_bind(dfbl->default_fb);
+ DRW_draw_pass(psl->bone_selection);
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
+ GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0);
+ GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ DRW_draw_pass(psl->bone_envelope);
+
+ if (transparent_bones) {
+ DRW_pass_state_add(psl->bone_solid, DRW_STATE_BLEND);
+ DRW_pass_state_remove(psl->bone_solid, DRW_STATE_WRITE_DEPTH);
+ DRW_draw_pass(psl->bone_solid);
+ }
+
+ MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl)
+
+ if (!transparent_bones) {
+ DRW_draw_pass(psl->bone_solid);
+ }
+
+ DRW_draw_pass(psl->bone_outline);
+ DRW_draw_pass(psl->bone_wire);
+ DRW_draw_pass(psl->relationship);
+
+ MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl)
+
+ /* Draw axes with linesmooth and outside of multisample buffer. */
+ DRW_draw_pass(psl->bone_axes);
+}
+
+static const DrawEngineDataSize POSE_data_size = DRW_VIEWPORT_DATA_SIZE(POSE_Data);
+
+DrawEngineType draw_engine_pose_type = {
+ NULL, NULL,
+ N_("PoseMode"),
+ &POSE_data_size,
+ &POSE_engine_init,
+ &POSE_engine_free,
+ &POSE_cache_init,
+ &POSE_cache_populate,
+ NULL,
+ NULL,
+ &POSE_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
new file mode 100644
index 00000000000..56b5898a6cf
--- /dev/null
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file blender/draw/modes/sculpt_mode.c
+ * \ingroup draw
+ */
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_pbvh.h"
+#include "BKE_paint.h"
+
+#include "DEG_depsgraph.h"
+
+/* If builtin shaders are needed */
+#include "GPU_shader.h"
+#include "GPU_matrix.h"
+
+#include "draw_common.h"
+
+#include "draw_mode_engines.h"
+
+/* *********** LISTS *********** */
+/* All lists are per viewport specific datas.
+ * They are all free when viewport changes engines
+ * or is free itself. Use SCULPT_engine_init() to
+ * initialize most of them and SCULPT_cache_init()
+ * for SCULPT_PassList */
+
+typedef struct SCULPT_PassList {
+ /* Declare all passes here and init them in
+ * SCULPT_cache_init().
+ * Only contains (DRWPass *) */
+ struct DRWPass *pass;
+} SCULPT_PassList;
+
+typedef struct SCULPT_FramebufferList {
+ /* Contains all framebuffer objects needed by this engine.
+ * Only contains (GPUFrameBuffer *) */
+ struct GPUFrameBuffer *fb;
+} SCULPT_FramebufferList;
+
+typedef struct SCULPT_TextureList {
+ /* Contains all framebuffer textures / utility textures
+ * needed by this engine. Only viewport specific textures
+ * (not per object). Only contains (GPUTexture *) */
+ struct GPUTexture *texture;
+} SCULPT_TextureList;
+
+typedef struct SCULPT_StorageList {
+ /* Contains any other memory block that the engine needs.
+ * Only directly MEM_(m/c)allocN'ed blocks because they are
+ * free with MEM_freeN() when viewport is freed.
+ * (not per object) */
+ struct CustomStruct *block;
+ struct SCULPT_PrivateData *g_data;
+} SCULPT_StorageList;
+
+typedef struct SCULPT_Data {
+ /* Struct returned by DRW_viewport_engine_data_ensure.
+ * If you don't use one of these, just make it a (void *) */
+ // void *fbl;
+ void *engine_type; /* Required */
+ SCULPT_FramebufferList *fbl;
+ SCULPT_TextureList *txl;
+ SCULPT_PassList *psl;
+ SCULPT_StorageList *stl;
+} SCULPT_Data;
+
+/* *********** STATIC *********** */
+
+static struct {
+ /* Custom shaders :
+ * Add sources to source/blender/draw/modes/shaders
+ * init in SCULPT_engine_init();
+ * free in SCULPT_engine_free(); */
+ struct GPUShader *shader_flat;
+ struct GPUShader *shader_smooth;
+} e_data = {NULL}; /* Engine data */
+
+typedef struct SCULPT_PrivateData {
+ /* This keeps the references of the shading groups for
+ * easy access in SCULPT_cache_populate() */
+ DRWShadingGroup *group_flat;
+ DRWShadingGroup *group_smooth;
+} SCULPT_PrivateData; /* Transient data */
+
+/* *********** FUNCTIONS *********** */
+
+/* Init Textures, Framebuffers, Storage and Shaders.
+ * It is called for every frames.
+ * (Optional) */
+static void SCULPT_engine_init(void *vedata)
+{
+ SCULPT_TextureList *txl = ((SCULPT_Data *)vedata)->txl;
+ SCULPT_FramebufferList *fbl = ((SCULPT_Data *)vedata)->fbl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ UNUSED_VARS(txl, fbl, stl);
+
+ /* Init Framebuffers like this: order is attachment order (for color texs) */
+ /*
+ * DRWFboTexture tex[2] = {{&txl->depth, GPU_DEPTH_COMPONENT24, 0},
+ * {&txl->color, GPU_RGBA8, DRW_TEX_FILTER}};
+ */
+
+ /* DRW_framebuffer_init takes care of checking if
+ * the framebuffer is valid and has the right size*/
+ /*
+ * float *viewport_size = DRW_viewport_size_get();
+ * DRW_framebuffer_init(&fbl->occlude_wire_fb,
+ * (int)viewport_size[0], (int)viewport_size[1],
+ * tex, 2);
+ */
+
+ if (!e_data.shader_flat) {
+ e_data.shader_flat = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ }
+ if (!e_data.shader_smooth) {
+ e_data.shader_smooth = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
+ }
+}
+
+/* Here init all passes and shading groups
+ * Assume that all Passes are NULL */
+static void SCULPT_cache_init(void *vedata)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ if (!stl->g_data) {
+ /* Alloc transient pointers */
+ stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__);
+ }
+
+ {
+ /* Create a pass */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_MULTIPLY;
+ psl->pass = DRW_pass_create("Sculpt Pass", state);
+
+ /* Create a shadingGroup using a function in draw_common.c or custom one */
+ /*
+ * stl->g_data->group = shgroup_dynlines_uniform_color(psl->pass, ts.colorWire);
+ * -- or --
+ * stl->g_data->group = DRW_shgroup_create(e_data.custom_shader, psl->pass);
+ */
+ stl->g_data->group_flat = DRW_shgroup_create(e_data.shader_flat, psl->pass);
+ stl->g_data->group_smooth = DRW_shgroup_create(e_data.shader_smooth, psl->pass);
+ }
+}
+
+static bool object_is_flat(const Object *ob)
+{
+ Mesh *me = ob->data;
+ if (me->mpoly && me->mpoly[0].flag & ME_SMOOTH) {
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+/* Add geometry to shadingGroups. Execute for each objects */
+static void SCULPT_cache_populate(void *vedata, Object *ob)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ UNUSED_VARS(psl, stl);
+
+ if (ob->type == OB_MESH) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+
+ if (ob->sculpt && (ob == draw_ctx->obact)) {
+ /* XXX, needed for dyntopo-undo (which clears).
+ * probably depsgraph should handlle? in 2.7x getting derived-mesh does this (mesh_build_data) */
+ if (ob->sculpt->pbvh == NULL) {
+ /* create PBVH immediately (would be created on the fly too,
+ * but this avoids waiting on first stroke) */
+ Scene *scene = draw_ctx->scene;
+
+ BKE_sculpt_update_mesh_elements(draw_ctx->depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
+ }
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ if (pbvh && pbvh_has_mask(pbvh)) {
+ /* Get geometry cache */
+ DRWShadingGroup *shgroup = object_is_flat(ob) ? stl->g_data->group_flat : stl->g_data->group_smooth;
+
+ /* Add geom to a shading group */
+ DRW_shgroup_call_sculpt_add(shgroup, ob, ob->obmat);
+ }
+ }
+ }
+}
+
+/* Optional: Post-cache_populate callback */
+static void SCULPT_cache_finish(void *vedata)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_StorageList *stl = ((SCULPT_Data *)vedata)->stl;
+
+ /* Do something here! dependant on the objects gathered */
+ UNUSED_VARS(psl, stl);
+}
+
+/* Draw time ! Control rendering pipeline from here */
+static void SCULPT_draw_scene(void *vedata)
+{
+ SCULPT_PassList *psl = ((SCULPT_Data *)vedata)->psl;
+ SCULPT_FramebufferList *fbl = ((SCULPT_Data *)vedata)->fbl;
+
+ /* Default framebuffer and texture */
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ UNUSED_VARS(fbl, dfbl, dtxl);
+
+ /* Show / hide entire passes, swap framebuffers ... whatever you fancy */
+ /*
+ * DRW_framebuffer_texture_detach(dtxl->depth);
+ * DRW_framebuffer_bind(fbl->custom_fb);
+ * DRW_draw_pass(psl->pass);
+ * DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
+ * DRW_framebuffer_bind(dfbl->default_fb);
+ */
+
+ /* ... or just render passes on default framebuffer. */
+ DRW_draw_pass(psl->pass);
+
+ /* If you changed framebuffer, double check you rebind
+ * the default one with its textures attached before finishing */
+}
+
+/* Cleanup when destroying the engine.
+ * This is not per viewport ! only when quitting blender.
+ * Mostly used for freeing shaders */
+static void SCULPT_engine_free(void)
+{
+ // DRW_SHADER_FREE_SAFE(custom_shader);
+}
+
+static const DrawEngineDataSize SCULPT_data_size = DRW_VIEWPORT_DATA_SIZE(SCULPT_Data);
+
+DrawEngineType draw_engine_sculpt_type = {
+ NULL, NULL,
+ N_("SculptMode"),
+ &SCULPT_data_size,
+ &SCULPT_engine_init,
+ &SCULPT_engine_free,
+ &SCULPT_cache_init,
+ &SCULPT_cache_populate,
+ &SCULPT_cache_finish,
+ NULL, /* draw_background but not needed by mode engines */
+ &SCULPT_draw_scene,
+ NULL,
+ NULL,
+};
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl b/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl
new file mode 100644
index 00000000000..d9d59880e99
--- /dev/null
+++ b/source/blender/draw/modes/shaders/animviz_mpath_lines_geom.glsl
@@ -0,0 +1,38 @@
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+uniform int lineThickness = 2;
+
+in vec4 finalColor_geom[];
+in vec2 ssPos[];
+
+out vec4 finalColor;
+
+vec2 compute_dir(vec2 v0, vec2 v1)
+{
+ vec2 dir = normalize(v1 - v0 + 1e-8);
+ dir = vec2(-dir.y, dir.x);
+ return dir;
+}
+
+void main(void)
+{
+ vec2 t;
+ vec2 edge_dir = compute_dir(ssPos[0], ssPos[1]) / viewportSize;
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ finalColor = finalColor_geom[0];
+ t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[0].gl_Position.w : 1.0));
+ gl_Position = gl_in[0].gl_Position + vec4(t, 0.0, 0.0); EmitVertex();
+ gl_Position = gl_in[0].gl_Position - vec4(t, 0.0, 0.0); EmitVertex();
+
+ finalColor = finalColor_geom[1];
+ t = edge_dir * (float(lineThickness) * (is_persp ? gl_in[1].gl_Position.w : 1.0));
+ gl_Position = gl_in[1].gl_Position + vec4(t, 0.0, 0.0); EmitVertex();
+ gl_Position = gl_in[1].gl_Position - vec4(t, 0.0, 0.0); EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl b/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl
new file mode 100644
index 00000000000..276f4004fb6
--- /dev/null
+++ b/source/blender/draw/modes/shaders/animviz_mpath_lines_vert.glsl
@@ -0,0 +1,91 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+uniform int frameCurrent;
+uniform int frameStart;
+uniform int frameEnd;
+uniform int cacheStart;
+uniform bool selected;
+uniform bool useCustomColor;
+uniform vec3 customColor;
+
+in vec3 pos;
+
+out vec2 ssPos;
+out vec4 finalColor_geom;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+#define SET_INTENSITY(A, B, C, min, max) (((1.0 - (float(C - B) / float(C - A))) * (max - min)) + min)
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+
+ ssPos = proj(gl_Position);
+
+ int frame = gl_VertexID + cacheStart;
+
+ float intensity; /* how faint */
+
+ vec3 blend_base = (abs(frame - frameCurrent) == 1) ? colorCurrentFrame.rgb : colorBackground.rgb; /* "bleed" cframe color to ease color blending */
+
+ /* TODO: We might want something more consistent with custom color and standard colors. */
+ if (frame < frameCurrent) {
+ if (useCustomColor) {
+ /* Custom color: previous frames color is darker than current frame */
+ finalColor_geom.rgb = customColor * 0.25;
+ }
+ else {
+ /* black - before frameCurrent */
+ if (selected) {
+ intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.25, 0.75);
+ }
+ else {
+ intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.68, 0.92);
+ }
+ finalColor_geom.rgb = mix(colorWire.rgb, blend_base, intensity);
+ }
+ }
+ else if (frame > frameCurrent) {
+ if (useCustomColor) {
+ /* Custom color: next frames color is equal to user selected color */
+ finalColor_geom.rgb = customColor;
+ }
+ else {
+ /* blue - after frameCurrent */
+ if (selected) {
+ intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.25, 0.75);
+ }
+ else {
+ intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.68, 0.92);
+ }
+
+ finalColor_geom.rgb = mix(colorBonePose.rgb, blend_base, intensity);
+ }
+ }
+ else {
+ if (useCustomColor) {
+ /* Custom color: current frame color is slightly darker than user selected color */
+ finalColor_geom.rgb = customColor * 0.5;
+ }
+ else {
+ /* green - on frameCurrent */
+ if (selected) {
+ intensity = 0.5f;
+ }
+ else {
+ intensity = 0.99f;
+ }
+ finalColor_geom.rgb = clamp(mix(colorCurrentFrame.rgb, colorBackground.rgb, intensity) - 0.1, 0.0, 0.1);
+ }
+ }
+
+ finalColor_geom.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl b/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl
new file mode 100644
index 00000000000..3b2f170ca22
--- /dev/null
+++ b/source/blender/draw/modes/shaders/animviz_mpath_points_vert.glsl
@@ -0,0 +1,47 @@
+
+uniform mat4 ViewProjectionMatrix;
+
+uniform int pointSize = 2;
+uniform int frameCurrent;
+uniform int cacheStart;
+uniform bool showKeyFrames = true;
+uniform bool useCustomColor;
+uniform vec3 customColor;
+
+in vec3 pos;
+in int flag;
+
+#define MOTIONPATH_VERT_SEL (1 << 0)
+#define MOTIONPATH_VERT_KEY (1 << 1)
+
+out vec4 finalColor;
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+ gl_PointSize = float(pointSize + 2);
+
+ int frame = gl_VertexID + cacheStart;
+ finalColor = (useCustomColor) ? vec4(customColor, 1.0) : vec4(1.0);
+
+ /* Bias to reduce z fighting with the path */
+ gl_Position.z -= 1e-4;
+
+ if (showKeyFrames) {
+ if ((flag & MOTIONPATH_VERT_KEY) != 0) {
+ gl_PointSize = float(pointSize + 5);
+ finalColor = colorVertexSelect;
+ /* Bias more to get these on top of regular points */
+ gl_Position.z -= 1e-4;
+ }
+ /* Draw big green dot where the current frame is.
+ * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter
+ */
+ if (frame == frameCurrent) {
+ gl_PointSize = float(pointSize + 8);
+ finalColor = colorCurrentFrame;
+ /* Bias more to get these on top of keyframes */
+ gl_Position.z -= 1e-4;
+ }
+ }
+}
diff --git a/source/blender/draw/modes/shaders/armature_axes_vert.glsl b/source/blender/draw/modes/shaders/armature_axes_vert.glsl
new file mode 100644
index 00000000000..e46dab458e0
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_axes_vert.glsl
@@ -0,0 +1,30 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screenVecs[3];
+
+/* ---- Instanciated Attribs ---- */
+in float axis; /* position on the axis. [0.0-1.0] is X axis, [1.0-2.0] is Y, etc... */
+in vec2 screenPos;
+in vec3 colorAxis;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 color;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ vec3 chosen_axis = InstanceModelMatrix[int(axis)].xyz;
+ vec3 y_axis = InstanceModelMatrix[1].xyz;
+ vec3 bone_loc = InstanceModelMatrix[3].xyz;
+ vec3 wpos = bone_loc + y_axis + chosen_axis * fract(axis);
+ vec3 spos = screenVecs[0].xyz * screenPos.x + screenVecs[1].xyz * screenPos.y;
+ /* Scale uniformly by axis length */
+ spos *= length(chosen_axis);
+
+ gl_Position = ViewProjectionMatrix * vec4(wpos + spos, 1.0);
+
+ finalColor.rgb = mix(colorAxis, color.rgb, color.a);
+ finalColor.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl
new file mode 100644
index 00000000000..cecc5447c7c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_distance_frag.glsl
@@ -0,0 +1,15 @@
+
+flat in vec3 finalStateColor; /* UNUSED */
+flat in vec3 finalBoneColor; /* UNUSED */
+in vec3 normalView;
+
+out vec4 fragColor;
+
+uniform vec4 color = vec4(1.0, 1.0, 1.0, 0.2);
+
+void main()
+{
+ float n = normalize(normalView).z;
+ n = 1.0 - clamp(-n, 0.0, 1.0);
+ fragColor = color * n;
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl
new file mode 100644
index 00000000000..a836d7fa9e1
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_outline_vert.glsl
@@ -0,0 +1,156 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+
+uniform vec2 viewportSize;
+uniform float lineThickness = 2.0;
+
+/* ---- Instanciated Attribs ---- */
+in vec2 pos0;
+in vec2 pos1;
+in vec2 pos2;
+
+/* ---- Per instance Attribs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 headSphere;
+in vec4 tailSphere;
+in vec4 outlineColorSize;
+in vec3 xAxis;
+
+flat out vec4 finalColor;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+vec2 compute_dir(vec2 v0, vec2 v1, vec2 v2)
+{
+ vec2 dir = normalize(v2 - v0);
+ dir = vec2(dir.y, -dir.x);
+ return dir;
+}
+
+mat3 compute_mat(vec4 sphere, vec3 bone_vec, out float z_ofs)
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 cam_ray = (is_persp) ? sphere.xyz - ViewMatrixInverse[3].xyz
+ : -ViewMatrixInverse[2].xyz;
+
+ /* Sphere center distance from the camera (persp) in world space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(bone_vec, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+ z_ofs = 0.0;
+
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ float rad = sphere.w;
+ /* Let be :
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ z_ofs = -rad * cos_b;
+ }
+
+ return mat3(x_axis, y_axis, z_axis);
+}
+
+struct Bone { vec3 vec; float sinb; };
+
+bool bone_blend_starts(vec3 p, Bone b)
+{
+ /* we just want to know when the head sphere starts interpolating. */
+ return dot(p, b.vec) > -b.sinb;
+}
+
+vec3 get_outline_point(
+ vec2 pos, vec4 sph_near, vec4 sph_far,
+ mat3 mat_near, mat3 mat_far, float z_ofs_near, float z_ofs_far, Bone b)
+{
+ /* Compute outline position on the nearest sphere and check
+ * if it penetrates the capsule body. If it does, put this
+ * vertex on the farthest sphere. */
+ vec3 wpos = mat_near * vec3(pos * sph_near.w, z_ofs_near);
+ if (bone_blend_starts(wpos, b)) {
+ wpos = sph_far.xyz + mat_far * vec3(pos * sph_far.w, z_ofs_far);
+ }
+ else {
+ wpos += sph_near.xyz;
+ }
+ return wpos;
+}
+
+void main()
+{
+ float dst_head = distance(headSphere.xyz, ViewMatrixInverse[3].xyz);
+ float dst_tail = distance(tailSphere.xyz, ViewMatrixInverse[3].xyz);
+ // float dst_head = -dot(headSphere.xyz, ViewMatrix[2].xyz);
+ // float dst_tail = -dot(tailSphere.xyz, ViewMatrix[2].xyz);
+
+ vec4 sph_near, sph_far;
+ if ((dst_head > dst_tail) && (ProjectionMatrix[3][3] == 0.0)) {
+ sph_near = tailSphere;
+ sph_far = headSphere;
+ }
+ else {
+ sph_near = headSphere;
+ sph_far = tailSphere;
+ }
+
+ vec3 bone_vec = (sph_far.xyz - sph_near.xyz) + 1e-8;
+
+ Bone b;
+ float bone_lenrcp = 1.0 / max(1e-8, sqrt(dot(bone_vec, bone_vec)));
+ b.sinb = (sph_far.w - sph_near.w) * bone_lenrcp * sph_near.w;
+ b.vec = bone_vec * bone_lenrcp;
+
+ float z_ofs_near, z_ofs_far;
+ mat3 mat_near = compute_mat(sph_near, bone_vec, z_ofs_near);
+ mat3 mat_far = compute_mat(sph_far, bone_vec, z_ofs_far);
+
+ vec3 wpos0 = get_outline_point(pos0, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+ vec3 wpos1 = get_outline_point(pos1, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+ vec3 wpos2 = get_outline_point(pos2, sph_near, sph_far, mat_near, mat_far, z_ofs_near, z_ofs_far, b);
+
+ vec4 V = ViewMatrix * vec4(wpos1, 1.0);
+ float pres_fac = (ProjectionMatrix[3][3] == 0.0) ? abs(V.z) : 1.0;
+
+ vec4 p0 = ViewProjectionMatrix * vec4(wpos0, 1.0);
+ vec4 p1 = ProjectionMatrix * V;
+ vec4 p2 = ViewProjectionMatrix * vec4(wpos2, 1.0);
+
+ /* compute position from 3 vertex because the change in direction
+ * can happen very quicky and lead to very thin edges. */
+ vec2 ss0 = proj(p0);
+ vec2 ss1 = proj(p1);
+ vec2 ss2 = proj(p2);
+ vec2 edge_dir = compute_dir(ss0, ss1, ss2);
+
+ bool outer = ((gl_VertexID & 1) == 1);
+ vec2 t = outlineColorSize.w * (lineThickness / viewportSize);
+ t *= pres_fac;
+ t = (outer) ? t : vec2(0.0);
+
+ gl_Position = p1;
+ gl_Position.xy += t * edge_dir;
+
+ finalColor = vec4(outlineColorSize.rgb, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl
new file mode 100644
index 00000000000..b20656ff326
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl
@@ -0,0 +1,16 @@
+
+flat in vec3 finalStateColor;
+flat in vec3 finalBoneColor;
+in vec3 normalView;
+
+out vec4 fragColor;
+
+void main()
+{
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float n = normalize(normalView).z;
+ float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
+ fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
+ fragColor.a = 0.6; /* Hardcoded transparency factor. */
+}
diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl
new file mode 100644
index 00000000000..83ae720e70a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_envelope_solid_vert.glsl
@@ -0,0 +1,55 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+
+/* ---- Instanciated Attribs ---- */
+in vec3 pos;
+
+/* ---- Per instance Attribs ---- */
+/* Assumed to be in world coordinate already. */
+in vec4 headSphere;
+in vec4 tailSphere;
+in vec3 xAxis;
+in vec3 stateColor;
+in vec3 boneColor;
+
+flat out vec3 finalStateColor;
+flat out vec3 finalBoneColor;
+out vec3 normalView;
+
+void main()
+{
+ vec3 bone_vec = tailSphere.xyz - headSphere.xyz;
+ float bone_len = max(1e-8, sqrt(dot(bone_vec, bone_vec)));
+ float bone_lenrcp = 1.0 / bone_len;
+#ifdef SMOOTH_ENVELOPE
+ float sinb = (tailSphere.w - headSphere.w) * bone_lenrcp;
+#else
+ const float sinb = 0.0;
+#endif
+
+ vec3 y_axis = bone_vec * bone_lenrcp;
+ vec3 z_axis = normalize(cross(xAxis, -y_axis));
+ vec3 x_axis = cross(y_axis, z_axis); /* cannot trust xAxis to be orthogonal. */
+
+ vec3 sp, nor;
+ nor = sp = pos.xyz;
+
+ /* In bone space */
+ bool is_head = (pos.z < -sinb);
+ sp *= (is_head) ? headSphere.w : tailSphere.w;
+ sp.z += (is_head) ? 0.0 : bone_len;
+
+ /* Convert to world space */
+ mat3 bone_mat = mat3(x_axis, y_axis, z_axis);
+ sp = bone_mat * sp.xzy + headSphere.xyz;
+ nor = bone_mat * nor.xzy;
+
+ normalView = mat3(ViewMatrix) * nor;
+
+ gl_Position = ViewProjectionMatrix * vec4(sp, 1.0);
+
+ finalStateColor = stateColor;
+ finalBoneColor = boneColor;
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
new file mode 100644
index 00000000000..4d6f3e94693
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_outline_geom.glsl
@@ -0,0 +1,87 @@
+
+layout(lines_adjacency) in;
+layout(triangle_strip, max_vertices = 6) out;
+
+in vec4 pPos[];
+in vec3 vPos[];
+in vec2 ssPos[];
+in vec2 ssNor[];
+in vec4 vColSize[];
+
+flat out vec4 finalColor;
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+uniform float lineThickness = 2.0;
+
+vec2 compute_dir(vec2 v0, vec2 v1)
+{
+ vec2 dir = normalize(v1 - v0);
+ dir = vec2(-dir.y, dir.x);
+ return dir;
+}
+
+void emit_edge(vec2 edge_dir, vec2 hidden_dir, vec2 thick, bool is_persp)
+{
+ float fac = dot(-hidden_dir, edge_dir);
+
+ vec2 t = thick * (is_persp ? abs(vPos[1].z) : 1.0);
+ gl_Position = pPos[1];
+ EmitVertex();
+ gl_Position.xy += t * edge_dir * sign(fac);
+ EmitVertex();
+
+ t = thick * (is_persp ? abs(vPos[2].z) : 1.0);
+ gl_Position = pPos[2];
+ EmitVertex();
+ gl_Position.xy += t * edge_dir * sign(fac);
+ EmitVertex();
+}
+
+void emit_corner(const int e, vec2 thick, bool is_persp)
+{
+ vec2 corner_dir = ssNor[e];
+ vec2 t = thick * (is_persp ? abs(vPos[e].z) : 1.0);
+
+ gl_Position = pPos[e] + vec4(t * corner_dir, 0.0, 0.0);
+ EmitVertex();
+}
+
+void main(void)
+{
+ finalColor = vec4(vColSize[0].rgb, 1.0);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0);
+ vec3 v10 = vPos[0] - vPos[1];
+ vec3 v12 = vPos[2] - vPos[1];
+ vec3 v13 = vPos[3] - vPos[1];
+
+ vec3 n0 = cross(v12, v10);
+ vec3 n3 = cross(v13, v12);
+
+ float fac0 = dot(view_vec, n0);
+ float fac3 = dot(view_vec, n3);
+
+ /* If both adjacent verts are facing the camera the same way,
+ * then it isn't an outline edge. */
+ if (sign(fac0) == sign(fac3))
+ return;
+
+ /* Don't outline if concave edge. */
+ if (dot(n0, v13) > 0.0001)
+ return;
+
+ vec2 thick = vColSize[0].w * (lineThickness / viewportSize);
+ vec2 edge_dir = compute_dir(ssPos[1], ssPos[2]);
+
+ /* Take the farthest point to compute edge direction
+ * (avoid problems with point behind near plane). */
+ vec2 hidden_point = (vPos[0].z < vPos[3].z) ? ssPos[0] : ssPos[3];
+ vec2 hidden_dir = normalize(hidden_point - ssPos[1]);
+
+ emit_corner(1, thick, is_persp);
+ emit_edge(edge_dir, hidden_dir, thick, is_persp);
+ emit_corner(2, thick, is_persp);
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl
new file mode 100644
index 00000000000..3e7a185bb62
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_outline_vert.glsl
@@ -0,0 +1,48 @@
+
+uniform mat3 NormalMatrix;
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+/* ---- Instanciated Attribs ---- */
+in vec3 pos;
+in vec3 nor;
+in vec3 snor;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 outlineColorSize;
+
+out vec4 pPos;
+out vec3 vPos;
+out vec2 ssPos;
+out vec2 ssNor;
+out vec4 vColSize;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ /* This is slow and run per vertex, but it's still faster than
+ * doing it per instance on CPU and sending it on via instance attrib */
+ mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix)));
+
+ vec4 viewpos = ViewMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
+
+ vPos = viewpos.xyz;
+ pPos = ProjectionMatrix * viewpos;
+
+ /* TODO FIX: there is still a problem with this vector
+ * when the bone is scaled or in persp mode. But it's
+ * barelly visible at the outline corners. */
+ ssNor = normalize((NormalMatrix * snor).xy);
+
+ ssPos = proj(pPos);
+
+ vColSize = outlineColorSize;
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl
new file mode 100644
index 00000000000..89f4d97f29b
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl
@@ -0,0 +1,9 @@
+
+in vec4 finalColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(finalColor.rgb, 0.6); /* Hardcoded transparency factor. */
+}
diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl
new file mode 100644
index 00000000000..505868c9dcf
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_shape_solid_vert.glsl
@@ -0,0 +1,37 @@
+
+uniform mat3 NormalMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewProjectionMatrix;
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+/* ---- Instanciated Attribs ---- */
+in vec3 pos;
+in vec3 nor;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec3 boneColor;
+in vec3 stateColor;
+
+out vec4 finalColor;
+
+void main()
+{
+ mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix)));
+ vec3 normal = normalize(NormalMatrix * nor);
+
+ /* Do lighting at an angle to avoid flat shading on front facing bone. */
+ const vec3 light = vec3(0.1, 0.1, 0.8);
+ float n = dot(normal, light);
+
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0);
+ finalColor.rgb = mix(stateColor, boneColor, fac);
+ finalColor.a = 1.0;
+
+ gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(pos, 1.0));
+}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl
new file mode 100644
index 00000000000..a169facd45a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_sphere_outline_vert.glsl
@@ -0,0 +1,102 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+uniform float lineThickness = 2.0;
+
+/* ---- Instanciated Attribs ---- */
+in vec2 pos0;
+in vec2 pos1;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec4 outlineColorSize;
+
+flat out vec4 finalColor;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+vec2 compute_dir(vec2 v0, vec2 v1, vec2 c)
+{
+ vec2 dir = normalize(v1 - v0);
+ dir = vec2(dir.y, -dir.x);
+ /* The model matrix can be scaled negativly.
+ * Use projected sphere center to determine
+ * the outline direction. */
+ vec2 cv = c - v0;
+ dir = (dot(dir, cv) > 0.0) ? -dir : dir;
+ return dir;
+}
+
+void main()
+{
+ mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix;
+ mat4 sphereMatrix = inverse(model_view_matrix);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ /* This is the local space camera ray (not normalize).
+ * In perspective mode it's also the viewspace position
+ * of the sphere center. */
+ vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0);
+ cam_ray = mat3(sphereMatrix) * cam_ray;
+
+ /* Sphere center distance from the camera (persp) in local space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+ float z_ofs = 0.0;
+
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ const float rad = 0.05;
+ /* Let be (in local space):
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ z_ofs = -rad * cos_b;
+ }
+
+ /* Camera oriented position (but still in local space) */
+ vec3 cam_pos0 = x_axis * pos0.x + y_axis * pos0.y + z_axis * z_ofs;
+ vec3 cam_pos1 = x_axis * pos1.x + y_axis * pos1.y + z_axis * z_ofs;
+
+ vec4 V = model_view_matrix * vec4(cam_pos0, 1.0);
+ vec4 p0 = ProjectionMatrix * V;
+ vec4 p1 = ProjectionMatrix * (model_view_matrix * vec4(cam_pos1, 1.0));
+ vec4 c = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
+
+ vec2 ssc = proj(c);
+ vec2 ss0 = proj(p0);
+ vec2 ss1 = proj(p1);
+ vec2 edge_dir = compute_dir(ss0, ss1, ssc);
+
+ bool outer = ((gl_VertexID & 1) == 1);
+
+ vec2 t = outlineColorSize.w * (lineThickness / viewportSize);
+ t *= (is_persp) ? abs(V.z) : 1.0;
+ t = (outer) ? t : vec2(0.0);
+
+ gl_Position = p0;
+ gl_Position.xy += t * edge_dir;
+
+ finalColor = vec4(outlineColorSize.rgb, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl
new file mode 100644
index 00000000000..3c80f629d79
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl
@@ -0,0 +1,81 @@
+
+#extension GL_ARB_conservative_depth : enable
+
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ProjectionMatrix;
+
+flat in vec3 finalStateColor;
+flat in vec3 finalBoneColor;
+flat in mat4 sphereMatrix;
+in vec3 viewPosition;
+
+#ifdef GL_ARB_conservative_depth
+/* Saves a lot of overdraw! */
+layout(depth_greater) out float gl_FragDepth;
+#endif
+
+out vec4 fragColor;
+
+#define cameraPos ViewMatrixInverse[3].xyz
+
+float get_depth_from_view_z(float z)
+{
+ if (ProjectionMatrix[3][3] == 0.0) {
+ z = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
+ }
+ else {
+ z = z * ProjectionMatrix[2][2] / (1.0 - ProjectionMatrix[3][2]);
+ }
+ return z * 0.5 + 0.5;
+}
+
+void main()
+{
+ const float sphere_radius = 0.05;
+
+ bool is_perp = (ProjectionMatrix[3][3] == 0.0);
+ vec3 ray_ori_view = (is_perp) ? vec3(0.0) : viewPosition.xyz;
+ vec3 ray_dir_view = (is_perp) ? viewPosition : vec3(0.0, 0.0, -1.0);
+
+ /* Single matrix mul without branch. */
+ vec4 mul_vec = (is_perp) ? vec4(ray_dir_view, 0.0) : vec4(ray_ori_view, 1.0);
+ vec3 mul_res = (sphereMatrix * mul_vec).xyz;
+
+ /* Reminder :
+ * sphereMatrix[3] is the view space origin in sphere space (sph_ori -> view_ori).
+ * sphereMatrix[2] is the view space Z axis in sphere space. */
+
+ /* convert to sphere local space */
+ vec3 ray_ori = (is_perp) ? sphereMatrix[3].xyz : mul_res;
+ vec3 ray_dir = (is_perp) ? mul_res : -sphereMatrix[2].xyz;
+ float ray_len = length(ray_dir);
+ ray_dir /= ray_len;
+
+ /* Line to sphere intersect */
+ const float sphere_radius_sqr = sphere_radius * sphere_radius;
+ float b = dot(ray_ori, ray_dir);
+ float c = dot(ray_ori, ray_ori) - sphere_radius_sqr;
+ float h = b * b - c;
+ float t = -sqrt(max(0.0, h)) - b;
+
+ /* Compute dot product for lighting */
+ vec3 p = ray_dir * t + ray_ori; /* Point on sphere */
+ vec3 n = normalize(p); /* Normal is just the point in sphere space, normalized. */
+ vec3 l = normalize(sphereMatrix[2].xyz); /* Just the view Z axis in the sphere space. */
+
+
+ /* Smooth lighting factor. */
+ const float s = 0.2; /* [0.0-0.5] range */
+ float fac = clamp((dot(n, l) * (1.0 - s)) + s, 0.0, 1.0);
+ fragColor.rgb = mix(finalStateColor, finalBoneColor, fac);
+
+ /* 2x2 dither pattern to smooth the lighting. */
+ float dither = (0.5 + dot(vec2(ivec2(gl_FragCoord.xy) & ivec2(1)), vec2(1.0, 2.0))) * 0.25;
+ dither *= (1.0 / 255.0); /* Assume 8bit per color buffer. */
+
+ /* Hardcoded transparency factor. Less than shape to be less distractive. */
+ fragColor = vec4(fragColor.rgb + dither, 0.4);
+
+ t /= ray_len;
+ gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z);
+}
diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl
new file mode 100644
index 00000000000..1e06047054e
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_sphere_solid_vert.glsl
@@ -0,0 +1,82 @@
+
+uniform mat4 ViewMatrix;
+uniform mat4 ProjectionMatrix;
+
+/* ---- Instanciated Attribs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+in vec3 stateColor;
+in vec3 boneColor;
+
+flat out vec3 finalStateColor;
+flat out vec3 finalBoneColor;
+flat out mat4 sphereMatrix;
+out vec3 viewPosition;
+
+/* Sphere radius */
+const float rad = 0.05;
+
+void main()
+{
+ mat4 model_view_matrix = ViewMatrix * InstanceModelMatrix;
+ sphereMatrix = inverse(model_view_matrix);
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ /* This is the local space camera ray (not normalize).
+ * In perspective mode it's also the viewspace position
+ * of the sphere center. */
+ vec3 cam_ray = (is_persp) ? model_view_matrix[3].xyz : vec3(0.0, 0.0, -1.0);
+ cam_ray = mat3(sphereMatrix) * cam_ray;
+
+ /* Sphere center distance from the camera (persp) in local space. */
+ float cam_dist = length(cam_ray);
+
+ /* Compute view aligned orthonormal space. */
+ vec3 z_axis = cam_ray / cam_dist;
+ vec3 x_axis = normalize(cross(sphereMatrix[1].xyz, z_axis));
+ vec3 y_axis = cross(z_axis, x_axis);
+
+ float z_ofs = -rad - 1e-8; /* offset to the front of the sphere */
+ if (is_persp) {
+ /* For perspective, the projected sphere radius
+ * can be bigger than the center disc. Compute the
+ * max angular size and compensate by sliding the disc
+ * towards the camera and scale it accordingly. */
+ const float half_pi = 3.1415926 * 0.5;
+ /* Let be (in local space):
+ * V the view vector origin.
+ * O the sphere origin.
+ * T the point on the target circle.
+ * We compute the angle between (OV) and (OT). */
+ float a = half_pi - asin(rad / cam_dist);
+ float cos_b = cos(a);
+ float sin_b = sqrt(clamp(1.0 - cos_b * cos_b, 0.0, 1.0));
+#if 1
+ /* Instead of choosing the biggest circle in screenspace,
+ * we choose the nearest with the same angular size. This
+ * permit us to leverage GL_ARB_conservative_depth in the
+ * fragment shader. */
+ float minor = cam_dist - rad;
+ float major = cam_dist - cos_b * rad;
+ float fac = minor / major;
+ sin_b *= fac;
+#else
+ z_ofs = -rad * cos_b;
+#endif
+ x_axis *= sin_b;
+ y_axis *= sin_b;
+ }
+
+ /* Camera oriented position (but still in local space) */
+ vec3 cam_pos = x_axis * pos.x + y_axis * pos.y + z_axis * z_ofs;
+
+ vec4 V = model_view_matrix * vec4(cam_pos, 1.0);
+ gl_Position = ProjectionMatrix * V;
+ viewPosition = V.xyz;
+
+ finalStateColor = stateColor;
+ finalBoneColor = boneColor;
+}
diff --git a/source/blender/draw/modes/shaders/armature_stick_frag.glsl b/source/blender/draw/modes/shaders/armature_stick_frag.glsl
new file mode 100644
index 00000000000..d03cf4c0366
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_stick_frag.glsl
@@ -0,0 +1,13 @@
+
+noperspective in float colorFac;
+flat in vec4 finalWireColor;
+flat in vec4 finalInnerColor;
+
+out vec4 fragColor;
+
+void main()
+{
+ float fac = smoothstep(1.0, 0.2, colorFac);
+ fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac);
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/armature_stick_vert.glsl b/source/blender/draw/modes/shaders/armature_stick_vert.glsl
new file mode 100644
index 00000000000..eb14239bc6f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/armature_stick_vert.glsl
@@ -0,0 +1,88 @@
+
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ViewMatrix;
+uniform vec2 viewportSize;
+
+/* ---- Instanciated Attribs ---- */
+in vec2 pos; /* bone aligned screen space */
+in uint flag;
+
+#define COL_WIRE (1u << 0u)
+#define COL_HEAD (1u << 1u)
+#define COL_TAIL (1u << 2u)
+#define COL_BONE (1u << 3u)
+
+#define POS_HEAD (1u << 4u)
+#define POS_TAIL (1u << 5u) /* UNUSED */
+#define POS_BONE (1u << 6u)
+
+/* ---- Per instance Attribs ---- */
+in vec3 boneStart;
+in vec3 boneEnd;
+in vec4 wireColor; /* alpha encode if we do wire. If 0.0 we dont. */
+in vec4 boneColor; /* alpha encode if we do bone. If 0.0 we dont. */
+in vec4 headColor; /* alpha encode if we do head. If 0.0 we dont. */
+in vec4 tailColor; /* alpha encode if we do tail. If 0.0 we dont. */
+
+#define do_wire (wireColor.a > 0.0)
+#define is_head ((flag & POS_HEAD) != 0u)
+#define is_bone ((flag & POS_BONE) != 0u)
+
+noperspective out float colorFac;
+flat out vec4 finalWireColor;
+flat out vec4 finalInnerColor;
+
+uniform float stickSize = 5.0; /* might be dependant on DPI setting in the future. */
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ finalInnerColor = ((flag & COL_HEAD) != 0u) ? headColor : tailColor;
+ finalInnerColor = ((flag & COL_BONE) != 0u) ? boneColor : finalInnerColor;
+ finalWireColor = (do_wire) ? wireColor : finalInnerColor;
+ /* Make the color */
+ colorFac = ((flag & COL_WIRE) == 0u) ? ((flag & COL_BONE) != 0u) ? 1.0 : 2.0 : 0.0;
+
+ vec4 v0 = ViewMatrix * vec4(boneStart, 1.0);
+ vec4 v1 = ViewMatrix * vec4(boneEnd, 1.0);
+
+ /* Clip the bone to the camera origin plane (not the clip plane)
+ * to avoid glitches if one end is behind the camera origin (in persp). */
+ const float clip_dist = -1e-7; /* hardcoded, -1e-8 is giving gliches. */
+ vec3 bvec = v1.xyz - v0.xyz;
+ vec3 clip_pt = v0.xyz + bvec * ((v0.z - clip_dist) / -bvec.z);
+ if (v0.z > clip_dist) {
+ v0.xyz = clip_pt;
+ }
+ else if (v1.z > clip_dist) {
+ v1.xyz = clip_pt;
+ }
+
+ vec4 p0 = ProjectionMatrix * v0;
+ vec4 p1 = ProjectionMatrix * v1;
+
+ float h = (is_head) ? p0.w : p1.w;
+
+ vec2 x_screen_vec = normalize(proj(p1) - proj(p0) + 1e-8);
+ vec2 y_screen_vec = vec2(x_screen_vec.y, -x_screen_vec.x);
+
+ /* 2D screen aligned pos at the point */
+ vec2 vpos = pos.x * x_screen_vec + pos.y * y_screen_vec;
+ vpos *= (ProjectionMatrix[3][3] == 0.0) ? h : 1.0;
+ vpos *= (do_wire) ? 1.0 : 0.5;
+
+ if (finalInnerColor.a > 0.0) {
+ gl_Position = (is_head) ? p0 : p1;
+ gl_Position.xy += stickSize * (vpos / viewportSize);
+ gl_Position.z += (is_bone) ? 0.0 : 1e-6; /* Avoid Z fighting of head/tails. */
+ }
+ else {
+ gl_Position = vec4(0.0);
+ }
+}
diff --git a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl
new file mode 100644
index 00000000000..fc5cc1cdcc3
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl
@@ -0,0 +1,10 @@
+
+in vec2 pos;
+in vec2 uvs;
+out vec4 uvcoordsvar;
+
+void main()
+{
+ uvcoordsvar = vec4(uvs, 0.0, 0.0);
+ gl_Position = vec4(pos, 0.0, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/common_fxaa_lib.glsl b/source/blender/draw/modes/shaders/common_fxaa_lib.glsl
new file mode 100644
index 00000000000..8158437b943
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_fxaa_lib.glsl
@@ -0,0 +1,678 @@
+//----------------------------------------------------------------------------------
+// File: es3-kepler\FXAA/FXAA3_11.h
+// SDK Version: v3.00
+// Email: gameworks@nvidia.com
+// Site: http://developer.nvidia.com/
+//
+// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of NVIDIA CORPORATION nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//----------------------------------------------------------------------------------
+
+/* BLENDER MODIFICATIONS:
+ *
+ * - (#B1#) Compute luma on the fly using BT. 709 luma function
+ * - (#B2#) main function instead of #include, due to lack of
+ * ARB_shading_language_include in 3.3
+ * - (#B3#) version and extension directives
+ * - removed "FXAA Console" algorithm support and shader parameters
+ * - removed HLSL support shims
+ * - (#B4#) change luma sampling to compute, not use A channel
+ * (this also removes GATHER4_ALPHA support)
+ * - removed all the console shaders (only remaining algorithm is "FXAA PC
+ * Quality")
+ *
+ * Note that this file doesn't follow the coding style guidelines.
+ */
+
+/*============================================================================
+ FXAA QUALITY - TUNING KNOBS
+------------------------------------------------------------------------------
+NOTE the other tuning knobs are now in the shader function inputs!
+============================================================================*/
+#ifndef FXAA_QUALITY__PRESET
+ //
+ // Choose the quality preset.
+ // This needs to be compiled into the shader as it effects code.
+ // Best option to include multiple presets is to
+ // in each shader define the preset, then include this file.
+ //
+ // OPTIONS
+ // -----------------------------------------------------------------------
+ // 10 to 15 - default medium dither (10=fastest, 15=highest quality)
+ // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality)
+ // 39 - no dither, very expensive
+ //
+ // NOTES
+ // -----------------------------------------------------------------------
+ // 12 = slightly faster then FXAA 3.9 and higher edge quality (default)
+ // 13 = about same speed as FXAA 3.9 and better than 12
+ // 23 = closest to FXAA 3.9 visually and performance wise
+ // _ = the lowest digit is directly related to performance
+ // _ = the highest digit is directly related to style
+ //
+ #define FXAA_QUALITY__PRESET 12
+#endif
+
+/*============================================================================
+
+ FXAA QUALITY - PRESETS
+
+============================================================================*/
+
+/*============================================================================
+ FXAA QUALITY - MEDIUM DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY__PRESET == 10)
+ #define FXAA_QUALITY__PS 3
+ #define FXAA_QUALITY__P0 1.5
+ #define FXAA_QUALITY__P1 3.0
+ #define FXAA_QUALITY__P2 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 11)
+ #define FXAA_QUALITY__PS 4
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 3.0
+ #define FXAA_QUALITY__P3 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 12)
+ #define FXAA_QUALITY__PS 5
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 4.0
+ #define FXAA_QUALITY__P4 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 13)
+ #define FXAA_QUALITY__PS 6
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 4.0
+ #define FXAA_QUALITY__P5 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 14)
+ #define FXAA_QUALITY__PS 7
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 4.0
+ #define FXAA_QUALITY__P6 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 15)
+ #define FXAA_QUALITY__PS 8
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 4.0
+ #define FXAA_QUALITY__P7 12.0
+#endif
+
+/*============================================================================
+ FXAA QUALITY - LOW DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY__PRESET == 20)
+ #define FXAA_QUALITY__PS 3
+ #define FXAA_QUALITY__P0 1.5
+ #define FXAA_QUALITY__P1 2.0
+ #define FXAA_QUALITY__P2 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 21)
+ #define FXAA_QUALITY__PS 4
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 22)
+ #define FXAA_QUALITY__PS 5
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 23)
+ #define FXAA_QUALITY__PS 6
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 24)
+ #define FXAA_QUALITY__PS 7
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 3.0
+ #define FXAA_QUALITY__P6 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 25)
+ #define FXAA_QUALITY__PS 8
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 4.0
+ #define FXAA_QUALITY__P7 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 26)
+ #define FXAA_QUALITY__PS 9
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 4.0
+ #define FXAA_QUALITY__P8 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 27)
+ #define FXAA_QUALITY__PS 10
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 4.0
+ #define FXAA_QUALITY__P9 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 28)
+ #define FXAA_QUALITY__PS 11
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 2.0
+ #define FXAA_QUALITY__P9 4.0
+ #define FXAA_QUALITY__P10 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY__PRESET == 29)
+ #define FXAA_QUALITY__PS 12
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.5
+ #define FXAA_QUALITY__P2 2.0
+ #define FXAA_QUALITY__P3 2.0
+ #define FXAA_QUALITY__P4 2.0
+ #define FXAA_QUALITY__P5 2.0
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 2.0
+ #define FXAA_QUALITY__P9 2.0
+ #define FXAA_QUALITY__P10 4.0
+ #define FXAA_QUALITY__P11 8.0
+#endif
+
+/*============================================================================
+ FXAA QUALITY - EXTREME QUALITY
+============================================================================*/
+#if (FXAA_QUALITY__PRESET == 39)
+ #define FXAA_QUALITY__PS 12
+ #define FXAA_QUALITY__P0 1.0
+ #define FXAA_QUALITY__P1 1.0
+ #define FXAA_QUALITY__P2 1.0
+ #define FXAA_QUALITY__P3 1.0
+ #define FXAA_QUALITY__P4 1.0
+ #define FXAA_QUALITY__P5 1.5
+ #define FXAA_QUALITY__P6 2.0
+ #define FXAA_QUALITY__P7 2.0
+ #define FXAA_QUALITY__P8 2.0
+ #define FXAA_QUALITY__P9 2.0
+ #define FXAA_QUALITY__P10 4.0
+ #define FXAA_QUALITY__P11 8.0
+#endif
+
+#define FxaaSat(x) clamp(x, 0.0, 1.0)
+
+#ifdef FXAA_ALPHA
+
+#define FxaaTexTop(t, p) textureLod(t, p, 0.0).aaaa
+#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o).aaaa
+#define FxaaLuma(rgba) rgba.a
+
+#else
+
+#define FxaaTexTop(t, p) textureLod(t, p, 0.0)
+#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o)
+
+/* (#B1#) */
+float FxaaLuma(vec4 rgba) {
+ // note: sqrt because the sampled colors are in a linear colorspace!
+ // this approximates a perceptual conversion, which is good enough for the
+ // algorithm
+ return sqrt(dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722)));
+}
+
+#endif
+
+/*============================================================================
+
+ FXAA3 QUALITY - PC
+
+============================================================================*/
+/*--------------------------------------------------------------------------*/
+vec4 FxaaPixelShader(
+ //
+ // Use noperspective interpolation here (turn off perspective interpolation).
+ // {xy} = center of pixel
+ vec2 pos,
+ //
+ // Input color texture.
+ // {rgb_} = color in linear or perceptual color space
+ sampler2D tex,
+ //
+ // Only used on FXAA Quality.
+ // This must be from a constant/uniform.
+ // {x_} = 1.0/screenWidthInPixels
+ // {_y} = 1.0/screenHeightInPixels
+ vec2 fxaaQualityRcpFrame,
+ //
+ // Only used on FXAA Quality.
+ // This used to be the FXAA_QUALITY__SUBPIX define.
+ // It is here now to allow easier tuning.
+ // Choose the amount of sub-pixel aliasing removal.
+ // This can effect sharpness.
+ // 1.00 - upper limit (softer)
+ // 0.75 - default amount of filtering
+ // 0.50 - lower limit (sharper, less sub-pixel aliasing removal)
+ // 0.25 - almost off
+ // 0.00 - completely off
+ float fxaaQualitySubpix,
+ //
+ // Only used on FXAA Quality.
+ // This used to be the FXAA_QUALITY__EDGE_THRESHOLD define.
+ // It is here now to allow easier tuning.
+ // The minimum amount of local contrast required to apply algorithm.
+ // 0.333 - too little (faster)
+ // 0.250 - low quality
+ // 0.166 - default
+ // 0.125 - high quality
+ // 0.063 - overkill (slower)
+ float fxaaQualityEdgeThreshold,
+ //
+ // Only used on FXAA Quality.
+ // This used to be the FXAA_QUALITY__EDGE_THRESHOLD_MIN define.
+ // It is here now to allow easier tuning.
+ // Trims the algorithm from processing darks.
+ // 0.0833 - upper limit (default, the start of visible unfiltered edges)
+ // 0.0625 - high quality (faster)
+ // 0.0312 - visible limit (slower)
+ float fxaaQualityEdgeThresholdMin
+) {
+/*--------------------------------------------------------------------------*/
+ vec2 posM;
+ posM.x = pos.x;
+ posM.y = pos.y;
+ vec4 rgbyM = FxaaTexTop(tex, posM);
+ float lumaM = FxaaLuma(rgbyM); // (#B4#)
+ float lumaS = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 0, 1), fxaaQualityRcpFrame.xy));
+ float lumaE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1, 0), fxaaQualityRcpFrame.xy));
+ float lumaN = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 0,-1), fxaaQualityRcpFrame.xy));
+ float lumaW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1, 0), fxaaQualityRcpFrame.xy));
+/*--------------------------------------------------------------------------*/
+ float maxSM = max(lumaS, lumaM);
+ float minSM = min(lumaS, lumaM);
+ float maxESM = max(lumaE, maxSM);
+ float minESM = min(lumaE, minSM);
+ float maxWN = max(lumaN, lumaW);
+ float minWN = min(lumaN, lumaW);
+ float rangeMax = max(maxWN, maxESM);
+ float rangeMin = min(minWN, minESM);
+ float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;
+ float range = rangeMax - rangeMin;
+ float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);
+ bool earlyExit = range < rangeMaxClamped;
+/*--------------------------------------------------------------------------*/
+ if(earlyExit) {
+ return rgbyM;
+ }
+/*--------------------------------------------------------------------------*/
+ float lumaNW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1,-1), fxaaQualityRcpFrame.xy));
+ float lumaSE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1, 1), fxaaQualityRcpFrame.xy));
+ float lumaNE = FxaaLuma(FxaaTexOff(tex, posM, ivec2( 1,-1), fxaaQualityRcpFrame.xy));
+ float lumaSW = FxaaLuma(FxaaTexOff(tex, posM, ivec2(-1, 1), fxaaQualityRcpFrame.xy));
+/*--------------------------------------------------------------------------*/
+ float lumaNS = lumaN + lumaS;
+ float lumaWE = lumaW + lumaE;
+ float subpixRcpRange = 1.0/range;
+ float subpixNSWE = lumaNS + lumaWE;
+ float edgeHorz1 = (-2.0 * lumaM) + lumaNS;
+ float edgeVert1 = (-2.0 * lumaM) + lumaWE;
+/*--------------------------------------------------------------------------*/
+ float lumaNESE = lumaNE + lumaSE;
+ float lumaNWNE = lumaNW + lumaNE;
+ float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;
+ float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;
+/*--------------------------------------------------------------------------*/
+ float lumaNWSW = lumaNW + lumaSW;
+ float lumaSWSE = lumaSW + lumaSE;
+ float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);
+ float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);
+ float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;
+ float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;
+ float edgeHorz = abs(edgeHorz3) + edgeHorz4;
+ float edgeVert = abs(edgeVert3) + edgeVert4;
+/*--------------------------------------------------------------------------*/
+ float subpixNWSWNESE = lumaNWSW + lumaNESE;
+ float lengthSign = fxaaQualityRcpFrame.x;
+ bool horzSpan = edgeHorz >= edgeVert;
+ float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;
+/*--------------------------------------------------------------------------*/
+ if(!horzSpan) lumaN = lumaW;
+ if(!horzSpan) lumaS = lumaE;
+ if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;
+ float subpixB = (subpixA * (1.0/12.0)) - lumaM;
+/*--------------------------------------------------------------------------*/
+ float gradientN = lumaN - lumaM;
+ float gradientS = lumaS - lumaM;
+ float lumaNN = lumaN + lumaM;
+ float lumaSS = lumaS + lumaM;
+ bool pairN = abs(gradientN) >= abs(gradientS);
+ float gradient = max(abs(gradientN), abs(gradientS));
+ if(pairN) lengthSign = -lengthSign;
+ float subpixC = FxaaSat(abs(subpixB) * subpixRcpRange);
+/*--------------------------------------------------------------------------*/
+ vec2 posB;
+ posB.x = posM.x;
+ posB.y = posM.y;
+ vec2 offNP;
+ offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
+ offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
+ if(!horzSpan) posB.x += lengthSign * 0.5;
+ if( horzSpan) posB.y += lengthSign * 0.5;
+/*--------------------------------------------------------------------------*/
+ vec2 posN;
+ posN.x = posB.x - offNP.x * FXAA_QUALITY__P0;
+ posN.y = posB.y - offNP.y * FXAA_QUALITY__P0;
+ vec2 posP;
+ posP.x = posB.x + offNP.x * FXAA_QUALITY__P0;
+ posP.y = posB.y + offNP.y * FXAA_QUALITY__P0;
+ float subpixD = ((-2.0)*subpixC) + 3.0;
+ float lumaEndN = FxaaLuma(FxaaTexTop(tex, posN));
+ float subpixE = subpixC * subpixC;
+ float lumaEndP = FxaaLuma(FxaaTexTop(tex, posP));
+/*--------------------------------------------------------------------------*/
+ if(!pairN) lumaNN = lumaSS;
+ float gradientScaled = gradient * 1.0/4.0;
+ float lumaMM = lumaM - lumaNN * 0.5;
+ float subpixF = subpixD * subpixE;
+ bool lumaMLTZero = lumaMM < 0.0;
+/*--------------------------------------------------------------------------*/
+ lumaEndN -= lumaNN * 0.5;
+ lumaEndP -= lumaNN * 0.5;
+ bool doneN = abs(lumaEndN) >= gradientScaled;
+ bool doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1;
+ bool doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1;
+/*--------------------------------------------------------------------------*/
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 3)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 4)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 5)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 6)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 7)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 8)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 9)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 10)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 11)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11;
+/*--------------------------------------------------------------------------*/
+ #if (FXAA_QUALITY__PS > 12)
+ if(doneNP) {
+ if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy));
+ if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy));
+ if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+ if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+ doneN = abs(lumaEndN) >= gradientScaled;
+ doneP = abs(lumaEndP) >= gradientScaled;
+ if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12;
+ if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12;
+ doneNP = (!doneN) || (!doneP);
+ if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12;
+ if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12;
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+ #endif
+/*--------------------------------------------------------------------------*/
+ }
+/*--------------------------------------------------------------------------*/
+ float dstN = posM.x - posN.x;
+ float dstP = posP.x - posM.x;
+ if(!horzSpan) dstN = posM.y - posN.y;
+ if(!horzSpan) dstP = posP.y - posM.y;
+/*--------------------------------------------------------------------------*/
+ bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;
+ float spanLength = (dstP + dstN);
+ bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;
+ float spanLengthRcp = 1.0/spanLength;
+/*--------------------------------------------------------------------------*/
+ bool directionN = dstN < dstP;
+ float dst = min(dstN, dstP);
+ bool goodSpan = directionN ? goodSpanN : goodSpanP;
+ float subpixG = subpixF * subpixF;
+ float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;
+ float subpixH = subpixG * fxaaQualitySubpix;
+/*--------------------------------------------------------------------------*/
+ float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;
+ float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);
+ if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;
+ if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;
+ return vec4(FxaaTexTop(tex, posM).xyz, lumaM);
+}
+/*==========================================================================*/
+
diff --git a/source/blender/draw/modes/shaders/common_globals_lib.glsl b/source/blender/draw/modes/shaders/common_globals_lib.glsl
new file mode 100644
index 00000000000..c55457bb6d2
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_globals_lib.glsl
@@ -0,0 +1,73 @@
+
+/* keep in sync with GlobalsUboStorage */
+layout(std140) uniform globalsBlock {
+ vec4 colorWire;
+ vec4 colorWireEdit;
+ vec4 colorActive;
+ vec4 colorSelect;
+ vec4 colorTransform;
+ vec4 colorLibrarySelect;
+ vec4 colorLibrary;
+ vec4 colorLamp;
+ vec4 colorSpeaker;
+ vec4 colorCamera;
+ vec4 colorEmpty;
+ vec4 colorVertex;
+ vec4 colorVertexSelect;
+ vec4 colorEditMeshActive;
+ vec4 colorEdgeSelect;
+ vec4 colorEdgeSeam;
+ vec4 colorEdgeSharp;
+ vec4 colorEdgeCrease;
+ vec4 colorEdgeBWeight;
+ vec4 colorEdgeFaceSelect;
+ vec4 colorFace;
+ vec4 colorFaceSelect;
+ vec4 colorNormal;
+ vec4 colorVNormal;
+ vec4 colorLNormal;
+ vec4 colorFaceDot;
+
+ vec4 colorDeselect;
+ vec4 colorOutline;
+ vec4 colorLampNoAlpha;
+
+ vec4 colorBackground;
+
+ vec4 colorHandleFree;
+ vec4 colorHandleAuto;
+ vec4 colorHandleVect;
+ vec4 colorHandleAlign;
+ vec4 colorHandleAutoclamp;
+ vec4 colorHandleSelFree;
+ vec4 colorHandleSelAuto;
+ vec4 colorHandleSelVect;
+ vec4 colorHandleSelAlign;
+ vec4 colorHandleSelAutoclamp;
+ vec4 colorNurbUline;
+ vec4 colorNurbSelUline;
+ vec4 colorActiveSpline;
+
+ vec4 colorBonePose;
+
+ vec4 colorCurrentFrame;
+
+ vec4 colorGrid;
+ vec4 colorGridEmphasise;
+ vec4 colorGridAxisX;
+ vec4 colorGridAxisY;
+ vec4 colorGridAxisZ;
+
+ float sizeLampCenter;
+ float sizeLampCircle;
+ float sizeLampCircleShadow;
+ float sizeVertex;
+ float sizeEdge;
+ float sizeEdgeFix;
+ float sizeFaceDot;
+
+ float gridDistance;
+ float gridResolution;
+ float gridSubdivisions;
+ float gridScale;
+};
diff --git a/source/blender/draw/modes/shaders/common_hair_lib.glsl b/source/blender/draw/modes/shaders/common_hair_lib.glsl
new file mode 100644
index 00000000000..552690ba972
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_hair_lib.glsl
@@ -0,0 +1,190 @@
+/**
+ * Library to create hairs dynamically from control points.
+ * This is less bandwidth intensive than fetching the vertex attributes
+ * but does more ALU work per vertex. This also reduce the number
+ * of data the CPU has to precompute and transfert for each update.
+ **/
+
+/**
+ * hairStrandsRes: Number of points per hair strand.
+ * 2 - no subdivision
+ * 3+ - 1 or more interpolated points per hair.
+ **/
+uniform int hairStrandsRes = 8;
+
+/**
+ * hairThicknessRes : Subdiv around the hair.
+ * 1 - Wire Hair: Only one pixel thick, independant of view distance.
+ * 2 - Polystrip Hair: Correct width, flat if camera is parallel.
+ * 3+ - Cylinder Hair: Massive calculation but potentially perfect. Still need proper support.
+ **/
+uniform int hairThicknessRes = 1;
+
+/* Hair thickness shape. */
+uniform float hairRadRoot = 0.01;
+uniform float hairRadTip = 0.0;
+uniform float hairRadShape = 0.5;
+uniform bool hairCloseTip = true;
+
+/* -- Per control points -- */
+uniform samplerBuffer hairPointBuffer; /* RGBA32F */
+#define point_position xyz
+#define point_time w /* Position along the hair length */
+
+/* -- Per strands data -- */
+uniform usamplerBuffer hairStrandBuffer; /* R32UI */
+
+/* Not used, use one buffer per uv layer */
+//uniform samplerBuffer hairUVBuffer; /* RG32F */
+//uniform samplerBuffer hairColBuffer; /* RGBA16 linear color */
+
+void unpack_strand_data(uint data, out int strand_offset, out int strand_segments)
+{
+#if 0 /* Pack point count */
+ // strand_offset = (data & 0x1FFFFFFFu);
+ // strand_segments = 1u << (data >> 29u); /* We only need 3 bits to store subdivision level. */
+#else
+ strand_offset = int(data & 0x00FFFFFFu);
+ strand_segments = int(data >> 24u);
+#endif
+}
+
+/* -- Subdivision stage -- */
+/**
+ * We use a transform feedback to preprocess the strands and add more subdivision to it.
+ * For the moment theses are simple smooth interpolation but one could hope to see the full
+ * children particle modifiers being evaluated at this stage.
+ *
+ * If no more subdivision is needed, we can skip this step.
+ **/
+
+#ifdef HAIR_PHASE_SUBDIV
+int hair_get_base_id(float local_time, int strand_segments, out float interp_time)
+{
+ float time_per_strand_seg = 1.0 / float(strand_segments);
+
+ float ratio = local_time / time_per_strand_seg;
+ interp_time = fract(ratio);
+
+ return int(ratio);
+}
+
+void hair_get_interp_attribs(out vec4 data0, out vec4 data1, out vec4 data2, out vec4 data3, out float interp_time)
+{
+ float local_time = float(gl_VertexID % hairStrandsRes) / float(hairStrandsRes - 1);
+
+ int hair_id = gl_VertexID / hairStrandsRes;
+ uint strand_data = texelFetch(hairStrandBuffer, hair_id).x;
+
+ int strand_offset, strand_segments;
+ unpack_strand_data(strand_data, strand_offset, strand_segments);
+
+ int id = hair_get_base_id(local_time, strand_segments, interp_time);
+
+ int ofs_id = id + strand_offset;
+
+ data0 = texelFetch(hairPointBuffer, ofs_id - 1);
+ data1 = texelFetch(hairPointBuffer, ofs_id);
+ data2 = texelFetch(hairPointBuffer, ofs_id + 1);
+ data3 = texelFetch(hairPointBuffer, ofs_id + 2);
+
+ if (id <= 0) {
+ /* root points. Need to reconstruct previous data. */
+ data0 = data1 * 2.0 - data2;
+ }
+ if (id + 1 >= strand_segments) {
+ /* tip points. Need to reconstruct next data. */
+ data3 = data2 * 2.0 - data1;
+ }
+}
+#endif
+
+/* -- Drawing stage -- */
+/**
+ * For final drawing, the vertex index and the number of vertex per segment
+ **/
+
+#ifndef HAIR_PHASE_SUBDIV
+int hair_get_strand_id(void)
+{
+ return gl_VertexID / (hairStrandsRes * hairThicknessRes);
+}
+
+int hair_get_base_id(void)
+{
+ return gl_VertexID / hairThicknessRes;
+}
+
+/* Copied from cycles. */
+float hair_shaperadius(float shape, float root, float tip, float time)
+{
+ float radius = 1.0 - time;
+
+ if (shape < 0.0) {
+ radius = pow(radius, 1.0 + shape);
+ }
+ else {
+ radius = pow(radius, 1.0 / (1.0 - shape));
+ }
+
+ if (hairCloseTip && (time > 0.99)) {
+ return 0.0;
+ }
+
+ return (radius * (root - tip)) + tip;
+}
+
+void hair_get_pos_tan_binor_time(
+ bool is_persp, vec3 camera_pos, vec3 camera_z,
+ out vec3 wpos, out vec3 wtan, out vec3 wbinor, out float time, out float thickness, out float thick_time)
+{
+ int id = hair_get_base_id();
+ vec4 data = texelFetch(hairPointBuffer, id);
+ wpos = data.point_position;
+ time = data.point_time;
+ if (time == 0.0) {
+ /* Hair root */
+ wtan = texelFetch(hairPointBuffer, id + 1).point_position - wpos;
+ }
+ else {
+ wtan = wpos - texelFetch(hairPointBuffer, id - 1).point_position;
+ }
+
+ vec3 camera_vec = (is_persp) ? wpos - camera_pos : -camera_z;
+ wbinor = normalize(cross(camera_vec, wtan));
+
+ thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time);
+
+ if (hairThicknessRes > 1) {
+ thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1);
+ thick_time = thickness * (thick_time * 2.0 - 1.0);
+
+ wpos += wbinor * thick_time;
+ }
+}
+
+vec2 hair_get_customdata_vec2(const samplerBuffer cd_buf)
+{
+ int id = hair_get_strand_id();
+ return texelFetch(cd_buf, id).rg;
+}
+
+vec3 hair_get_customdata_vec3(const samplerBuffer cd_buf)
+{
+ int id = hair_get_strand_id();
+ return texelFetch(cd_buf, id).rgb;
+}
+
+vec4 hair_get_customdata_vec4(const samplerBuffer cd_buf)
+{
+ int id = hair_get_strand_id();
+ return texelFetch(cd_buf, id).rgba;
+}
+
+vec3 hair_get_strand_pos(void)
+{
+ int id = hair_get_strand_id() * hairStrandsRes;
+ return texelFetch(hairPointBuffer, id).point_position;
+}
+
+#endif
diff --git a/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl b/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl
new file mode 100644
index 00000000000..9f412c57db3
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_hair_refine_vert.glsl
@@ -0,0 +1,55 @@
+
+/* To be compiled with common_hair_lib.glsl */
+
+out vec4 outData;
+
+vec4 get_weights_cardinal(float t)
+{
+ float t2 = t * t;
+ float t3 = t2 * t;
+#if defined(CARDINAL)
+ float fc = 0.71;
+#else /* defined(CATMULL_ROM) */
+ float fc = 0.5;
+#endif
+
+ vec4 weights;
+ /* GLSL Optimized version of key_curve_position_weights() */
+ float fct = t * fc;
+ float fct2 = t2 * fc;
+ float fct3 = t3 * fc;
+ weights.x = ( fct2 * 2.0 - fct3) - fct;
+ weights.y = ( t3 * 2.0 - fct3) + (-t2 * 3.0 + fct2) + 1.0;
+ weights.z = (-t3 * 2.0 + fct3) + ( t2 * 3.0 - (2.0 * fct2)) + fct;
+ weights.w = fct3 - fct2;
+ return weights;
+}
+
+/* TODO(fclem): This one is buggy, find why. (it's not the optimization!!) */
+vec4 get_weights_bspline(float t)
+{
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ vec4 weights;
+ /* GLSL Optimized version of key_curve_position_weights() */
+ weights.xz = vec2(-0.16666666, -0.5) * t3 + (0.5 * t2 + 0.5 * vec2(-t, t) + 0.16666666);
+ weights.y = ( 0.5 * t3 - t2 + 0.66666666);
+ weights.w = ( 0.16666666 * t3);
+ return weights;
+}
+
+vec4 interp_data(vec4 v0, vec4 v1, vec4 v2, vec4 v3, vec4 w)
+{
+ return v0 * w.x + v1 * w.y + v2 * w.z + v3 * w.w;
+}
+
+void main(void)
+{
+ float interp_time;
+ vec4 data0, data1, data2, data3;
+ hair_get_interp_attribs(data0, data1, data2, data3, interp_time);
+
+ vec4 weights = get_weights_cardinal(interp_time);
+ outData = interp_data(data0, data1, data2, data3, weights);
+}
diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl
new file mode 100644
index 00000000000..d261d263a6f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/common_view_lib.glsl
@@ -0,0 +1,14 @@
+/* keep in sync with DRWManager.view_data */
+layout(std140) uniform viewBlock {
+ /* Same order as DRWViewportMatrixType */
+ mat4 ViewProjectionMatrix;
+ mat4 ViewProjectionMatrixInverse;
+ mat4 ViewMatrix;
+ mat4 ViewMatrixInverse;
+ mat4 ProjectionMatrix;
+ mat4 ProjectionMatrixInverse;
+
+ vec4 CameraTexCoFactors;
+
+ vec4 clipPlanes[2];
+};
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl
new file mode 100644
index 00000000000..e78462b6915
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_frag.glsl
@@ -0,0 +1,22 @@
+
+flat in int vertFlag;
+
+#define VERTEX_SELECTED (1 << 0)
+#define VERTEX_ACTIVE (1 << 1)
+
+out vec4 FragColor;
+
+void main()
+{
+ /* TODO: vertex size */
+
+ if ((vertFlag & VERTEX_SELECTED) != 0) {
+ FragColor = colorVertexSelect;
+ }
+ else if ((vertFlag & VERTEX_ACTIVE) != 0) {
+ FragColor = colorEditMeshActive;
+ }
+ else {
+ FragColor = colorVertex;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl
new file mode 100644
index 00000000000..9da8d9b50d7
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_handle_geom.glsl
@@ -0,0 +1,79 @@
+
+#define ACTIVE_NURB 1 << 7 /* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */
+
+layout(lines) in;
+layout(line_strip, max_vertices = 6) out;
+
+uniform vec2 viewportSize;
+
+flat in int vertFlag[];
+
+flat out vec4 finalColor;
+
+void main()
+{
+ /* TODO: vertex size */
+
+ vec4 v1 = gl_in[0].gl_Position;
+ vec4 v2 = gl_in[1].gl_Position;
+
+ int is_active_nurb = vertFlag[1] & ACTIVE_NURB;
+ int color_id = vertFlag[1] ^ is_active_nurb;
+
+ if (is_active_nurb != 0) {
+ /* draw the outline. */
+ vec2 v1_2 = (v2.xy/v2.w - v1.xy/v1.w);
+ vec2 offset;
+
+ if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) {
+ offset = vec2(2.0 / viewportSize.x, 0.0);
+ }
+ else {
+ offset = vec2(0.0, 2.0 / viewportSize.y);
+ }
+
+ finalColor = colorActiveSpline;
+
+ gl_Position = v1;
+ gl_Position.xy += offset * v1.w;
+ EmitVertex();
+
+ gl_Position = v2;
+ gl_Position.xy += offset * v2.w;
+ EmitVertex();
+
+ EndPrimitive();
+
+ gl_Position = v1;
+ gl_Position.xy -= offset * v1.w;
+ EmitVertex();
+
+ gl_Position = v2;
+ gl_Position.xy -= offset * v2.w;
+ EmitVertex();
+
+ EndPrimitive();
+ }
+
+ if (color_id == 0) finalColor = colorHandleFree;
+ else if (color_id == 1) finalColor = colorHandleAuto;
+ else if (color_id == 2) finalColor = colorHandleVect;
+ else if (color_id == 3) finalColor = colorHandleAlign;
+ else if (color_id == 4) finalColor = colorHandleAutoclamp;
+ else if (color_id == 5) finalColor = colorHandleSelFree;
+ else if (color_id == 6) finalColor = colorHandleSelAuto;
+ else if (color_id == 7) finalColor = colorHandleSelVect;
+ else if (color_id == 8) finalColor = colorHandleSelAlign;
+ else if (color_id == 9) finalColor = colorHandleSelAutoclamp;
+ else if (color_id == 10) finalColor = colorNurbUline;
+ else if (color_id == 11) finalColor = colorNurbSelUline;
+ else finalColor = colorVertexSelect;
+
+ gl_Position = v1;
+ EmitVertex();
+
+ gl_Position = v2;
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl
new file mode 100644
index 00000000000..9150ef8cd63
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_curve_overlay_loosevert_vert.glsl
@@ -0,0 +1,39 @@
+
+/* Draw Curve Vertices */
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec3 pos;
+in int data;
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out int vertFlag;
+flat out int clipCase;
+
+/* See fragment shader */
+noperspective out vec4 eData1;
+flat out vec4 eData2;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ clipCase = 0;
+
+ vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* only vertex position 0 is used */
+ eData1 = eData2 = vec4(1e10);
+ eData2.zw = proj(pPos);
+
+ vertFlag = data;
+
+ gl_Position = pPos;
+ gl_PointSize = sizeVertex;
+}
diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl
new file mode 100644
index 00000000000..e78462b6915
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_frag.glsl
@@ -0,0 +1,22 @@
+
+flat in int vertFlag;
+
+#define VERTEX_SELECTED (1 << 0)
+#define VERTEX_ACTIVE (1 << 1)
+
+out vec4 FragColor;
+
+void main()
+{
+ /* TODO: vertex size */
+
+ if ((vertFlag & VERTEX_SELECTED) != 0) {
+ FragColor = colorVertexSelect;
+ }
+ else if ((vertFlag & VERTEX_ACTIVE) != 0) {
+ FragColor = colorEditMeshActive;
+ }
+ else {
+ FragColor = colorVertex;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl
new file mode 100644
index 00000000000..0cbc66a2b1f
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_lattice_overlay_loosevert_vert.glsl
@@ -0,0 +1,39 @@
+
+/* Draw Lattice Vertices */
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec3 pos;
+in int data;
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out int vertFlag;
+flat out int clipCase;
+
+/* See fragment shader */
+noperspective out vec4 eData1;
+flat out vec4 eData2;
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ clipCase = 0;
+
+ vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* only vertex position 0 is used */
+ eData1 = eData2 = vec4(1e10);
+ eData2.zw = proj(pPos);
+
+ vertFlag = data;
+
+ gl_PointSize = sizeVertex;
+ gl_Position = pPos;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl
new file mode 100644
index 00000000000..dabbb4a321a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_common_lib.glsl
@@ -0,0 +1,51 @@
+#define EDGE_EXISTS (1 << 0)
+#define EDGE_ACTIVE (1 << 1)
+#define EDGE_SELECTED (1 << 2)
+#define EDGE_SEAM (1 << 3)
+#define EDGE_SHARP (1 << 4)
+#define EDGE_VERTEX_ACTIVE (1 << (0 + 8))
+#define EDGE_VERTEX_SELECTED (1 << (1 + 8))
+
+#define VERTEX_ACTIVE (1 << 0)
+#define VERTEX_SELECTED (1 << 1)
+
+
+vec4 EDIT_MESH_edge_color_outer(int edge_flag, bool face_active, float crease, float bweight)
+{
+ vec4 color = vec4(0.0);
+ color = ((edge_flag & EDGE_SHARP) != 0) ? colorEdgeSharp : color;
+ color = (crease > 0.0) ? vec4(colorEdgeCrease.rgb, crease) : color;
+ color = (bweight > 0.0) ? vec4(colorEdgeBWeight.rgb, bweight) : color;
+ color = ((edge_flag & EDGE_SEAM) != 0) ? colorEdgeSeam : color;
+
+ if (face_active)
+ {
+ color = colorEditMeshActive;
+ }
+ return color;
+}
+
+vec4 EDIT_MESH_edge_color_inner(int edge_flag, bool face_active)
+{
+#ifdef EDGE_SELECTION
+ vec4 color = colorWireEdit;
+ color = ((edge_flag & EDGE_SELECTED) != 0) ? colorEdgeSelect : color;
+ color = ((edge_flag & EDGE_ACTIVE) != 0) ? colorEditMeshActive : color;
+
+#else
+ vec4 color = colorWireEdit;
+ color = ((edge_flag & EDGE_SELECTED) != 0) ? colorEdgeSelect : color;
+#endif
+ return color;
+}
+
+vec4 EDIT_MESH_vertex_color(int vertex_flag)
+{
+ if ((vertex_flag & (VERTEX_ACTIVE | VERTEX_SELECTED)) != 0)
+ {
+ return colorEdgeSelect;
+ }
+ else {
+ return colorWireEdit;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl
new file mode 100644
index 00000000000..71cc1ccde8d
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_frag.glsl
@@ -0,0 +1,19 @@
+
+flat in int isSelected;
+#ifdef VERTEX_FACING
+flat in float facing;
+#endif
+
+out vec4 FragColor;
+
+void main()
+{
+ if (isSelected != 0)
+ FragColor = colorFaceDot;
+ else
+ FragColor = colorVertex;
+
+#ifdef VERTEX_FACING
+ FragColor.a *= 1.0 - abs(facing) * 0.4;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl
new file mode 100644
index 00000000000..fa3934c4b77
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facedot_vert.glsl
@@ -0,0 +1,31 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec4 norAndFlag;
+
+flat out int isSelected;
+
+#ifdef VERTEX_FACING
+uniform mat4 ProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat3 NormalMatrix;
+
+flat out float facing;
+#endif
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ /* Bias Facedot Z position in clipspace. */
+ gl_Position.z -= 0.0002;
+ gl_PointSize = sizeFaceDot;
+ isSelected = int(norAndFlag.w);
+#ifdef VERTEX_FACING
+ vec3 view_normal = normalize(NormalMatrix * norAndFlag.xyz);
+ vec3 view_vec = (ProjectionMatrix[3][3] == 0.0)
+ ? normalize((ModelViewMatrix * vec4(pos, 1.0)).xyz)
+ : vec3(0.0, 0.0, 1.0);
+ facing = dot(view_vec, view_normal);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
new file mode 100644
index 00000000000..2e729009a38
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_frag.glsl
@@ -0,0 +1,7 @@
+flat in vec4 faceColor;
+out vec4 FragColor;
+
+void main()
+{
+ FragColor = faceColor;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl
new file mode 100644
index 00000000000..c9de6d29524
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_facefill_vert.glsl
@@ -0,0 +1,15 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in ivec4 data;
+
+flat out vec4 faceColor;
+
+#define FACE_SELECTED (1 << 3)
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ faceColor = ((data.x & FACE_SELECTED) != 0)? colorFaceSelect: colorFace;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
new file mode 100644
index 00000000000..09d0b0a910d
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_frag.glsl
@@ -0,0 +1,123 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+/* This is not perfect. Only a subset of intel gpus are affected.
+ * This fix have some performance impact.
+ * TODO Refine the range to only affect GPUs. */
+
+uniform float faceAlphaMod;
+
+flat in vec3 edgesCrease;
+flat in vec3 edgesBweight;
+flat in vec4 faceColor;
+flat in ivec3 flag;
+#ifdef VERTEX_SELECTION
+in vec3 vertexColor;
+#endif
+#ifdef VERTEX_FACING
+in float facing;
+#endif
+
+flat in vec2 ssPos[3];
+
+out vec4 FragColor;
+
+/* Vertex flag is shifted and combined with the edge flag */
+#define FACE_ACTIVE (1 << (2 + 8))
+
+#define LARGE_EDGE_SIZE 3.0
+
+/* Style Parameters in pixel */
+
+void distToEdgeAndPoint(vec2 dir, vec2 ori, out float edge, out float point)
+{
+ dir = normalize(dir.xy);
+ vec2 of = gl_FragCoord.xy - ori;
+ point = dot(of, of);
+ float dof = dot(dir, of);
+ edge = sqrt(abs(point - dof * dof));
+ point = sqrt(point);
+}
+
+void colorDist(vec4 color, float dist)
+{
+ FragColor = (dist < 0) ? color : FragColor;
+}
+
+#ifdef ANTI_ALIASING
+void colorDistEdge(vec4 color, float dist)
+{
+ FragColor.rgb *= FragColor.a;
+ FragColor = mix(color, FragColor, clamp(dist, 0.0, 1.0));
+ FragColor.rgb /= max(1e-8, FragColor.a);
+}
+#else
+#define colorDistEdge colorDist
+#endif
+
+void main()
+{
+ vec3 e, p;
+
+ /* Step 1 : Computing Distances */
+ distToEdgeAndPoint((ssPos[1] - ssPos[0]) + 1e-8, ssPos[0], e.z, p.x);
+ distToEdgeAndPoint((ssPos[2] - ssPos[1]) + 1e-8, ssPos[1], e.x, p.y);
+ distToEdgeAndPoint((ssPos[0] - ssPos[2]) + 1e-8, ssPos[2], e.y, p.z);
+
+ /* Step 2 : coloring (order dependant) */
+
+ /* Face */
+ FragColor = faceColor;
+ FragColor.a *= faceAlphaMod;
+
+ /* Edges */
+ for (int v = 0; v < 3; ++v) {
+ if ((flag[v] & EDGE_EXISTS) != 0) {
+ /* Outer large edge */
+ float largeEdge = e[v] - sizeEdge * LARGE_EDGE_SIZE;
+
+ vec4 large_edge_color = EDIT_MESH_edge_color_outer(flag[v], (flag[0]& FACE_ACTIVE) != 0, edgesCrease[v], edgesBweight[v]);
+
+ if (large_edge_color.a != 0.0) {
+ colorDistEdge(large_edge_color, largeEdge);
+ }
+
+ /* Inner thin edge */
+ float innerEdge = e[v] - sizeEdge;
+#ifdef ANTI_ALIASING
+ innerEdge += 0.4;
+#endif
+
+#ifdef VERTEX_SELECTION
+ colorDistEdge(vec4(vertexColor, 1.0), innerEdge);
+#else
+ vec4 inner_edge_color = EDIT_MESH_edge_color_inner(flag[v], (flag[0]& FACE_ACTIVE) != 0);
+ colorDistEdge(inner_edge_color, innerEdge);
+#endif
+ }
+ }
+
+ /* Points */
+#ifdef VERTEX_SELECTION
+ for (int v = 0; v < 3; ++v) {
+ float size = p[v] - sizeVertex;
+
+ vec4 point_color = colorVertex;
+ point_color = ((flag[v] & EDGE_VERTEX_SELECTED) != 0) ? colorVertexSelect : point_color;
+ point_color = ((flag[v] & EDGE_VERTEX_ACTIVE) != 0) ? vec4(colorEditMeshActive.xyz, 1.0) : point_color;
+
+ colorDist(point_color, size);
+ }
+#endif
+
+#ifdef VERTEX_FACING
+ FragColor.a *= 1.0 - abs(facing) * 0.4;
+#endif
+
+ /* don't write depth if not opaque */
+ if (FragColor.a == 0.0) discard;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
new file mode 100644
index 00000000000..88cb6c07a94
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_edge.glsl
@@ -0,0 +1,113 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+layout(lines) in;
+layout(triangle_strip, max_vertices=6) out;
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec4 vPos[];
+in vec4 pPos[];
+in ivec4 vData[];
+#ifdef VERTEX_FACING
+in float vFacing[];
+#endif
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out vec4 faceColor;
+flat out ivec3 flag;
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+#ifdef VERTEX_FACING
+out float facing;
+#endif
+
+/* See fragment shader */
+flat out vec2 ssPos[3];
+
+#define FACE_ACTIVE (1 << 2)
+#define FACE_SELECTED (1 << 3)
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void doVertex(int v, vec4 pos)
+{
+#ifdef VERTEX_SELECTION
+ vertexColor = EDIT_MESH_vertex_color(vData[v].x).rgb;
+#endif
+
+#ifdef VERTEX_FACING
+ facing = vFacing[v];
+#endif
+
+ gl_Position = pos;
+
+ EmitVertex();
+}
+
+void main()
+{
+ /* Face */
+ faceColor = vec4(0.0);
+
+ /* Proj Vertex */
+ vec2 pos[2] = vec2[2](proj(pPos[0]), proj(pPos[1]));
+
+ /* little optimization use a vec4 to vectorize
+ * following operations */
+ vec4 dirs1, dirs2;
+
+ /* Edge normalized vector */
+ dirs1.xy = normalize(pos[1] - pos[0]);
+
+ /* perpendicular to dir */
+ dirs1.zw = vec2(-dirs1.y, dirs1.x);
+
+ /* Make it view independent */
+ dirs1 *= sizeEdgeFix / viewportSize.xyxy;
+
+ dirs2 = dirs1;
+
+ /* Perspective */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ /* vPos[i].z is negative and we don't want
+ * our fixvec to be flipped */
+ dirs1 *= -vPos[0].z;
+ dirs2 *= -vPos[1].z;
+ }
+
+ /* Edge / Vert data */
+ ssPos[0] = ssPos[2] = pos[0];
+ ssPos[1] = pos[1];
+ flag[0] = flag[2] = (vData[0].x << 8);
+ flag[1] = (vData[1].x << 8);
+
+ doVertex(0, pPos[0] + vec4(-dirs1.xy, 0.0, 0.0));
+ doVertex(0, pPos[0] + vec4( dirs1.zw, 0.0, 0.0));
+ doVertex(0, pPos[0] + vec4(-dirs1.zw, 0.0, 0.0));
+
+ flag[2] |= vData[0].y;
+ edgesCrease[2] = vData[0].z / 255.0;
+ edgesBweight[2] = vData[0].w / 255.0;
+
+ doVertex(1, pPos[1] + vec4( dirs2.zw, 0.0, 0.0));
+ doVertex(1, pPos[1] + vec4(-dirs2.zw, 0.0, 0.0));
+
+ flag[2] = 0;
+ doVertex(1, pPos[1] + vec4( dirs2.xy, 0.0, 0.0));
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
new file mode 100644
index 00000000000..e0ec6e50dc2
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_geom_tri.glsl
@@ -0,0 +1,208 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+layout(triangles) in;
+
+/* This is not perfect. Only a subset of intel gpus are affected.
+ * This fix have some performance impact.
+ * TODO Refine the range to only affect GPUs. */
+
+#ifdef EDGE_FIX
+/* To fix the edge artifacts, we render
+ * an outline strip around the screenspace
+ * triangle. Order is important.
+ * TODO diagram
+ */
+
+#ifdef VERTEX_SELECTION
+layout(triangle_strip, max_vertices=23) out;
+#else
+layout(triangle_strip, max_vertices=17) out;
+#endif
+#else
+layout(triangle_strip, max_vertices=3) out;
+#endif
+
+uniform mat4 ProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec4 vPos[];
+in vec4 pPos[];
+in ivec4 vData[];
+#ifdef VERTEX_FACING
+in float vFacing[];
+#endif
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out vec4 faceColor;
+flat out ivec3 flag;
+flat out int clipCase;
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+#ifdef VERTEX_FACING
+out float facing;
+#endif
+
+/* See fragment shader */
+flat out vec2 ssPos[3];
+
+#define FACE_ACTIVE (1 << 2)
+#define FACE_SELECTED (1 << 3)
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void doVertex(int v)
+{
+#ifdef VERTEX_SELECTION
+ vertexColor = EDIT_MESH_vertex_color(vData[v].x).rgb;
+#endif
+
+#ifdef VERTEX_FACING
+ facing = vFacing[v];
+#endif
+
+ gl_Position = pPos[v];
+
+ EmitVertex();
+}
+
+void doLoopStrip(int v, vec3 offset)
+{
+ doVertex(v);
+
+ gl_Position.xyz += offset;
+
+ EmitVertex();
+}
+
+#ifdef ANTI_ALIASING
+#define Z_OFFSET 0.008
+#else
+#define Z_OFFSET 0.0
+#endif
+
+void main()
+{
+ /* Edge */
+ ivec3 eflag; vec3 ecrease, ebweight;
+ for (int v = 0; v < 3; ++v) {
+ flag[v] = eflag[v] = vData[v].y | (vData[v].x << 8);
+ edgesCrease[v] = ecrease[v] = vData[v].z / 255.0;
+ edgesBweight[v] = ebweight[v] = vData[v].w / 255.0;
+ }
+
+ /* Face */
+ if ((vData[0].x & FACE_ACTIVE) != 0)
+ faceColor = colorFaceSelect;
+ else if ((vData[0].x & FACE_SELECTED) != 0)
+ faceColor = colorFaceSelect;
+ else
+ faceColor = colorFace;
+
+ /* Vertex */
+ vec2 pos[3];
+ ssPos[0] = pos[0] = proj(pPos[0]);
+ ssPos[1] = pos[1] = proj(pPos[1]);
+ ssPos[2] = pos[2] = proj(pPos[2]);
+
+ doVertex(0);
+ doVertex(1);
+ doVertex(2);
+
+#ifdef EDGE_FIX
+ vec2 fixvec[6];
+ vec2 fixvecaf[6];
+ vec2 cornervec[3];
+
+ /* This fix the case when 2 vertices are perfectly aligned
+ * and corner vectors have nowhere to go.
+ * ie: length(cornervec[i]) == 0 */
+ const float epsilon = 1e-2; /* in pixel so not that much */
+ const vec2 bias[3] = vec2[3](
+ vec2( epsilon, epsilon),
+ vec2(-epsilon, epsilon),
+ vec2( 0.0, -epsilon)
+ );
+
+ for (int i = 0; i < 3; ++i) {
+ int i1 = (i + 1) % 3;
+ int i2 = (i + 2) % 3;
+
+ vec2 v1 = ssPos[i] + bias[i];
+ vec2 v2 = ssPos[i1] + bias[i1];
+ vec2 v3 = ssPos[i2] + bias[i2];
+
+ /* Edge normalized vector */
+ vec2 dir = normalize(v2 - v1);
+ vec2 dir2 = normalize(v3 - v1);
+
+ cornervec[i] = -normalize(dir + dir2);
+
+ /* perpendicular to dir */
+ vec2 perp = vec2(-dir.y, dir.x);
+
+ /* Backface case */
+ if (dot(perp, dir2) > 0) {
+ perp = -perp;
+ }
+
+ /* Make it view independent */
+ perp *= sizeEdgeFix / viewportSize;
+ cornervec[i] *= sizeEdgeFix / viewportSize;
+ fixvec[i] = fixvecaf[i] = perp;
+
+ /* Perspective */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ /* vPos[i].z is negative and we don't want
+ * our fixvec to be flipped */
+ fixvec[i] *= -vPos[i].z;
+ fixvecaf[i] *= -vPos[i1].z;
+ cornervec[i] *= -vPos[i].z;
+ }
+ }
+
+ /* to not let face color bleed */
+ faceColor.a = 0.0;
+
+ /* Start with the same last vertex to create a
+ * degenerate triangle in order to "create"
+ * a new triangle strip */
+ for (int i = 2; i < 5; ++i) {
+ int vbe = (i - 1) % 3;
+ int vaf = (i + 1) % 3;
+ int v = i % 3;
+
+ doLoopStrip(v, vec3(fixvec[v], Z_OFFSET));
+
+ /* Only shade the edge that we are currently drawing.
+ * (fix corner bleeding) */
+ flag[vbe] |= (EDGE_EXISTS & eflag[vbe]);
+ flag[vaf] &= ~EDGE_EXISTS;
+ flag[v] &= ~EDGE_EXISTS;
+ doLoopStrip(vaf, vec3(fixvecaf[v], Z_OFFSET));
+
+ /* corner vertices should not draw edges but draw point only */
+ flag[vbe] &= ~EDGE_EXISTS;
+#ifdef VERTEX_SELECTION
+ doLoopStrip(vaf, vec3(cornervec[vaf], Z_OFFSET));
+#endif
+ }
+
+ /* finish the loop strip */
+ doLoopStrip(2, vec3(fixvec[2], Z_OFFSET));
+#endif
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl
new file mode 100644
index 00000000000..13d824c2410
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_loosevert_vert.glsl
@@ -0,0 +1,52 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 viewportSize;
+
+in vec3 pos;
+in ivec4 data;
+
+/* these are the same for all vertices
+ * and does not need interpolation */
+flat out vec3 edgesCrease;
+flat out vec3 edgesBweight;
+flat out vec4 faceColor;
+flat out ivec3 flag;
+#ifdef VERTEX_SELECTION
+out vec3 vertexColor;
+#endif
+
+/* See fragment shader */
+flat out vec2 ssPos[3];
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+void main()
+{
+ edgesCrease = vec3(0.0);
+ edgesBweight = vec3(0.0);
+
+ vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* there is no face */
+ faceColor = vec4(0.0);
+
+#ifdef VERTEX_SELECTION
+ vertexColor = vec3(0.0);
+#endif
+
+ ssPos[0] = ssPos[1] = ssPos[2] = proj(pPos);
+ flag[0] = flag[1] = flag[2] = (data.x << 8);
+
+ gl_PointSize = sizeEdgeFix;
+ gl_Position = pPos;
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl
new file mode 100644
index 00000000000..8f94a105332
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_mix_frag.glsl
@@ -0,0 +1,22 @@
+
+out vec4 FragColor;
+
+uniform sampler2D wireColor;
+uniform sampler2D wireDepth;
+uniform sampler2D sceneDepth;
+uniform float alpha;
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ float wire_depth = texelFetch(wireDepth, uv, 0).r;
+ float scene_depth = texelFetch(sceneDepth, uv, 0).r;
+ vec4 wire_color = texelFetch(wireColor, uv, 0).rgba;
+
+ FragColor = wire_color;
+
+ /* Modulate alpha if occluded */
+ if (wire_depth > scene_depth) {
+ FragColor.a *= alpha;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl
new file mode 100644
index 00000000000..8ebfa4376f0
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_mesh_overlay_vert.glsl
@@ -0,0 +1,38 @@
+
+/* Solid Wirefram implementation
+ * Mike Erwin, Clément Foucault */
+
+/* This shader follows the principles of
+ * http://developer.download.nvidia.com/SDK/10/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf */
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in ivec4 data;
+
+out vec4 vPos;
+out vec4 pPos;
+out ivec4 vData;
+
+#ifdef VERTEX_FACING
+uniform mat4 ProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+in vec3 vnor;
+out float vFacing;
+#endif
+
+void main()
+{
+ vPos = ModelViewMatrix * vec4(pos, 1.0);
+ pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ vData = data;
+#ifdef VERTEX_FACING
+ vec3 view_normal = normalize(NormalMatrix * vnor);
+ vec3 view_vec = (ProjectionMatrix[3][3] == 0.0)
+ ? normalize(vPos.xyz)
+ : vec3(0.0, 0.0, 1.0);
+ vFacing = dot(view_vec, view_normal);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/edit_normals_geom.glsl b/source/blender/draw/modes/shaders/edit_normals_geom.glsl
new file mode 100644
index 00000000000..d17823f2f5a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_normals_geom.glsl
@@ -0,0 +1,15 @@
+
+layout(points) in;
+layout(line_strip, max_vertices=2) out;
+
+flat in vec4 v1[1];
+flat in vec4 v2[1];
+
+void main()
+{
+ gl_Position = v1[0];
+ EmitVertex();
+ gl_Position = v2[0];
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/edit_normals_vert.glsl b/source/blender/draw/modes/shaders/edit_normals_vert.glsl
new file mode 100644
index 00000000000..3ce7e618511
--- /dev/null
+++ b/source/blender/draw/modes/shaders/edit_normals_vert.glsl
@@ -0,0 +1,30 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 ProjectionMatrix;
+uniform float normalSize;
+
+in vec3 pos;
+
+#ifdef LOOP_NORMALS
+in vec3 lnor;
+#define nor lnor
+
+#elif defined(FACE_NORMALS)
+in vec4 norAndFlag;
+#define nor norAndFlag.xyz
+#else
+
+in vec3 vnor;
+#define nor vnor
+#endif
+
+flat out vec4 v1;
+flat out vec4 v2;
+
+void main()
+{
+ v1 = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ vec3 n = normalize(NormalMatrix * nor); /* viewspace */
+ v2 = v1 + ProjectionMatrix * vec4(n * normalSize, 0.0);
+}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
new file mode 100644
index 00000000000..eab107354d1
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl
@@ -0,0 +1,21 @@
+
+flat in vec4 finalColor;
+
+#ifndef USE_WIRE
+in vec2 texCoord_interp;
+#endif
+
+out vec4 fragColor;
+
+#ifndef USE_WIRE
+uniform sampler2D image;
+#endif
+
+void main()
+{
+#ifdef USE_WIRE
+ fragColor = finalColor;
+#else
+ fragColor = finalColor * texture(image, texCoord_interp);
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_empty_image_vert.glsl b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl
new file mode 100644
index 00000000000..c629fdcb7ef
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_empty_image_vert.glsl
@@ -0,0 +1,38 @@
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec2 aspect;
+
+/* ---- Instanciated Attribs ---- */
+in vec2 texCoord;
+in vec2 pos;
+/* ---- Per instance Attribs ---- */
+in mat4 InstanceModelMatrix;
+
+#ifdef USE_WIRE
+in vec3 color;
+#else
+in vec4 objectColor;
+#endif
+
+in float size;
+in vec2 offset;
+
+flat out vec4 finalColor;
+
+#ifndef USE_WIRE
+out vec2 texCoord_interp;
+#endif
+
+void main()
+{
+ gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(
+ (pos[0] + offset[0]) * (size * aspect[0]),
+ (pos[1] + offset[1]) * (size * aspect[1]),
+ 0.0, 1.0);
+#ifdef USE_WIRE
+ finalColor = vec4(color, 1.0);
+#else
+ texCoord_interp = texCoord;
+ finalColor = objectColor;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_grid_frag.glsl b/source/blender/draw/modes/shaders/object_grid_frag.glsl
new file mode 100644
index 00000000000..2b04bb0d855
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_grid_frag.glsl
@@ -0,0 +1,227 @@
+
+/* Infinite grid
+ * Clément Foucault */
+
+out vec4 FragColor;
+
+uniform mat4 ProjectionMatrix;
+uniform vec3 cameraPos;
+uniform vec3 planeNormal;
+uniform vec3 planeAxes;
+uniform vec3 eye;
+uniform vec4 gridSettings;
+uniform vec2 viewportSize;
+uniform vec4 screenvecs[3];
+uniform float gridOneOverLogSubdiv;
+uniform sampler2D depthBuffer;
+
+#define gridDistance gridSettings.x
+#define gridResolution gridSettings.y
+#define gridScale gridSettings.z
+#define gridSubdiv gridSettings.w
+
+uniform int gridFlag;
+
+#define AXIS_X (1 << 0)
+#define AXIS_Y (1 << 1)
+#define AXIS_Z (1 << 2)
+#define GRID (1 << 3)
+#define PLANE_XY (1 << 4)
+#define PLANE_XZ (1 << 5)
+#define PLANE_YZ (1 << 6)
+#define GRID_BACK (1 << 9) /* grid is behind objects */
+
+#define GRID_LINE_SMOOTH 1.15
+
+float get_grid(vec2 co, vec2 fwidthCos, float grid_size)
+{
+ float half_size = grid_size / 2.0;
+ /* triangular wave pattern, amplitude is [0, half_size] */
+ vec2 grid_domain = abs(mod(co + half_size, grid_size) - half_size);
+ /* modulate by the absolute rate of change of the coordinates
+ * (make lines have the same width under perspective) */
+ grid_domain /= fwidthCos;
+
+ /* collapse waves and normalize */
+ grid_domain.x = min(grid_domain.x, grid_domain.y) / half_size;
+
+ return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH / grid_size, grid_domain.x * 0.5);
+}
+
+vec3 get_axes(vec3 co, vec3 fwidthCos, float line_size)
+{
+ vec3 axes_domain = abs(co);
+ /* modulate by the absolute rate of change of the coordinates
+ * (make line have the same width under perspective) */
+ axes_domain /= fwidthCos;
+
+ return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH, axes_domain - line_size);
+}
+
+vec3 get_floor_pos(vec2 uv, out vec3 wPos)
+{
+ vec3 camera_vec, camera_pos, corner_pos;
+ vec3 floored_pos = planeAxes * floor(screenvecs[2].xyz);
+ corner_pos = screenvecs[2].xyz - floored_pos;
+
+ vec3 pixel_pos = corner_pos + uv.x * screenvecs[0].xyz + uv.y * screenvecs[1].xyz;
+
+ /* if perspective */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ camera_pos = cameraPos - floored_pos;
+ camera_vec = normalize(pixel_pos - camera_pos);
+ }
+ else {
+ camera_pos = pixel_pos;
+ camera_vec = normalize(eye);
+ }
+
+ float plane_normal_dot_camera_vec = dot(planeNormal, camera_vec);
+ float p = -dot(planeNormal, camera_pos);
+ if (plane_normal_dot_camera_vec != 0) {
+ p /= plane_normal_dot_camera_vec;
+ }
+ vec3 plane = camera_pos + camera_vec * p;
+
+ /* fix residual imprecision */
+ plane *= planeAxes;
+
+ /* Recover non-offseted world position */
+ wPos = plane + floored_pos;
+
+ return plane;
+}
+
+void main()
+{
+ vec2 sPos = gl_FragCoord.xy / viewportSize; /* Screen [0,1] position */
+
+ /* To reduce artifacts, use a local version of the positions
+ * to compute derivatives since they are not position dependant.
+ * This gets rid of the blocky artifacts. Unfortunately we still
+ * need the world position for the grid to scale properly from the origin. */
+ vec3 gPos, wPos; /* Grid pos., World pos. */
+ gPos = get_floor_pos(sPos, wPos);
+
+ vec3 fwidthPos = fwidth(gPos);
+
+ float dist, fade;
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ vec3 viewvec = cameraPos - wPos;
+ dist = length(viewvec);
+ viewvec /= dist;
+
+ float angle;
+ if ((gridFlag & PLANE_XZ) > 0)
+ angle = viewvec.y;
+ else if ((gridFlag & PLANE_YZ) > 0)
+ angle = viewvec.x;
+ else
+ angle = viewvec.z;
+
+ angle = 1.0 - abs(angle);
+ angle *= angle;
+ fade = 1.0 - angle * angle;
+ fade *= 1.0 - smoothstep(0.0, gridDistance, dist - gridDistance);
+ }
+ else {
+ dist = abs(gl_FragCoord.z * 2.0 - 1.0);
+ fade = 1.0 - smoothstep(0.0, 0.5, dist - 0.5);
+ dist = 1.0; /* avoid branch after */
+
+ if ((gridFlag & PLANE_XY) > 0) {
+ float angle = 1.0 - abs(eye.z);
+ dist = 1.0 + angle * 2.0;
+ angle *= angle;
+ fade *= 1.0 - angle * angle;
+ }
+ }
+
+ if ((gridFlag & GRID) > 0) {
+ float grid_res = log(dist * gridResolution) * gridOneOverLogSubdiv;
+
+ float blend = fract(-max(grid_res, 0.0));
+ float lvl = floor(grid_res);
+
+ /* from biggest to smallest */
+ float scaleA = gridScale * pow(gridSubdiv, max(lvl - 1.0, 0.0));
+ float scaleB = gridScale * pow(gridSubdiv, max(lvl + 0.0, 0.0));
+ float scaleC = gridScale * pow(gridSubdiv, max(lvl + 1.0, 1.0));
+
+ vec2 grid_pos, grid_fwidth;
+ if ((gridFlag & PLANE_XZ) > 0) {
+ grid_pos = wPos.xz;
+ grid_fwidth = fwidthPos.xz;
+ }
+ else if ((gridFlag & PLANE_YZ) > 0) {
+ grid_pos = wPos.yz;
+ grid_fwidth = fwidthPos.yz;
+ }
+ else {
+ grid_pos = wPos.xy;
+ grid_fwidth = fwidthPos.xy;
+ }
+
+ float gridA = get_grid(grid_pos, grid_fwidth, scaleA);
+ float gridB = get_grid(grid_pos, grid_fwidth, scaleB);
+ float gridC = get_grid(grid_pos, grid_fwidth, scaleC);
+
+ FragColor = vec4(colorGrid.rgb, gridA * blend);
+ FragColor = mix(FragColor, vec4(mix(colorGrid.rgb, colorGridEmphasise.rgb, blend), 1.0), gridB);
+ FragColor = mix(FragColor, vec4(colorGridEmphasise.rgb, 1.0), gridC);
+ }
+ else {
+ FragColor = vec4(colorGrid.rgb, 0.0);
+ }
+
+ if ((gridFlag & (AXIS_X | AXIS_Y | AXIS_Z)) > 0) {
+ /* Setup axes 'domains' */
+ vec3 axes_dist, axes_fwidth;
+
+ if ((gridFlag & AXIS_X) > 0) {
+ axes_dist.x = dot(wPos.yz, planeAxes.yz);
+ axes_fwidth.x = dot(fwidthPos.yz, planeAxes.yz);
+ }
+ if ((gridFlag & AXIS_Y) > 0) {
+ axes_dist.y = dot(wPos.xz, planeAxes.xz);
+ axes_fwidth.y = dot(fwidthPos.xz, planeAxes.xz);
+ }
+ if ((gridFlag & AXIS_Z) > 0) {
+ axes_dist.z = dot(wPos.xy, planeAxes.xy);
+ axes_fwidth.z = dot(fwidthPos.xy, planeAxes.xy);
+ }
+
+ /* Computing all axes at once using vec3 */
+ vec3 axes = get_axes(axes_dist, axes_fwidth, 0.1);
+
+ if ((gridFlag & AXIS_X) > 0) {
+ FragColor = mix(FragColor, colorGridAxisX, axes.x);
+ }
+ if ((gridFlag & AXIS_Y) > 0) {
+ FragColor = mix(FragColor, colorGridAxisY, axes.y);
+ }
+ if ((gridFlag & AXIS_Z) > 0) {
+ FragColor = mix(FragColor, colorGridAxisZ, axes.z);
+ }
+ }
+
+ float scene_depth = texture(depthBuffer, sPos).r;
+ if ((gridFlag & GRID_BACK) > 0) {
+ fade *= (scene_depth == 1.0) ? 1.0 : 0.0;
+ }
+ else {
+ /* Manual, non hard, depth test:
+ * Progressively fade the grid below occluders
+ * (avoids poping visuals due to depth buffer precision) */
+ /* Add a small bias so the grid will always
+ * be on top of a mesh with the same depth. */
+ float grid_depth = gl_FragCoord.z - 1e-8;
+ /* Harder settings tend to flicker more,
+ * but have less "see through" appearance. */
+ const float test_hardness = 1e4;
+ fade *= 1.0 - clamp((grid_depth - scene_depth) * test_hardness, 0.0, 1.0);
+ }
+
+ FragColor.a *= fade;
+}
diff --git a/source/blender/draw/modes/shaders/object_grid_vert.glsl b/source/blender/draw/modes/shaders/object_grid_vert.glsl
new file mode 100644
index 00000000000..3f99d8b5d0a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_grid_vert.glsl
@@ -0,0 +1,63 @@
+
+/* Infinite grid
+ * Clément Foucault */
+
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ProjectionMatrix;
+uniform vec3 cameraPos;
+uniform vec4 gridSettings;
+
+#define gridDistance gridSettings.x
+#define gridResolution gridSettings.y
+#define gridScale gridSettings.z
+#define gridSubdiv gridSettings.w
+
+uniform int gridFlag;
+
+#define PLANE_XY (1 << 4)
+#define PLANE_XZ (1 << 5)
+#define PLANE_YZ (1 << 6)
+#define CLIP_Z_POS (1 << 7)
+#define CLIP_Z_NEG (1 << 8)
+
+in vec3 pos;
+
+void main()
+{
+ vec3 vert_pos, proj_camera_pos;
+
+ /* Project camera pos to the needed plane */
+ if ((gridFlag & PLANE_XY) > 0) {
+ vert_pos = vec3(pos.x, pos.y, 0.0);
+ proj_camera_pos = vec3(cameraPos.x, cameraPos.y, 0.0);
+ }
+ else if ((gridFlag & PLANE_XZ) > 0) {
+ vert_pos = vec3(pos.x, 0.0, pos.y);
+ proj_camera_pos = vec3(cameraPos.x, 0.0, cameraPos.z);
+ }
+ else {
+ vert_pos = vec3(0.0, pos.x, pos.y);
+ proj_camera_pos = vec3(0.0, cameraPos.y, cameraPos.z);
+ }
+
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ vert_pos *= gridDistance * 2.0;
+ }
+ else {
+ float viewdist = 1.0 / min(abs(ProjectionMatrix[0][0]), abs(ProjectionMatrix[1][1]));
+ vert_pos *= viewdist * gridDistance * 2.0;
+ }
+
+ vec3 realPos = proj_camera_pos + vert_pos;
+
+ /* Used for additional Z axis */
+ if ((gridFlag & CLIP_Z_POS) > 0) {
+ realPos.z = max(realPos.z, 0.0);
+ }
+ if ((gridFlag & CLIP_Z_NEG) > 0) {
+ realPos.z = min(-realPos.z, 0.0);
+ }
+
+ gl_Position = ViewProjectionMatrix * vec4(realPos, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
new file mode 100644
index 00000000000..d9616076dbf
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_lightprobe_grid_vert.glsl
@@ -0,0 +1,35 @@
+
+in vec3 pos;
+in vec3 nor;
+
+uniform mat4 ViewProjectionMatrix;
+
+uniform float sphere_size;
+uniform ivec3 grid_resolution;
+uniform vec3 corner;
+uniform vec3 increment_x;
+uniform vec3 increment_y;
+uniform vec3 increment_z;
+
+uniform int call_id; /* we don't want the builtin callId which would be 0. */
+uniform int baseId;
+
+flat out uint finalId;
+
+void main()
+{
+ vec3 ls_cell_location;
+ /* Keep in sync with update_irradiance_probe */
+ ls_cell_location.z = float(gl_InstanceID % grid_resolution.z);
+ ls_cell_location.y = float((gl_InstanceID / grid_resolution.z) % grid_resolution.y);
+ ls_cell_location.x = float(gl_InstanceID / (grid_resolution.z * grid_resolution.y));
+
+ vec3 ws_cell_location = corner +
+ (increment_x * ls_cell_location.x +
+ increment_y * ls_cell_location.y +
+ increment_z * ls_cell_location.z);
+
+ gl_Position = ViewProjectionMatrix * vec4(pos * 0.02 * sphere_size + ws_cell_location, 1.0);
+
+ finalId = uint(baseId + call_id);
+}
diff --git a/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl
new file mode 100644
index 00000000000..baa3ecb804c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_mball_handles_vert.glsl
@@ -0,0 +1,34 @@
+
+/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view,
+ * and scales the shape according to per-instance attributes
+ * Note that if the stiffness is zero, it assumes the scale is directly multiplied by the radius */
+
+
+uniform mat4 ViewProjectionMatrix;
+uniform vec3 screen_vecs[2];
+
+/* ---- Instanciated Attribs ---- */
+in vec2 pos;
+
+/* ---- Per instance Attribs ---- */
+in mat3x4 ScaleTranslationMatrix;
+in float radius;
+in vec3 color;
+
+flat out vec4 finalColor;
+
+void main()
+{
+ mat3 Scamat = mat3(ScaleTranslationMatrix);
+ vec4 world_pos = vec4(
+ ScaleTranslationMatrix[0][3],
+ ScaleTranslationMatrix[1][3],
+ ScaleTranslationMatrix[2][3],
+ 1.0);
+
+ vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y;
+ world_pos.xyz += Scamat * (screen_pos * radius);
+
+ gl_Position = ViewProjectionMatrix * world_pos;
+ finalColor = vec4(color, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
new file mode 100644
index 00000000000..9a7856ecb13
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_detect_frag.glsl
@@ -0,0 +1,88 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform usampler2D outlineId;
+uniform sampler2D outlineDepth;
+uniform sampler2D sceneDepth;
+
+uniform int idOffsets[3];
+
+uniform float alphaOcclu;
+uniform vec2 viewportSize;
+
+vec4 convert_id_to_color(int id)
+{
+ if (id == 0) {
+ return vec4(0.0);
+ }
+ if (id < idOffsets[1]) {
+ return colorActive;
+ }
+ else if (id < idOffsets[2]) {
+ return colorSelect;
+ }
+ else {
+ return colorTransform;
+ }
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy);
+
+#ifdef GL_ARB_texture_gather
+ vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy);
+ vec2 uv = ceil(gl_FragCoord.xy) * texel_size;
+
+ /* Samples order is CW starting from top left. */
+ uvec4 tmp1 = textureGather(outlineId, uv - texel_size);
+ uvec4 tmp2 = textureGather(outlineId, uv);
+
+ uint ref_id = tmp1.y;
+ uvec4 id = uvec4(tmp1.xz, tmp2.xz);
+#else
+ uvec4 id;
+ uint ref_id = texelFetch(outlineId, texel, 0).r;
+ id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r;
+ id.y = texelFetchOffset(outlineId, texel, 0, ivec2( 0, -1)).r;
+ id.z = texelFetchOffset(outlineId, texel, 0, ivec2( 0, 1)).r;
+ id.w = texelFetchOffset(outlineId, texel, 0, ivec2( 1, 0)).r;
+#endif
+
+#ifdef WIRE
+ /* We want only 2px outlines. */
+ /* TODO optimize, don't sample if we don't need to. */
+ id.xy = uvec2(ref_id);
+#endif
+
+ bool outline = any(notEqual(id, uvec4(ref_id)));
+
+ ivec2 depth_texel = texel;
+ /* If texel is an outline but has no valid id ...
+ * replace id and depth texel by a valid one.
+ * This keeps the outline thickness consistent everywhere. */
+ if (ref_id == 0u && outline) {
+ depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel;
+ depth_texel = (id.y != 0u) ? texel + ivec2( 0, -1) : depth_texel;
+ depth_texel = (id.z != 0u) ? texel + ivec2( 0, 1) : depth_texel;
+ depth_texel = (id.w != 0u) ? texel + ivec2( 1, 0) : depth_texel;
+
+ ref_id = (id.x != 0u) ? id.x : ref_id;
+ ref_id = (id.y != 0u) ? id.y : ref_id;
+ ref_id = (id.z != 0u) ? id.z : ref_id;
+ ref_id = (id.w != 0u) ? id.w : ref_id;
+ }
+
+ float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r;
+ float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r;
+
+ /* Avoid bad cases of zfighting for occlusion only. */
+ const float epsilon = 3.0 / 8388608.0;
+ bool occluded = (ref_depth > scene_depth + epsilon);
+
+ FragColor = convert_id_to_color(int(ref_id));
+ FragColor.a *= (occluded) ? alphaOcclu : 1.0;
+ FragColor.a = (outline) ? FragColor.a : 0.0;
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl
new file mode 100644
index 00000000000..7e288cde236
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_expand_frag.glsl
@@ -0,0 +1,37 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineColor;
+
+uniform float alpha;
+uniform bool doExpand;
+
+void main()
+{
+ ivec2 uv = ivec2(gl_FragCoord.xy);
+ FragColor = texelFetch(outlineColor, uv, 0).rgba;
+
+ vec4 color[4];
+ color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2( 1, 0)).rgba;
+ color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2( 0, 1)).rgba;
+ color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba;
+ color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2( 0, -1)).rgba;
+
+ vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a);
+
+ vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */
+ bvec4 btests = equal(tests, vec4(1.0));
+
+ if (FragColor.a != 0.0) {
+ return;
+ }
+
+ FragColor = (btests.x) ? color[0] : FragColor;
+ FragColor = (btests.y) ? color[1] : FragColor;
+ FragColor = (btests.z) ? color[2] : FragColor;
+ FragColor = (btests.w) ? color[3] : FragColor;
+
+ FragColor.a *= (!doExpand) ? 0.0 : 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
new file mode 100644
index 00000000000..776adb787ad
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_frag.glsl
@@ -0,0 +1,10 @@
+uniform int callId;
+uniform int baseId;
+
+/* using uint because 16bit uint can contain more ids than int. */
+out uint outId;
+
+void main()
+{
+ outId = uint(baseId + callId);
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
new file mode 100644
index 00000000000..c90195e11fd
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_geom.glsl
@@ -0,0 +1,40 @@
+
+layout(lines_adjacency) in;
+layout(line_strip, max_vertices = 2) out;
+
+uniform mat4 ProjectionMatrix;
+
+in vec4 pPos[];
+in vec3 vPos[];
+
+void main()
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+
+ vec3 view_vec = (is_persp) ? normalize(vPos[1]) : vec3(0.0, 0.0, -1.0);
+
+ vec3 v10 = vPos[0] - vPos[1];
+ vec3 v12 = vPos[2] - vPos[1];
+ vec3 v13 = vPos[3] - vPos[1];
+
+ vec3 n0 = cross(v12, v10);
+ vec3 n3 = cross(v13, v12);
+
+ float fac0 = dot(view_vec, n0);
+ float fac3 = dot(view_vec, n3);
+
+ /* If both adjacent verts are facing the camera the same way,
+ * then it isn't an outline edge. */
+ if (sign(fac0) == sign(fac3))
+ return;
+
+ /* Don't outline if concave edge. */
+ /* That would hide a lot of non usefull edge but it flickers badly.
+ * TODO revisit later... */
+ // if (dot(n0, v13) > 0.01)
+ // return;
+
+ gl_Position = pPos[1]; EmitVertex();
+ gl_Position = pPos[2]; EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
new file mode 100644
index 00000000000..ba824a7c007
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_prepass_vert.glsl
@@ -0,0 +1,16 @@
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+
+out vec4 pPos;
+out vec3 vPos;
+
+void main()
+{
+ vPos = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
+ pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ /* Small bias to always be on top of the geom. */
+ pPos.z -= 1e-3;
+}
diff --git a/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl
new file mode 100644
index 00000000000..964ebe72e81
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_outline_resolve_frag.glsl
@@ -0,0 +1,27 @@
+
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D outlineBluredColor;
+uniform vec2 rcpDimensions;
+
+void main()
+{
+#ifdef USE_FXAA
+ float aa_alpha = FxaaPixelShader(
+ uvcoordsvar.st,
+ outlineBluredColor,
+ rcpDimensions,
+ 1.0,
+ 0.166,
+ 0.0833
+ ).r;
+#endif
+
+ FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba;
+
+#ifdef USE_FXAA
+ FragColor.a = aa_alpha;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl b/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl
new file mode 100644
index 00000000000..e8bf7884701
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_dot_frag.glsl
@@ -0,0 +1,52 @@
+
+uniform vec3 color;
+uniform vec3 outlineColor;
+uniform sampler1D ramp;
+
+in vec4 radii;
+flat in float finalVal;
+
+out vec4 fragColor;
+
+void main() {
+ float dist = length(gl_PointCoord - vec2(0.5));
+
+// transparent outside of point
+// --- 0 ---
+// smooth transition
+// --- 1 ---
+// pure outline color
+// --- 2 ---
+// smooth transition
+// --- 3 ---
+// pure point color
+// ...
+// dist = 0 at center of point
+
+ float midStroke = 0.5 * (radii[1] + radii[2]);
+
+ if (dist > midStroke) {
+ if (finalVal < 0.0) {
+ fragColor.rgb = outlineColor;
+ }
+ else {
+ fragColor.rgb = texture(ramp, finalVal).rgb;
+ }
+
+ fragColor.a = mix(1.0, 0.0, smoothstep(radii[1], radii[0], dist));
+ }
+ else {
+ if (finalVal < 0.0) {
+ fragColor.rgb = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist));
+ }
+ else {
+ fragColor.rgb = texture(ramp, finalVal).rgb;
+ }
+
+ fragColor.a = 1.0;
+ }
+
+ if (fragColor.a == 0.0) {
+ discard;
+ }
+}
diff --git a/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl
new file mode 100644
index 00000000000..6dfc212a776
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_dot_vert.glsl
@@ -0,0 +1,35 @@
+
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform float pixel_size;
+uniform float size;
+
+in vec3 pos;
+in float val;
+
+out vec4 radii;
+flat out float finalVal;
+
+void main() {
+ gl_Position = ModelViewMatrix * vec4(pos, 1.0);
+
+ float psize = (ProjectionMatrix[3][3] == 0.0) ? (size / (-gl_Position.z * pixel_size)) : (size / pixel_size);
+
+ gl_PointSize = psize;
+
+ // calculate concentric radii in pixels
+ float radius = 0.5 * psize;
+
+ // start at the outside and progress toward the center
+ radii[0] = radius;
+ radii[1] = radius - 1.0;
+ radii[2] = radius - 1.0;
+ radii[3] = radius - 2.0;
+
+ // convert to PointCoord units
+ radii /= psize;
+
+ gl_Position = ProjectionMatrix * gl_Position;
+
+ finalVal = val;
+}
diff --git a/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl
new file mode 100644
index 00000000000..54ae319307a
--- /dev/null
+++ b/source/blender/draw/modes/shaders/object_particle_prim_vert.glsl
@@ -0,0 +1,56 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ViewProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform int screen_space;
+uniform float draw_size;
+uniform vec3 color;
+uniform sampler1D ramp;
+
+in vec3 pos;
+in vec4 rot;
+in float val;
+in vec3 inst_pos;
+in int axis;
+
+flat out vec4 finalColor;
+
+vec3 rotate(vec3 vec, vec4 quat)
+{
+ /* The quaternion representation here stores the w component in the first index */
+ return vec + 2.0 * cross(quat.yzw, cross(quat.yzw, vec) + quat.x * vec);
+}
+
+void main()
+{
+ if (screen_space == 1) {
+ gl_Position = ModelViewMatrix * vec4(pos, 1.0) + vec4(inst_pos * draw_size, 0.0);
+ gl_Position = ProjectionMatrix * gl_Position;
+ }
+ else {
+ float size = draw_size;
+
+ if (axis > -1) {
+ size *= 2;
+ }
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos + rotate(inst_pos * size, rot), 1.0);
+ }
+
+#ifdef USE_AXIS
+ if (axis == 0)
+ finalColor = vec4(1.0, 0.0, 0.0, 1.0);
+ else if (axis == 1)
+ finalColor = vec4(0.0, 1.0, 0.0, 1.0);
+ else
+ finalColor = vec4(0.0, 0.0, 1.0, 1.0);
+#else
+ if (val < 0.0) {
+ finalColor = vec4(color, 1.0);
+ }
+ else {
+ finalColor = vec4(texture(ramp, val).rgb, 1.0);
+ }
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl
new file mode 100644
index 00000000000..5b0ad7863d1
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_orientation_frag.glsl
@@ -0,0 +1,10 @@
+uniform vec3 color_towards = vec3(0.0, 0.0, 1.0);
+uniform vec3 color_outwards = vec3(1.0, 0.0, 0.0);
+
+out vec4 fragColor;
+
+
+void main()
+{
+ fragColor = vec4(gl_FrontFacing ? color_towards: color_outwards, 0.7);
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl
new file mode 100644
index 00000000000..d8a72f28eee
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_orientation_vert.glsl
@@ -0,0 +1,7 @@
+uniform mat4 ModelViewProjectionMatrix;
+in vec3 pos;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
new file mode 100644
index 00000000000..5dfbb4352e4
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_frag.glsl
@@ -0,0 +1,53 @@
+uniform vec3 wireColor;
+uniform vec3 rimColor;
+
+flat in vec3 ssVec0;
+flat in vec3 ssVec1;
+flat in vec3 ssVec2;
+in float facing;
+
+#ifdef LIGHT_EDGES
+flat in vec3 edgeSharpness;
+#endif
+
+out vec4 fragColor;
+
+float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
+float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
+
+/* In pixels */
+const float wire_size = 0.0; /* Expands the core of the wire (part that is 100% wire color) */
+const float wire_smooth = 1.2; /* Smoothing distance after the 100% core. */
+
+/* Alpha constants could be exposed in the future. */
+const float front_alpha = 0.35;
+const float rim_alpha = 0.75;
+
+void main()
+{
+ vec3 ss_pos = vec3(gl_FragCoord.xy, 1.0);
+ vec3 dist_to_edge = vec3(
+ dot(ss_pos, ssVec0),
+ dot(ss_pos, ssVec1),
+ dot(ss_pos, ssVec2)
+ );
+
+#ifdef LIGHT_EDGES
+ vec3 fac = abs(dist_to_edge);
+#else
+ float fac = min_v3(abs(dist_to_edge));
+#endif
+
+ fac = smoothstep(wire_size + wire_smooth, wire_size, fac);
+
+ float facing_clamped = clamp((gl_FrontFacing) ? facing : -facing, 0.0, 1.0);
+
+ vec3 final_front_col = mix(rimColor, wireColor, 0.05);
+ fragColor = mix(vec4(rimColor, rim_alpha), vec4(final_front_col, front_alpha), facing_clamped);
+
+#ifdef LIGHT_EDGES
+ fragColor.a *= max_v3(fac * edgeSharpness);
+#else
+ fragColor.a *= fac;
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
new file mode 100644
index 00000000000..eb69af92435
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_geom.glsl
@@ -0,0 +1,86 @@
+
+/* This shader is only used for intel GPU where the Geom shader is faster
+ * than doing everything thrice in the vertex shader. */
+
+layout(triangles) in;
+layout(triangle_strip, max_vertices = 3) out;
+
+uniform vec2 wireStepParam;
+
+in vec2 ssPos[];
+in float facingOut[];
+
+flat out vec3 ssVec0;
+flat out vec3 ssVec1;
+flat out vec3 ssVec2;
+out float facing;
+
+#ifdef LIGHT_EDGES
+in vec3 obPos[];
+in vec3 vNor[];
+in float forceEdge[];
+
+flat out vec3 edgeSharpness;
+#endif
+
+#define NO_EDGE vec3(10000.0);
+
+/* TODO(fclem) remove code duplication. */
+vec3 compute_vec(vec2 v0, vec2 v1)
+{
+ vec2 v = normalize(v1 - v0);
+ v = vec2(-v.y, v.x);
+ return vec3(v, -dot(v, v0));
+}
+
+vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge)
+{
+ edge = normalize(edge);
+ vec3 n = n1 + n2;
+ float p = dot(edge, n);
+ return normalize(n - p * edge);
+}
+
+float get_edge_sharpness(vec3 fnor, vec3 vnor)
+{
+ float sharpness = abs(dot(fnor, vnor));
+ return smoothstep(wireStepParam.x, wireStepParam.y, sharpness);
+}
+
+void main(void)
+{
+ vec3 facings = vec3(facingOut[0], facingOut[1], facingOut[2]);
+ bvec3 do_edge = greaterThan(abs(facings), vec3(1.0));
+ facings = fract(facings) - clamp(-sign(facings), 0.0, 1.0);
+
+ ssVec0 = do_edge.x ? compute_vec(ssPos[0], ssPos[1]) : NO_EDGE;
+ ssVec1 = do_edge.y ? compute_vec(ssPos[1], ssPos[2]) : NO_EDGE;
+ ssVec2 = do_edge.z ? compute_vec(ssPos[2], ssPos[0]) : NO_EDGE;
+
+#ifdef LIGHT_EDGES
+ vec3 edges[3];
+ edges[0] = obPos[1] - obPos[0];
+ edges[1] = obPos[2] - obPos[1];
+ edges[2] = obPos[0] - obPos[2];
+ vec3 fnor = normalize(cross(edges[0], -edges[2]));
+
+ edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(vNor[0], vNor[1], edges[0]));
+ edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(vNor[1], vNor[2], edges[1]));
+ edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(vNor[2], vNor[0], edges[2]));
+ edgeSharpness.x = (forceEdge[0] == 1.0) ? 1.0 : edgeSharpness.x;
+ edgeSharpness.y = (forceEdge[1] == 1.0) ? 1.0 : edgeSharpness.y;
+ edgeSharpness.z = (forceEdge[2] == 1.0) ? 1.0 : edgeSharpness.z;
+#endif
+ gl_Position = gl_in[0].gl_Position;
+ facing = facings.x;
+ EmitVertex();
+
+ gl_Position = gl_in[1].gl_Position;
+ facing = facings.y;
+ EmitVertex();
+
+ gl_Position = gl_in[2].gl_Position;
+ facing = facings.z;
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
new file mode 100644
index 00000000000..fe3c2021b7e
--- /dev/null
+++ b/source/blender/draw/modes/shaders/overlay_face_wireframe_vert.glsl
@@ -0,0 +1,189 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelViewMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat3 NormalMatrix;
+
+uniform vec2 wireStepParam;
+uniform vec2 viewportSize;
+uniform float nearDist;
+
+uniform samplerBuffer vertData;
+uniform usamplerBuffer faceIds;
+
+#ifdef USE_GEOM_SHADER
+out vec2 ssPos;
+out float facingOut; /* abs(facing) > 1.0 if we do edge */
+#else
+flat out vec3 ssVec0;
+flat out vec3 ssVec1;
+flat out vec3 ssVec2;
+out float facing;
+#endif
+
+#ifdef LIGHT_EDGES
+#ifdef USE_GEOM_SHADER
+out vec3 obPos;
+out vec3 vNor;
+out float forceEdge;
+#else
+flat out vec3 edgeSharpness;
+#endif
+#endif
+
+/* project to screen space */
+vec2 proj(vec4 pos)
+{
+ return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
+}
+
+vec3 compute_vec(vec2 v0, vec2 v1)
+{
+ vec2 v = normalize(v1 - v0);
+ v = vec2(-v.y, v.x);
+ return vec3(v, -dot(v, v0));
+}
+
+float short_to_unit_float(uint s)
+{
+ int value = int(s) & 0x7FFF;
+ if ((s & 0x8000u) != 0u) {
+ value |= ~0x7FFF;
+ }
+ return float(value) / float(0x7FFF);
+}
+
+vec3 get_vertex_nor(uint id)
+{
+ int v_id = int(id) * 5; /* See vertex format for explanation. */
+ /* Fetch compressed normal as float and unpack them. */
+ vec2 data;
+ data.x = texelFetch(vertData, v_id + 3).r;
+ data.y = texelFetch(vertData, v_id + 4).r;
+
+ uvec2 udata = floatBitsToUint(data);
+
+ vec3 nor;
+ nor.x = short_to_unit_float(udata.x & 0xFFFFu);
+ nor.y = short_to_unit_float(udata.x >> 16u);
+ nor.z = short_to_unit_float(udata.y & 0xFFFFu);
+ return nor;
+}
+
+vec3 get_vertex_pos(uint id)
+{
+ int v_id = int(id) * 5; /* See vertex format for explanation. */
+ vec3 pos;
+ pos.x = texelFetch(vertData, v_id).r;
+ pos.y = texelFetch(vertData, v_id + 1).r;
+ pos.z = texelFetch(vertData, v_id + 2).r;
+ return pos;
+}
+
+vec3 get_edge_normal(vec3 n1, vec3 n2, vec3 edge)
+{
+ edge = normalize(edge);
+ vec3 n = n1 + n2;
+ float p = dot(edge, n);
+ return normalize(n - p * edge);
+}
+
+float get_edge_sharpness(vec3 fnor, vec3 vnor)
+{
+ float sharpness = abs(dot(fnor, vnor));
+ return smoothstep(wireStepParam.x, wireStepParam.y, sharpness);
+}
+
+#define NO_EDGE vec3(10000.0);
+
+void main()
+{
+#ifdef USE_GEOM_SHADER
+ uint v_id = texelFetch(faceIds, gl_VertexID).r;
+
+ bool do_edge = (v_id & (1u << 30u)) != 0u;
+ bool force_edge = (v_id & (1u << 31u)) != 0u;
+ v_id = (v_id << 2u) >> 2u;
+
+ vec3 pos = get_vertex_pos(v_id);
+ vec3 nor = get_vertex_nor(v_id);
+ facingOut = normalize(NormalMatrix * nor).z;
+ facingOut += (do_edge) ? ((facingOut > 0.0) ? 2.0 : -2.0) : 0.0;
+
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ ssPos = proj(gl_Position);
+
+# ifdef LIGHT_EDGES
+ obPos = pos;
+ vNor = nor;
+ forceEdge = float(force_edge); /* meh, could try to also encode it in facingOut */
+# endif
+
+#else
+ int v_0 = (gl_VertexID / 3) * 3;
+ int v_n = gl_VertexID % 3;
+
+ /* Getting the same positions for each of the 3 verts. */
+ uvec3 v_id;
+ v_id.x = texelFetch(faceIds, v_0).r;
+ v_id.y = texelFetch(faceIds, v_0 + 1).r;
+ v_id.z = texelFetch(faceIds, v_0 + 2).r;
+
+ bvec3 do_edge, force_edge;
+ do_edge.x = (v_id.x & (1u << 30u)) != 0u;
+ do_edge.y = (v_id.y & (1u << 30u)) != 0u;
+ do_edge.z = (v_id.z & (1u << 30u)) != 0u;
+ force_edge.x = (v_id.x & (1u << 31u)) != 0u;
+ force_edge.y = (v_id.y & (1u << 31u)) != 0u;
+ force_edge.z = (v_id.z & (1u << 31u)) != 0u;
+ v_id = (v_id << 2u) >> 2u;
+
+ vec3 pos[3];
+ pos[0] = get_vertex_pos(v_id.x);
+ pos[1] = get_vertex_pos(v_id.y);
+ pos[2] = get_vertex_pos(v_id.z);
+
+ vec4 p_pos[3];
+ p_pos[0] = ModelViewProjectionMatrix * vec4(pos[0], 1.0);
+ p_pos[1] = ModelViewProjectionMatrix * vec4(pos[1], 1.0);
+ p_pos[2] = ModelViewProjectionMatrix * vec4(pos[2], 1.0);
+
+ vec2 ss_pos[3];
+ ss_pos[0] = proj(p_pos[0]);
+ ss_pos[1] = proj(p_pos[1]);
+ ss_pos[2] = proj(p_pos[2]);
+
+ /* Compute the edges screen vectors */
+ ssVec0 = do_edge.x ? compute_vec(ss_pos[0], ss_pos[1]) : NO_EDGE;
+ ssVec1 = do_edge.y ? compute_vec(ss_pos[1], ss_pos[2]) : NO_EDGE;
+ ssVec2 = do_edge.z ? compute_vec(ss_pos[2], ss_pos[0]) : NO_EDGE;
+
+ gl_Position = p_pos[v_n];
+
+# ifndef LIGHT_EDGES
+ vec3 nor = get_vertex_nor(v_id[v_n]);
+# else
+ vec3 edges[3];
+ edges[0] = pos[1] - pos[0];
+ edges[1] = pos[2] - pos[1];
+ edges[2] = pos[0] - pos[2];
+ vec3 fnor = normalize(cross(edges[0], -edges[2]));
+
+ vec3 nors[3];
+ nors[0] = get_vertex_nor(v_id.x);
+ nors[1] = get_vertex_nor(v_id.y);
+ nors[2] = get_vertex_nor(v_id.z);
+ edgeSharpness.x = get_edge_sharpness(fnor, get_edge_normal(nors[0], nors[1], edges[0]));
+ edgeSharpness.y = get_edge_sharpness(fnor, get_edge_normal(nors[1], nors[2], edges[1]));
+ edgeSharpness.z = get_edge_sharpness(fnor, get_edge_normal(nors[2], nors[0], edges[2]));
+ edgeSharpness.x = force_edge.x ? 1.0 : edgeSharpness.x;
+ edgeSharpness.y = force_edge.y ? 1.0 : edgeSharpness.y;
+ edgeSharpness.z = force_edge.z ? 1.0 : edgeSharpness.z;
+
+ vec3 nor = nors[v_n];
+# endif
+
+ facing = normalize(NormalMatrix * nor).z;
+
+#endif
+}
diff --git a/source/blender/draw/modes/shaders/paint_texture_frag.glsl b/source/blender/draw/modes/shaders/paint_texture_frag.glsl
new file mode 100644
index 00000000000..4305e20ce7b
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_texture_frag.glsl
@@ -0,0 +1,11 @@
+
+in vec2 uv_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+uniform float alpha = 1.0;
+
+void main()
+{
+ fragColor = vec4(texture(image, uv_interp).rgb, alpha);
+}
diff --git a/source/blender/draw/modes/shaders/paint_texture_vert.glsl b/source/blender/draw/modes/shaders/paint_texture_vert.glsl
new file mode 100644
index 00000000000..4ce12e048fa
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_texture_vert.glsl
@@ -0,0 +1,15 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec2 uv;
+in vec3 pos;
+
+out vec2 uv_interp;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ uv_interp = uv;
+
+}
diff --git a/source/blender/draw/modes/shaders/paint_vert_frag.glsl b/source/blender/draw/modes/shaders/paint_vert_frag.glsl
new file mode 100644
index 00000000000..c22e1c04b96
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_vert_frag.glsl
@@ -0,0 +1,26 @@
+
+flat in int finalFlag;
+out vec4 fragColor;
+
+#define VERTEX_SELECTED (1 << 0)
+#define VERTEX_HIDE (1 << 4)
+
+void main()
+{
+ if (bool(finalFlag & VERTEX_HIDE)) {
+ discard;
+ }
+
+ vec2 centered = gl_PointCoord - vec2(0.5);
+ float dist_squared = dot(centered, centered);
+ const float rad_squared = 0.25;
+ const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0);
+ const vec4 colUnsel = vec4(0.5, 0.5, 0.5, 1.0);
+
+ // round point with jaggy edges
+ if (dist_squared > rad_squared) {
+ discard;
+ }
+
+ fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colUnsel;
+}
diff --git a/source/blender/draw/modes/shaders/paint_vertex_frag.glsl b/source/blender/draw/modes/shaders/paint_vertex_frag.glsl
new file mode 100644
index 00000000000..2c968dafa69
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_vertex_frag.glsl
@@ -0,0 +1,17 @@
+
+in vec3 finalColor;
+
+out vec4 fragColor;
+uniform float alpha = 1.0;
+vec3 linear_to_srgb_attrib(vec3 c) {
+ c = max(c, vec3(0.0));
+ vec3 c1 = c * 12.92;
+ vec3 c2 = 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055;
+ return mix(c1, c2, step(vec3(0.0031308), c));
+}
+
+void main()
+{
+ fragColor.rgb = linear_to_srgb_attrib(finalColor);
+ fragColor.a = alpha;
+}
diff --git a/source/blender/draw/modes/shaders/paint_vertex_vert.glsl b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl
new file mode 100644
index 00000000000..178f77c6b9c
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_vertex_vert.glsl
@@ -0,0 +1,21 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in vec3 color;
+
+out vec3 finalColor;
+
+vec3 srgb_to_linear_attrib(vec3 c) {
+ c = max(c, vec3(0.0));
+ vec3 c1 = c * (1.0 / 12.92);
+ vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
+ return mix(c1, c2, step(vec3(0.04045), c));
+}
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ finalColor = srgb_to_linear_attrib(color);
+}
diff --git a/source/blender/draw/modes/shaders/paint_wire_frag.glsl b/source/blender/draw/modes/shaders/paint_wire_frag.glsl
new file mode 100644
index 00000000000..b6637fea308
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_wire_frag.glsl
@@ -0,0 +1,22 @@
+
+flat in int finalFlag;
+out vec4 fragColor;
+
+#define VERTEX_SELECTED (1 << 0)
+#define VERTEX_HIDE (1 << 4)
+
+void main()
+{
+ if (bool(finalFlag & VERTEX_HIDE)) {
+ discard;
+ }
+
+#ifdef VERTEX_MODE
+ vec4 colSel = colorEdgeSelect;
+ colSel.rgb = clamp(colSel.rgb - 0.2, 0.0, 1.0);
+#else
+ const vec4 colSel = vec4(1.0, 1.0, 1.0, 1.0);
+#endif
+
+ fragColor = bool(finalFlag & VERTEX_SELECTED) ? colSel : colorWire;
+}
diff --git a/source/blender/draw/modes/shaders/paint_wire_vert.glsl b/source/blender/draw/modes/shaders/paint_wire_vert.glsl
new file mode 100644
index 00000000000..6a800e56d94
--- /dev/null
+++ b/source/blender/draw/modes/shaders/paint_wire_vert.glsl
@@ -0,0 +1,17 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+
+in vec3 pos;
+in int data;
+
+flat out int finalFlag;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+
+ /* Temp hack for william to start using blender 2.8 for icons. Will be removed by T54910 */
+ gl_Position.z -= 0.0001;
+
+ finalFlag = data;
+}
diff --git a/source/blender/draw/modes/shaders/particle_strand_frag.glsl b/source/blender/draw/modes/shaders/particle_strand_frag.glsl
new file mode 100644
index 00000000000..7053ca43ae7
--- /dev/null
+++ b/source/blender/draw/modes/shaders/particle_strand_frag.glsl
@@ -0,0 +1,12 @@
+uniform mat4 ProjectionMatrix;
+
+in vec3 tangent;
+in vec3 viewPosition;
+flat in float colRand;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor.rgb = tangent;
+ fragColor.a = 1.0;
+}
diff --git a/source/blender/draw/modes/shaders/particle_strand_vert.glsl b/source/blender/draw/modes/shaders/particle_strand_vert.glsl
new file mode 100644
index 00000000000..d4c35d14182
--- /dev/null
+++ b/source/blender/draw/modes/shaders/particle_strand_vert.glsl
@@ -0,0 +1,34 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat3 NormalMatrix;
+uniform mat4 ModelViewMatrix;
+
+in vec3 pos;
+in vec3 nor;
+in int ind;
+out vec3 tangent;
+out vec3 viewPosition;
+flat out float colRand;
+
+float rand(int s)
+{
+ int seed = s * 1023423;
+
+ seed = (seed ^ 61) ^ (seed >> 16);
+ seed *= 9;
+ seed = seed ^ (seed >> 4);
+ seed *= 0x27d4eb2d;
+ seed = seed ^ (seed >> 15);
+
+ float value = float(seed);
+ value *= 1.0 / 42596.0;
+ return fract(value);
+}
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+ tangent = normalize(NormalMatrix * nor);
+ viewPosition = (ModelViewMatrix * vec4(pos, 1.0)).xyz;
+ colRand = rand(ind);
+}