diff options
Diffstat (limited to 'source/blender/draw/modes')
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); +} |