diff options
author | Antonio Vazquez <blendergit@gmail.com> | 2020-03-09 18:27:24 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2020-03-09 18:27:24 +0300 |
commit | 29f3af95272590d26f610ae828b2eeee89c82a00 (patch) | |
tree | a696a58a2561c48f7ec6166e369e22081e0a64d8 /source/blender/draw/engines/overlay | |
parent | dcb93126876879d969a30a7865700abd072066f8 (diff) |
GPencil: Refactor of Draw Engine, Vertex Paint and all internal functions
This commit is a full refactor of the grease pencil modules including Draw Engine, Modifiers, VFX, depsgraph update, improvements in operators and conversion of Sculpt and Weight paint tools to real brushes.
Also, a huge code cleanup has been done at all levels.
Thanks to @fclem for his work and yo @pepeland and @mendio for the testing and help in the development.
Differential Revision: https://developer.blender.org/D6293
Diffstat (limited to 'source/blender/draw/engines/overlay')
14 files changed, 902 insertions, 98 deletions
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index a8d2c4c6cf0..cfa0fa9eb1a 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -25,6 +25,8 @@ #include "DRW_engine.h" #include "DRW_render.h" +#include "DEG_depsgraph_query.h" + #include "ED_view3d.h" #include "BKE_object.h" @@ -79,6 +81,7 @@ static void OVERLAY_engine_init(void *vedata) pd->xray_enabled = XRAY_ACTIVE(v3d); pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE; pd->clear_in_front = (v3d->shading.type != OB_SOLID); + pd->cfra = DEG_get_ctime(draw_ctx->depsgraph); OVERLAY_antialiasing_init(vedata); @@ -133,11 +136,14 @@ static void OVERLAY_cache_init(void *vedata) case CTX_MODE_SCULPT: OVERLAY_sculpt_cache_init(vedata); break; - case CTX_MODE_OBJECT: - case CTX_MODE_PAINT_GPENCIL: case CTX_MODE_EDIT_GPENCIL: + case CTX_MODE_PAINT_GPENCIL: case CTX_MODE_SCULPT_GPENCIL: + case CTX_MODE_VERTEX_GPENCIL: case CTX_MODE_WEIGHT_GPENCIL: + OVERLAY_edit_gpencil_cache_init(vedata); + break; + case CTX_MODE_OBJECT: break; default: BLI_assert(!"Draw mode invalid"); @@ -148,6 +154,7 @@ static void OVERLAY_cache_init(void *vedata) OVERLAY_background_cache_init(vedata); OVERLAY_extra_cache_init(vedata); OVERLAY_facing_cache_init(vedata); + OVERLAY_gpencil_cache_init(vedata); OVERLAY_grid_cache_init(vedata); OVERLAY_image_cache_init(vedata); OVERLAY_metaball_cache_init(vedata); @@ -216,8 +223,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) const bool in_paint_mode = (ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT); const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL); - const bool has_surface = ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT); - const bool draw_surface = !((ob->dt < OB_WIRE) || (!renderable && (ob->dt != OB_WIRE))); + const bool has_surface = ELEM( + ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT, OB_GPENCIL); + const bool draw_surface = (ob->dt >= OB_WIRE) && (renderable || (ob->dt == OB_WIRE)); const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION); const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0; const bool draw_wires = draw_surface && has_surface && @@ -429,6 +437,7 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_armature_draw(vedata); OVERLAY_particle_draw(vedata); OVERLAY_metaball_draw(vedata); + OVERLAY_gpencil_draw(vedata); OVERLAY_extra_draw(vedata); if (DRW_state_is_fbo()) { @@ -491,6 +500,13 @@ static void OVERLAY_draw_scene(void *vedata) case CTX_MODE_SCULPT: OVERLAY_sculpt_draw(vedata); break; + case CTX_MODE_EDIT_GPENCIL: + case CTX_MODE_PAINT_GPENCIL: + case CTX_MODE_SCULPT_GPENCIL: + case CTX_MODE_VERTEX_GPENCIL: + case CTX_MODE_WEIGHT_GPENCIL: + OVERLAY_edit_gpencil_draw(vedata); + break; default: break; } diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index b40e95d538c..49f266291da 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -38,7 +38,7 @@ #include "DNA_camera_types.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_curve_types.h" #include "DNA_lightprobe_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" @@ -1331,89 +1331,6 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, /** \} */ /* -------------------------------------------------------------------- */ -/** \name GPencil. - * \{ */ - -static void OVERLAY_gpencil_color_names(Object *ob) -{ - if (ob->mode != OB_MODE_EDIT_GPENCIL) { - return; - } - - bGPdata *gpd = (bGPdata *)ob->data; - if (gpd == NULL) { - return; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - ViewLayer *view_layer = draw_ctx->view_layer; - int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); - uchar color[4]; - /* Color Management: Exception here as texts are drawn in sRGB space directly. */ - UI_GetThemeColor3ubv(theme_id, color); - color[3] = 255; - struct DRWTextStore *dt = DRW_text_cache_ensure(); - - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->flag & GP_LAYER_HIDE) { - continue; - } - bGPDframe *gpf = gpl->actframe; - if (gpf == NULL) { - continue; - } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1); - if (ma == NULL) { - continue; - } - - MaterialGPencilStyle *gp_style = ma->gp_style; - /* skip stroke if it doesn't have any valid data */ - if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) { - continue; - } - /* check if the color is visible */ - if (gp_style->flag & GP_STYLE_COLOR_HIDE) { - continue; - } - - /* only if selected */ - if (gps->flag & GP_STROKE_SELECT) { - float fpt[3]; - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - if (pt->flag & GP_SPOINT_SELECT) { - mul_v3_m4v3(fpt, ob->obmat, &pt->x); - DRW_text_cache_add(dt, - fpt, - ma->id.name + 2, - strlen(ma->id.name + 2), - 10, - 0, - DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, - color); - break; - } - } - } - } - } -} - -void OVERLAY_gpencil_cache_populate(OVERLAY_Data *UNUSED(vedata), Object *ob) -{ - /* don't show object extras in set's */ - if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { - if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) { - OVERLAY_gpencil_color_names(ob); - } - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Volumetric / Smoke sim * \{ */ diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c new file mode 100644 index 00000000000..c96c448c63b --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_gpencil.c @@ -0,0 +1,391 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BKE_gpencil.h" + +#include "UI_resources.h" + +#include "DNA_gpencil_types.h" + +#include "DEG_depsgraph_query.h" + +#include "ED_view3d.h" + +#include "overlay_private.h" + +#include "draw_common.h" +#include "draw_manager_text.h" + +void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + /* Default: Display nothing. */ + pd->edit_gpencil_points_grp = NULL; + pd->edit_gpencil_wires_grp = NULL; + psl->edit_gpencil_ps = NULL; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + + if (gpd == NULL || ob->type != OB_GPENCIL) { + return; + } + + /* For sculpt show only if mask mode, and only points if not stroke mode. */ + const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) && + GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt)); + const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) && + (ts->gpencil_selectmode_sculpt & + (GP_SCULPT_MASK_SELECTMODE_POINT | + GP_SCULPT_MASK_SELECTMODE_SEGMENT))); + + /* For vertex paint show only if mask mode, and only points if not stroke mode. */ + bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) && + GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); + const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) && + (ts->gpencil_selectmode_vertex & + (GP_VERTEX_MASK_SELECTMODE_POINT | + GP_VERTEX_MASK_SELECTMODE_SEGMENT))); + + /* If Sculpt or Vertex mode and the mask is disabled, the select must be hidden. */ + const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) || + (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask)); + + const bool do_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool show_multi_edit_lines = (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0; + + const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) || show_multi_edit_lines; + + const bool hide_lines = !GPENCIL_EDIT_MODE(gpd) && !GPENCIL_WEIGHT_MODE(gpd) && + !use_sculpt_mask && !use_vertex_mask && !show_lines; + + /* Special case when vertex paint and multiedit lines. */ + if (do_multiedit && show_multi_edit_lines && GPENCIL_VERTEX_MODE(gpd)) { + use_vertex_mask = true; + } + + const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + + /* Show Edit points if: + * Edit mode: Not in Stroke selection mode + * Sculpt mode: If use Mask and not Stroke mode + * Weight mode: Always + * Vertex mode: If use Mask and not Stroke mode + */ + const bool show_points = show_sculpt_points || is_weight_paint || show_vertex_points || + (GPENCIL_EDIT_MODE(gpd) && + (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE)); + + if ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state); + + if (show_lines && !hide_lines) { + sh = OVERLAY_shader_edit_gpencil_wire(); + pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines); + DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); + DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select); + DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); + } + + if (show_points && !hide_select) { + sh = OVERLAY_shader_edit_gpencil_point(); + pd->edit_gpencil_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", do_multiedit); + DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); + DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); + } + } + + /* control points for primitives and speed guide */ + const bool is_cppoint = (gpd->runtime.tot_cp_points > 0); + const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide && + (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL)); + const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) && + ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0)); + + if ((is_cppoint || is_speed_guide) && (is_show_gizmo)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_gpencil_gizmos_ps, state); + + sh = OVERLAY_shader_edit_gpencil_guide_point(); + grp = DRW_shgroup_create(sh, psl->edit_gpencil_gizmos_ps); + + if (gpd->runtime.cp_points != NULL) { + for (int i = 0; i < gpd->runtime.tot_cp_points; i++) { + bGPDcontrolpoint *cp = &gpd->runtime.cp_points[i]; + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", &cp->x); + DRW_shgroup_uniform_float_copy(grp, "pSize", cp->size * 0.8f * G_draw.block.sizePixel); + DRW_shgroup_uniform_vec4_copy(grp, "pColor", cp->color); + DRW_shgroup_call_procedural_points(grp, NULL, 1); + } + } + + if (ts->gp_sculpt.guide.use_guide) { + float color[4]; + if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) { + UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.location); + } + else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT && + ts->gp_sculpt.guide.reference_object != NULL) { + UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.reference_object->loc); + } + else { + UI_GetThemeColor4fv(TH_REDALERT, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", scene->cursor.location); + } + DRW_shgroup_uniform_vec4_copy(grp, "pColor", color); + DRW_shgroup_uniform_float_copy(grp, "pSize", 8.0f * G_draw.block.sizePixel); + DRW_shgroup_call_procedural_points(grp, NULL, 1); + } + } +} + +void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + struct GPUShader *sh; + DRWShadingGroup *grp; + + /* Default: Display nothing. */ + psl->gpencil_canvas_ps = NULL; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + const View3DCursor *cursor = &scene->cursor; + + if (gpd == NULL || ob->type != OB_GPENCIL) { + return; + } + + const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; + const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0; + + if (show_grid && show_overlays) { + const char *grid_unit = NULL; + float mat[4][4]; + float col_grid[4]; + float size[2]; + + /* set color */ + copy_v3_v3(col_grid, gpd->grid.color); + col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f); + + copy_m4_m4(mat, ob->obmat); + + float viewinv[4][4]; + /* Set the grid in the selected axis */ + switch (ts->gp_sculpt.lock_axis) { + case GP_LOCKAXIS_X: + swap_v4_v4(mat[0], mat[2]); + break; + case GP_LOCKAXIS_Y: + swap_v4_v4(mat[1], mat[2]); + break; + case GP_LOCKAXIS_Z: + /* Default. */ + break; + case GP_LOCKAXIS_CURSOR: + loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, (float[3]){1, 1, 1}); + break; + case GP_LOCKAXIS_VIEW: + /* view aligned */ + DRW_view_viewmat_get(NULL, viewinv, true); + copy_v3_v3(mat[0], viewinv[0]); + copy_v3_v3(mat[1], viewinv[1]); + break; + } + + translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f); + mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit)); + rescale_m4(mat, (float[3]){size[0], size[1], 0.0f}); + + const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines; + int line_ct = gridlines * 4 + 2; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->gpencil_canvas_ps, state); + + sh = OVERLAY_shader_gpencil_canvas(); + grp = DRW_shgroup_create(sh, psl->gpencil_canvas_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_vec4_copy(grp, "color", col_grid); + DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]); + DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]); + DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]); + DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2); + DRW_shgroup_call_procedural_lines(grp, NULL, line_ct); + } +} + +static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + bGPdata *gpd = (bGPdata *)ob->data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + + if (pd->edit_gpencil_wires_grp) { + DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp); + DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color); + + struct GPUBatch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra); + DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob); + } + + if (pd->edit_gpencil_points_grp) { + const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0; + + DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp); + DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction); + + struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra); + DRW_shgroup_call_no_cull(grp, geom, ob); + } +} + +static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + Object *ob = (Object *)thunk; + Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1); + if (ma == NULL) { + return; + } + MaterialGPencilStyle *gp_style = ma->gp_style; + /* skip stroke if it doesn't have any valid data */ + if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) { + return; + } + /* check if the color is visible */ + if (gp_style->flag & GP_MATERIAL_HIDE) { + return; + } + /* only if selected */ + if (gps->flag & GP_STROKE_SELECT) { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + /* Draw name at the first selected point. */ + if (pt->flag & GP_SPOINT_SELECT) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + uchar color[4]; + UI_GetThemeColor4ubv(theme_id, color); + + float fpt[3]; + mul_v3_m4v3(fpt, ob->obmat, &pt->x); + + struct DRWTextStore *dt = DRW_text_cache_ensure(); + DRW_text_cache_add(dt, + fpt, + ma->id.name + 2, + strlen(ma->id.name + 2), + 10, + 0, + DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, + color); + break; + } + } + } +} + +static void OVERLAY_gpencil_color_names(Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + int cfra = DEG_get_ctime(draw_ctx->depsgraph); + + BKE_gpencil_visible_stroke_iter( + ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); +} + +void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + + bGPdata *gpd = (bGPdata *)ob->data; + if (gpd == NULL) { + return; + } + + if (GPENCIL_ANY_MODE(gpd)) { + OVERLAY_edit_gpencil_cache_populate(vedata, ob); + } + + /* don't show object extras in set's */ + if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { + if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL) && + DRW_state_show_text()) { + OVERLAY_gpencil_color_names(ob); + } + } +} + +void OVERLAY_gpencil_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->gpencil_canvas_ps) { + DRW_draw_pass(psl->gpencil_canvas_ps); + } +} + +void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->edit_gpencil_gizmos_ps) { + DRW_draw_pass(psl->edit_gpencil_gizmos_ps); + } + + if (psl->edit_gpencil_ps) { + DRW_draw_pass(psl->edit_gpencil_ps); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c index 555e0084c49..29eb4fd12a4 100644 --- a/source/blender/draw/engines/overlay/overlay_motion_path.c +++ b/source/blender/draw/engines/overlay/overlay_motion_path.c @@ -155,7 +155,7 @@ static void motion_path_cache(OVERLAY_Data *vedata, DRW_shgroup_uniform_bool_copy(grp, "selected", selected); DRW_shgroup_uniform_vec3_copy(grp, "customColor", color); /* Only draw the required range. */ - DRW_shgroup_call_range(grp, mpath_batch_line_get(mpath), start_index, len); + DRW_shgroup_call_range(grp, NULL, mpath_batch_line_get(mpath), start_index, len); } /* Draw points. */ @@ -167,7 +167,7 @@ static void motion_path_cache(OVERLAY_Data *vedata, DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes); DRW_shgroup_uniform_vec3_copy(grp, "customColor", color); /* Only draw the required range. */ - DRW_shgroup_call_range(grp, mpath_batch_points_get(mpath), start_index, len); + DRW_shgroup_call_range(grp, NULL, mpath_batch_points_get(mpath), start_index, len); } /* Draw frame numbers at each frame-step value. */ diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index 63738b3c214..e77a0a143a9 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -23,13 +23,67 @@ #include "DRW_render.h" #include "BKE_global.h" +#include "BKE_gpencil.h" -#include "DNA_lightprobe_types.h" +#include "BKE_object.h" + +#include "DNA_gpencil_types.h" #include "UI_resources.h" #include "overlay_private.h" +/* Returns the normal plane in ndc space. */ +static void gpencil_depth_plane(Object *ob, float r_plane[4]) +{ + /* TODO put that into private data. */ + float viewinv[4][4]; + DRW_view_viewmat_get(NULL, viewinv, true); + float *camera_z_axis = viewinv[2]; + float *camera_pos = viewinv[3]; + + /* Find the normal most likely to represent the gpObject. */ + /* TODO: This does not work quite well if you use + * strokes not aligned with the object axes. Maybe we could try to + * compute the minimum axis of all strokes. But this would be more + * computationaly heavy and should go into the GPData evaluation. */ + BoundBox *bbox = BKE_object_boundbox_get(ob); + /* Convert bbox to matrix */ + float mat[4][4], size[3], center[3]; + BKE_boundbox_calc_size_aabb(bbox, size); + BKE_boundbox_calc_center_aabb(bbox, center); + unit_m4(mat); + copy_v3_v3(mat[3], center); + /* Avoid division by 0.0 later. */ + add_v3_fl(size, 1e-8f); + rescale_m4(mat, size); + /* BBox space to World. */ + mul_m4_m4m4(mat, ob->obmat, mat); + /* BBox center in world space. */ + copy_v3_v3(center, mat[3]); + /* View Vector. */ + if (DRW_view_is_persp_get(NULL)) { + /* BBox center to camera vector. */ + sub_v3_v3v3(r_plane, camera_pos, mat[3]); + } + else { + copy_v3_v3(r_plane, camera_z_axis); + } + /* World to BBox space. */ + invert_m4(mat); + /* Normalize the vector in BBox space. */ + mul_mat3_m4_v3(mat, r_plane); + normalize_v3(r_plane); + + transpose_m4(mat); + /* mat is now a "normal" matrix which will transform + * BBox space normal to world space. */ + mul_mat3_m4_v3(mat, r_plane); + normalize_v3(r_plane); + + plane_from_point_normal_v3(r_plane, center, r_plane); +} + void OVERLAY_outline_init(OVERLAY_Data *vedata) { OVERLAY_FramebufferList *fbl = vedata->fbl; @@ -79,6 +133,11 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps); DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); + + GPUShader *sh_gpencil = OVERLAY_shader_outline_prepass_gpencil(); + + pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps); + DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); } /* outlines_prepass_ps is still needed for selection of probes. */ @@ -107,6 +166,98 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) } } +typedef struct iterData { + Object *ob; + DRWShadingGroup *stroke_grp; + DRWShadingGroup *fill_grp; + int cfra; + float plane[4]; +} iterData; + +static void gp_layer_cache_populate(bGPDlayer *gpl, + bGPDframe *UNUSED(gpf), + bGPDstroke *UNUSED(gps), + void *thunk) +{ + iterData *iter = (iterData *)thunk; + bGPdata *gpd = (bGPdata *)iter->ob->data; + + const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0; + const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D); + + float object_scale = mat4_to_scale(iter->ob->obmat); + /* Negate thickness sign to tag that strokes are in screen space. + * Convert to world units (by default, 1 meter = 2000 px). */ + float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f); + + DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp); + DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", is_stroke_order_3d); + DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get()); + DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get()); + DRW_shgroup_uniform_float_copy(grp, "thicknessScale", object_scale); + DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change); + DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale); + DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane); +} + +static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + iterData *iter = (iterData *)thunk; + + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1); + + bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; + // TODO: What about simplify Fill? + bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + + if (hide_material) { + return; + } + + if (show_fill) { + struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra); + int vfirst = gps->runtime.fill_start * 3; + int vcount = gps->tot_triangles * 3; + DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount); + } + + if (show_stroke) { + struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra); + /* Start one vert before to have gl_InstanceID > 0 (see shader). */ + int vfirst = gps->runtime.stroke_start - 1; + /* Include "potential" cyclic vertex and start adj vertex (see shader). */ + int vcount = gps->totpoints + 1 + 1; + DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); + } +} + +static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) +{ + /* No outlines in edit mode. */ + bGPdata *gpd = (bGPdata *)ob->data; + if (gpd && GPENCIL_ANY_MODE(gpd)) { + return; + } + + iterData iter = { + .ob = ob, + .stroke_grp = pd->outlines_gpencil_grp, + .fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp), + .cfra = pd->cfra, + }; + + if (gpd->draw_mode == GP_DRAWMODE_2D) { + gpencil_depth_plane(ob, iter.plane); + } + + BKE_gpencil_visible_stroke_iter( + ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra); +} + void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, Object *ob, OVERLAY_DupliData *dupli, @@ -123,6 +274,11 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, return; } + if (ob->type == OB_GPENCIL) { + OVERLAY_outline_gpencil(pd, ob); + return; + } + if (dupli && !init_dupli) { geom = dupli->outline_geom; shgroup = dupli->outline_shgrp; diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 185df723301..167a8e940df 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -60,6 +60,8 @@ typedef struct OVERLAY_PassList { DRWPass *clipping_frustum_ps; DRWPass *edit_curve_wire_ps[2]; DRWPass *edit_curve_handle_ps; + DRWPass *edit_gpencil_ps; + DRWPass *edit_gpencil_gizmos_ps; DRWPass *edit_lattice_ps; DRWPass *edit_mesh_depth_ps[2]; DRWPass *edit_mesh_verts_ps[2]; @@ -76,6 +78,7 @@ typedef struct OVERLAY_PassList { DRWPass *extra_blend_ps; DRWPass *extra_centers_ps; DRWPass *extra_grid_ps; + DRWPass *gpencil_canvas_ps; DRWPass *facing_ps; DRWPass *grid_ps; DRWPass *image_background_ps; @@ -219,6 +222,8 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *edit_curve_points_grp; DRWShadingGroup *edit_lattice_points_grp; DRWShadingGroup *edit_lattice_wires_grp; + DRWShadingGroup *edit_gpencil_points_grp; + DRWShadingGroup *edit_gpencil_wires_grp; DRWShadingGroup *edit_mesh_depth_grp[2]; DRWShadingGroup *edit_mesh_faces_grp[2]; DRWShadingGroup *edit_mesh_faces_cage_grp[2]; @@ -238,6 +243,7 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *motion_path_lines_grp; DRWShadingGroup *motion_path_points_grp; DRWShadingGroup *outlines_grp; + DRWShadingGroup *outlines_gpencil_grp; DRWShadingGroup *paint_surf_grp; DRWShadingGroup *paint_wire_grp; DRWShadingGroup *paint_wire_selected_grp; @@ -277,6 +283,7 @@ typedef struct OVERLAY_PrivateData { float xray_opacity; short v3d_flag; /* TODO move to View3DOverlay */ short v3d_gridflag; /* TODO move to View3DOverlay */ + int cfra; DRWState clipping_state; OVERLAY_ShadingData shdata; @@ -419,6 +426,12 @@ void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata); +void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata); +void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata); +void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_gpencil_draw(OVERLAY_Data *vedata); +void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata); + void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata); void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob); @@ -446,7 +459,6 @@ void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata); void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob); @@ -547,6 +559,9 @@ GPUShader *OVERLAY_shader_depth_only(void); GPUShader *OVERLAY_shader_edit_curve_handle(void); GPUShader *OVERLAY_shader_edit_curve_point(void); GPUShader *OVERLAY_shader_edit_curve_wire(void); +GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void); +GPUShader *OVERLAY_shader_edit_gpencil_point(void); +GPUShader *OVERLAY_shader_edit_gpencil_wire(void); GPUShader *OVERLAY_shader_edit_lattice_point(void); GPUShader *OVERLAY_shader_edit_lattice_wire(void); GPUShader *OVERLAY_shader_edit_mesh_analysis(void); @@ -564,12 +579,14 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object); GPUShader *OVERLAY_shader_extra_loose_point(void); GPUShader *OVERLAY_shader_extra_point(void); GPUShader *OVERLAY_shader_facing(void); +GPUShader *OVERLAY_shader_gpencil_canvas(void); GPUShader *OVERLAY_shader_grid(void); GPUShader *OVERLAY_shader_image(void); GPUShader *OVERLAY_shader_motion_path_line(void); GPUShader *OVERLAY_shader_motion_path_vert(void); GPUShader *OVERLAY_shader_uniform_color(void); GPUShader *OVERLAY_shader_outline_prepass(bool use_wire); +GPUShader *OVERLAY_shader_outline_prepass_gpencil(void); GPUShader *OVERLAY_shader_extra_grid(void); GPUShader *OVERLAY_shader_outline_detect(void); GPUShader *OVERLAY_shader_paint_face(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index d33ef239198..86d5f58957e 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -54,6 +54,9 @@ extern char datatoc_edit_curve_handle_geom_glsl[]; extern char datatoc_edit_curve_handle_vert_glsl[]; extern char datatoc_edit_curve_point_vert_glsl[]; extern char datatoc_edit_curve_wire_vert_glsl[]; +extern char datatoc_edit_gpencil_canvas_vert_glsl[]; +extern char datatoc_edit_gpencil_guide_vert_glsl[]; +extern char datatoc_edit_gpencil_vert_glsl[]; extern char datatoc_edit_lattice_point_vert_glsl[]; extern char datatoc_edit_lattice_wire_vert_glsl[]; extern char datatoc_edit_mesh_common_lib_glsl[]; @@ -113,6 +116,8 @@ extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[]; extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; +extern char datatoc_gpencil_common_lib_glsl[]; + extern char datatoc_common_colormanagement_lib_glsl[]; extern char datatoc_common_fullscreen_vert_glsl[]; extern char datatoc_common_fxaa_lib_glsl[]; @@ -138,6 +143,9 @@ typedef struct OVERLAY_Shaders { GPUShader *edit_curve_handle; GPUShader *edit_curve_point; GPUShader *edit_curve_wire; + GPUShader *edit_gpencil_guide_point; + GPUShader *edit_gpencil_point; + GPUShader *edit_gpencil_wire; GPUShader *edit_lattice_point; GPUShader *edit_lattice_wire; GPUShader *edit_mesh_vert; @@ -159,11 +167,13 @@ typedef struct OVERLAY_Shaders { GPUShader *extra_lightprobe_grid; GPUShader *extra_loose_point; GPUShader *facing; + GPUShader *gpencil_canvas; GPUShader *grid; GPUShader *image; GPUShader *motion_path_line; GPUShader *motion_path_vert; GPUShader *outline_prepass; + GPUShader *outline_prepass_gpencil; GPUShader *outline_prepass_wire; GPUShader *outline_detect; GPUShader *paint_face; @@ -557,6 +567,58 @@ GPUShader *OVERLAY_shader_edit_curve_wire(void) return sh_data->edit_curve_wire; } +GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_gpencil_guide_point) { + sh_data->edit_gpencil_guide_point = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_guide_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL}, + }); + } + return sh_data->edit_gpencil_guide_point; +} + +GPUShader *OVERLAY_shader_edit_gpencil_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->edit_gpencil_point) { + sh_data->edit_gpencil_point = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define USE_POINTS\n", NULL}, + }); + } + return sh_data->edit_gpencil_point; +} + +GPUShader *OVERLAY_shader_edit_gpencil_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->edit_gpencil_wire) { + sh_data->edit_gpencil_wire = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); + } + return sh_data->edit_gpencil_wire; +} + GPUShader *OVERLAY_shader_edit_lattice_point(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -883,6 +945,21 @@ GPUShader *OVERLAY_shader_facing(void) return sh_data->facing; } +GPUShader *OVERLAY_shader_gpencil_canvas(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->gpencil_canvas) { + sh_data->gpencil_canvas = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_canvas_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL}, + }); + } + return sh_data->gpencil_canvas; +} + GPUShader *OVERLAY_shader_grid(void) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; @@ -998,6 +1075,32 @@ GPUShader *OVERLAY_shader_outline_prepass(bool use_wire) return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass; } +GPUShader *OVERLAY_shader_outline_prepass_gpencil(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->outline_prepass_gpencil) { + sh_data->outline_prepass_gpencil = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_gpencil_common_lib_glsl, + datatoc_gpu_shader_common_obinfos_lib_glsl, + datatoc_outline_prepass_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_gpencil_common_lib_glsl, + datatoc_outline_prepass_frag_glsl, + NULL}, + .defs = (const char *[]){sh_cfg->def, + "#define USE_GPENCIL\n", + "#define UNIFORM_RESOURCE_ID\n", + NULL}, + }); + } + return sh_data->outline_prepass_gpencil; +} + GPUShader *OVERLAY_shader_outline_detect(void) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index 5dbdc71dae1..4df9faace18 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -201,7 +201,11 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, shgrp = pd->wires_grp[is_xray][use_coloring]; } - if (use_sculpt_pbvh) { + if (ob->type == OB_GPENCIL) { + /* TODO (fclem) Make GPencil objects have correct boundbox. */ + DRW_shgroup_call_no_cull(shgrp, geom, ob); + } + else if (use_sculpt_pbvh) { DRW_shgroup_call_sculpt(shgrp, ob, true, false, false); } else { diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl new file mode 100644 index 00000000000..5aa7fe78e4e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl @@ -0,0 +1,35 @@ + +uniform vec4 color; +uniform vec3 xAxis; +uniform vec3 yAxis; +uniform vec3 origin; +uniform int halfLineCount; + +flat out vec4 finalColor; +flat out vec2 edgeStart; +noperspective out vec2 edgePos; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec2 pos; + pos.x = float(gl_VertexID % 2); + pos.y = float(gl_VertexID / 2) / float(halfLineCount - 1); + + if (pos.y > 1.0) { + pos.xy = pos.yx; + pos.x -= 1.0 + 1.0 / float(halfLineCount - 1); + } + + pos -= 0.5; + + vec3 world_pos = xAxis * pos.x + yAxis * pos.y + origin; + + gl_Position = point_world_to_ndc(world_pos); + + finalColor = color; + + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl new file mode 100644 index 00000000000..ef68b0f4e6f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl @@ -0,0 +1,14 @@ +uniform vec4 pColor; +uniform float pSize; +uniform vec3 pPosition; + +out vec4 finalColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + gl_Position = point_world_to_ndc(pPosition); + finalColor = pColor; + gl_PointSize = pSize; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl new file mode 100644 index 00000000000..cb03ad44615 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl @@ -0,0 +1,103 @@ + +uniform float normalSize; +uniform bool doMultiframe; +uniform bool doStrokeEndpoints; +uniform bool hideSelect; +uniform bool doWeightColor; +uniform float gpEditOpacity; +uniform vec4 gpEditColor; +uniform sampler1D weightTex; + +in vec3 pos; +in float ma; +in uint vflag; +in float weight; + +out vec4 finalColor; + +void discard_vert() +{ + /* We set the vertex at the camera origin to generate 0 fragments. */ + gl_Position = vec4(0.0, 0.0, -3e36, 0.0); +} + +#define GP_EDIT_POINT_SELECTED (1u << 0u) +#define GP_EDIT_STROKE_SELECTED (1u << 1u) +#define GP_EDIT_MULTIFRAME (1u << 2u) +#define GP_EDIT_STROKE_START (1u << 3u) +#define GP_EDIT_STROKE_END (1u << 4u) + +#ifdef USE_POINTS +# define colorUnselect colorGpencilVertex +# define colorSelect colorGpencilVertexSelect +#else +# define colorUnselect gpEditColor +# define colorSelect (hideSelect ? colorUnselect : colorGpencilVertexSelect) +#endif + +vec3 weight_to_rgb(float t) +{ + if (t < 0.0) { + /* No weight */ + return colorUnselect.rgb; + } + else if (t > 1.0) { + /* Error color */ + return vec3(1.0, 0.0, 1.0); + } + else { + return texture(weightTex, t).rgb; + } +} + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + bool is_multiframe = (vflag & GP_EDIT_MULTIFRAME) != 0u; + bool is_stroke_sel = (vflag & GP_EDIT_STROKE_SELECTED) != 0u; + bool is_point_sel = (vflag & GP_EDIT_POINT_SELECTED) != 0u; + + if (doWeightColor) { + finalColor.rgb = weight_to_rgb(weight); + finalColor.a = gpEditOpacity; + } + else { + finalColor = (is_point_sel) ? colorSelect : colorUnselect; + finalColor.a *= gpEditOpacity; + } + +#ifdef USE_POINTS + gl_PointSize = sizeVertex * 2.0; + + if (doStrokeEndpoints && !doWeightColor) { + bool is_stroke_start = (vflag & GP_EDIT_STROKE_START) != 0u; + bool is_stroke_end = (vflag & GP_EDIT_STROKE_END) != 0u; + + if (is_stroke_start) { + gl_PointSize *= 2.0; + finalColor.rgb = vec3(0.0, 1.0, 0.0); + } + else if (is_stroke_end) { + gl_PointSize *= 1.5; + finalColor.rgb = vec3(1.0, 0.0, 0.0); + } + } + + if ((!is_stroke_sel && !doWeightColor) || (!doMultiframe && is_multiframe)) { + discard_vert(); + } +#endif + + /* Discard unwanted padding vertices. */ + if (ma == -1.0 || (is_multiframe && !doMultiframe)) { + discard_vert(); + } + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl index f6e3724eb51..85f79e94263 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl @@ -1,10 +1,46 @@ +uniform vec4 gpDepthPlane; + flat in uint objectId; /* using uint because 16bit uint can contain more ids than int. */ out uint outId; +vec3 ray_plane_intersection(vec3 ray_ori, vec3 ray_dir, vec4 plane) +{ + float d = dot(plane.xyz, ray_dir); + vec3 plane_co = plane.xyz * (-plane.w / dot(plane.xyz, plane.xyz)); + vec3 h = ray_ori - plane_co; + float lambda = -dot(plane.xyz, h) / ((abs(d) < 1e-8) ? 1e-8 : d); + return ray_ori + ray_dir * lambda; +} + void main() { - outId = objectId; +#ifdef USE_GPENCIL + if (stroke_round_cap_mask(strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness) < + 0.001) { + discard; + } + + if (depth != -1.0) { + /* Stroke order 2D. */ + bool is_persp = ProjectionMatrix[3][3] == 0.0; + vec2 uvs = vec2(gl_FragCoord.xy) * sizeViewportInv; + vec3 pos_ndc = vec3(uvs, gl_FragCoord.z) * 2.0 - 1.0; + vec4 pos_world = ViewProjectionMatrixInverse * vec4(pos_ndc, 1.0); + vec3 pos = pos_world.xyz / pos_world.w; + + vec3 ray_ori = pos; + vec3 ray_dir = (is_persp) ? (ViewMatrixInverse[3].xyz - pos) : ViewMatrixInverse[2].xyz; + vec3 isect = ray_plane_intersection(ray_ori, ray_dir, gpDepthPlane); + vec4 ndc = point_world_to_ndc(isect); + gl_FragDepth = (ndc.z / ndc.w) * 0.5 + 0.5; + } + else { + gl_FragDepth = gl_FragCoord.z; + } +#endif + + outId = uint(objectId); } diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl index 984e55b0c46..a2021759196 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl @@ -1,7 +1,9 @@ uniform bool isTransform; +#ifndef USE_GPENCIL in vec3 pos; +#endif #ifdef USE_GEOM out vec3 vPos; @@ -47,11 +49,19 @@ uint outline_colorid_get(void) void main() { +#ifdef USE_GPENCIL + gpencil_vertex(); +# ifdef USE_WORLD_CLIP_PLANES + vec3 world_pos = point_object_to_world(pos1.xyz); +# endif + +#else vec3 world_pos = point_object_to_world(pos); -#ifdef USE_GEOM + gl_Position = point_world_to_ndc(world_pos); +# ifdef USE_GEOM vPos = point_world_to_view(world_pos); +# endif #endif - gl_Position = point_world_to_ndc(world_pos); /* Small bias to always be on top of the geom. */ gl_Position.z -= 1e-3; diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 31ac9a2b181..1abac302cda 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -101,8 +101,10 @@ void wire_object_color_get(out vec3 rim_col, out vec3 wire_col) void main() { + bool no_attrib = all(equal(nor, vec3(0))); + vec3 wnor = no_attrib ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor)); + vec3 wpos = point_object_to_world(pos); - vec3 wnor = normalize(normal_object_to_world(nor)); bool is_persp = (ProjectionMatrix[3][3] == 0.0); vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz; @@ -147,7 +149,7 @@ void main() #endif /* Cull flat edges below threshold. */ - if (get_edge_sharpness(wd) < 0.0) { + if (!no_attrib && (get_edge_sharpness(wd) < 0.0)) { edgeStart = vec2(-1.0); } |