diff options
Diffstat (limited to 'source/blender/draw/engines/overlay/overlay_gpencil.c')
-rw-r--r-- | source/blender/draw/engines/overlay/overlay_gpencil.c | 391 |
1 files changed, 391 insertions, 0 deletions
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); + } +} |