1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2020, Blender Foundation.
17  */
18 
19 /** \file
20  * \ingroup draw_engine
21  */
22 
23 #include "DRW_render.h"
24 
25 #include "BKE_gpencil.h"
26 
27 #include "UI_resources.h"
28 
29 #include "DNA_gpencil_types.h"
30 
31 #include "DEG_depsgraph_query.h"
32 
33 #include "ED_view3d.h"
34 
35 #include "overlay_private.h"
36 
37 #include "draw_common.h"
38 #include "draw_manager_text.h"
39 
OVERLAY_edit_gpencil_cache_init(OVERLAY_Data * vedata)40 void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
41 {
42   OVERLAY_PassList *psl = vedata->psl;
43   OVERLAY_PrivateData *pd = vedata->stl->pd;
44   struct GPUShader *sh;
45   DRWShadingGroup *grp;
46 
47   /* Default: Display nothing. */
48   pd->edit_gpencil_points_grp = NULL;
49   pd->edit_gpencil_wires_grp = NULL;
50   psl->edit_gpencil_ps = NULL;
51 
52   const DRWContextState *draw_ctx = DRW_context_state_get();
53   View3D *v3d = draw_ctx->v3d;
54   Object *ob = draw_ctx->obact;
55   bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL;
56   Scene *scene = draw_ctx->scene;
57   ToolSettings *ts = scene->toolsettings;
58 
59   if (gpd == NULL || ob->type != OB_GPENCIL) {
60     return;
61   }
62 
63   /* For sculpt show only if mask mode, and only points if not stroke mode. */
64   const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) &&
65                                 GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt));
66   const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) &&
67                                    (ts->gpencil_selectmode_sculpt &
68                                     (GP_SCULPT_MASK_SELECTMODE_POINT |
69                                      GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
70 
71   /* For vertex paint show only if mask mode, and only points if not stroke mode. */
72   bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) &&
73                           GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex));
74   const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) &&
75                                    (ts->gpencil_selectmode_vertex &
76                                     (GP_VERTEX_MASK_SELECTMODE_POINT |
77                                      GP_VERTEX_MASK_SELECTMODE_SEGMENT)));
78 
79   /* If Sculpt or Vertex mode and the mask is disabled, the select must be hidden. */
80   const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) ||
81                             (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask));
82 
83   const bool do_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
84   const bool show_multi_edit_lines = (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
85 
86   const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) || show_multi_edit_lines;
87 
88   const bool hide_lines = !GPENCIL_EDIT_MODE(gpd) && !GPENCIL_WEIGHT_MODE(gpd) &&
89                           !use_sculpt_mask && !use_vertex_mask && !show_lines;
90 
91   /* Special case when vertex paint and multiedit lines. */
92   if (do_multiedit && show_multi_edit_lines && GPENCIL_VERTEX_MODE(gpd)) {
93     use_vertex_mask = true;
94   }
95 
96   const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
97 
98   /* Show Edit points if:
99    *  Edit mode: Not in Stroke selection mode
100    *  Sculpt mode: If use Mask and not Stroke mode
101    *  Weight mode: Always
102    *  Vertex mode: If use Mask and not Stroke mode
103    */
104   const bool show_points = show_sculpt_points || is_weight_paint || show_vertex_points ||
105                            (GPENCIL_EDIT_MODE(gpd) &&
106                             (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
107 
108   if ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask) {
109     DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
110                      DRW_STATE_BLEND_ALPHA;
111     DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state);
112 
113     if (show_lines && !hide_lines) {
114       sh = OVERLAY_shader_edit_gpencil_wire();
115       pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps);
116       DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
117       DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines);
118       DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint);
119       DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select);
120       DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity);
121       DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
122     }
123 
124     if (show_points && !hide_select) {
125       sh = OVERLAY_shader_edit_gpencil_point();
126       pd->edit_gpencil_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps);
127       DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
128       DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", do_multiedit);
129       DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint);
130       DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity);
131       DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
132     }
133   }
134 
135   /* control points for primitives and speed guide */
136   const bool is_cppoint = (gpd->runtime.tot_cp_points > 0);
137   const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide &&
138                                (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL));
139   const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) &&
140                               ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0));
141 
142   if ((is_cppoint || is_speed_guide) && (is_show_gizmo)) {
143     DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
144     DRW_PASS_CREATE(psl->edit_gpencil_gizmos_ps, state);
145 
146     sh = OVERLAY_shader_edit_gpencil_guide_point();
147     grp = DRW_shgroup_create(sh, psl->edit_gpencil_gizmos_ps);
148 
149     if (gpd->runtime.cp_points != NULL) {
150       for (int i = 0; i < gpd->runtime.tot_cp_points; i++) {
151         bGPDcontrolpoint *cp = &gpd->runtime.cp_points[i];
152         grp = DRW_shgroup_create_sub(grp);
153         DRW_shgroup_uniform_vec3_copy(grp, "pPosition", &cp->x);
154         DRW_shgroup_uniform_float_copy(grp, "pSize", cp->size * 0.8f * G_draw.block.sizePixel);
155         DRW_shgroup_uniform_vec4_copy(grp, "pColor", cp->color);
156         DRW_shgroup_call_procedural_points(grp, NULL, 1);
157       }
158     }
159 
160     if (ts->gp_sculpt.guide.use_guide) {
161       float color[4];
162       if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) {
163         UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
164         DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.location);
165       }
166       else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT &&
167                ts->gp_sculpt.guide.reference_object != NULL) {
168         UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
169         DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.reference_object->loc);
170       }
171       else {
172         UI_GetThemeColor4fv(TH_REDALERT, color);
173         DRW_shgroup_uniform_vec3_copy(grp, "pPosition", scene->cursor.location);
174       }
175       DRW_shgroup_uniform_vec4_copy(grp, "pColor", color);
176       DRW_shgroup_uniform_float_copy(grp, "pSize", 8.0f * G_draw.block.sizePixel);
177       DRW_shgroup_call_procedural_points(grp, NULL, 1);
178     }
179   }
180 }
181 
OVERLAY_gpencil_cache_init(OVERLAY_Data * vedata)182 void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
183 {
184   OVERLAY_PassList *psl = vedata->psl;
185   struct GPUShader *sh;
186   DRWShadingGroup *grp;
187 
188   /* Default: Display nothing. */
189   psl->gpencil_canvas_ps = NULL;
190 
191   const DRWContextState *draw_ctx = DRW_context_state_get();
192   View3D *v3d = draw_ctx->v3d;
193   Object *ob = draw_ctx->obact;
194   bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL;
195   Scene *scene = draw_ctx->scene;
196   ToolSettings *ts = scene->toolsettings;
197   const View3DCursor *cursor = &scene->cursor;
198 
199   if (gpd == NULL || ob->type != OB_GPENCIL) {
200     return;
201   }
202 
203   const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
204   const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0 &&
205                          ((ts->gpencil_v3d_align &
206                            (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) == 0);
207   const bool grid_xray = (v3d->gp_flag & V3D_GP_SHOW_GRID_XRAY);
208 
209   if (show_grid && show_overlays) {
210     const char *grid_unit = NULL;
211     float mat[4][4];
212     float col_grid[4];
213     float size[2];
214 
215     /* set color */
216     copy_v3_v3(col_grid, gpd->grid.color);
217     col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f);
218 
219     copy_m4_m4(mat, ob->obmat);
220 
221     float viewinv[4][4];
222     /* Set the grid in the selected axis */
223     switch (ts->gp_sculpt.lock_axis) {
224       case GP_LOCKAXIS_X:
225         swap_v4_v4(mat[0], mat[2]);
226         break;
227       case GP_LOCKAXIS_Y:
228         swap_v4_v4(mat[1], mat[2]);
229         break;
230       case GP_LOCKAXIS_Z:
231         /* Default. */
232         break;
233       case GP_LOCKAXIS_CURSOR:
234         loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, (float[3]){1, 1, 1});
235         break;
236       case GP_LOCKAXIS_VIEW:
237         /* view aligned */
238         DRW_view_viewmat_get(NULL, viewinv, true);
239         copy_v3_v3(mat[0], viewinv[0]);
240         copy_v3_v3(mat[1], viewinv[1]);
241         break;
242     }
243 
244     /* Move the grid to the right location depending of the align type.
245      * This is required only for 3D Cursor or Origin. */
246     if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
247       copy_v3_v3(mat[3], cursor->location);
248     }
249     else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) {
250       copy_v3_v3(mat[3], ob->obmat[3]);
251     }
252 
253     translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f);
254     mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit));
255     rescale_m4(mat, (float[3]){size[0], size[1], 0.0f});
256 
257     const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
258     int line_ct = gridlines * 4 + 2;
259 
260     DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
261     state |= (grid_xray) ? DRW_STATE_DEPTH_ALWAYS : DRW_STATE_DEPTH_LESS_EQUAL;
262 
263     DRW_PASS_CREATE(psl->gpencil_canvas_ps, state);
264 
265     sh = OVERLAY_shader_gpencil_canvas();
266     grp = DRW_shgroup_create(sh, psl->gpencil_canvas_ps);
267     DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
268     DRW_shgroup_uniform_vec4_copy(grp, "color", col_grid);
269     DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]);
270     DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]);
271     DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]);
272     DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2);
273     DRW_shgroup_call_procedural_lines(grp, NULL, line_ct);
274   }
275 }
276 
OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data * vedata,Object * ob)277 static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
278 {
279   OVERLAY_PrivateData *pd = vedata->stl->pd;
280   bGPdata *gpd = (bGPdata *)ob->data;
281   const DRWContextState *draw_ctx = DRW_context_state_get();
282   View3D *v3d = draw_ctx->v3d;
283 
284   /* Overlay is only for active object. */
285   if (ob != draw_ctx->obact) {
286     return;
287   }
288 
289   if (pd->edit_gpencil_wires_grp) {
290     DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp);
291     DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color);
292 
293     struct GPUBatch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra);
294     DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob);
295   }
296 
297   if (pd->edit_gpencil_points_grp) {
298     const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0;
299 
300     DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp);
301     DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction);
302 
303     struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra);
304     DRW_shgroup_call_no_cull(grp, geom, ob);
305   }
306 }
307 
overlay_gpencil_draw_stroke_color_name(bGPDlayer * UNUSED (gpl),bGPDframe * UNUSED (gpf),bGPDstroke * gps,void * thunk)308 static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl),
309                                                    bGPDframe *UNUSED(gpf),
310                                                    bGPDstroke *gps,
311                                                    void *thunk)
312 {
313   Object *ob = (Object *)thunk;
314   Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
315   if (ma == NULL) {
316     return;
317   }
318   MaterialGPencilStyle *gp_style = ma->gp_style;
319   /* skip stroke if it doesn't have any valid data */
320   if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
321     return;
322   }
323   /* check if the color is visible */
324   if (gp_style->flag & GP_MATERIAL_HIDE) {
325     return;
326   }
327   /* only if selected */
328   if (gps->flag & GP_STROKE_SELECT) {
329     for (int i = 0; i < gps->totpoints; i++) {
330       bGPDspoint *pt = &gps->points[i];
331       /* Draw name at the first selected point. */
332       if (pt->flag & GP_SPOINT_SELECT) {
333         const DRWContextState *draw_ctx = DRW_context_state_get();
334         ViewLayer *view_layer = draw_ctx->view_layer;
335 
336         int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
337         uchar color[4];
338         UI_GetThemeColor4ubv(theme_id, color);
339 
340         float fpt[3];
341         mul_v3_m4v3(fpt, ob->obmat, &pt->x);
342 
343         struct DRWTextStore *dt = DRW_text_cache_ensure();
344         DRW_text_cache_add(dt,
345                            fpt,
346                            ma->id.name + 2,
347                            strlen(ma->id.name + 2),
348                            10,
349                            0,
350                            DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
351                            color);
352         break;
353       }
354     }
355   }
356 }
357 
OVERLAY_gpencil_color_names(Object * ob)358 static void OVERLAY_gpencil_color_names(Object *ob)
359 {
360   const DRWContextState *draw_ctx = DRW_context_state_get();
361   int cfra = DEG_get_ctime(draw_ctx->depsgraph);
362 
363   BKE_gpencil_visible_stroke_iter(
364       NULL, ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra);
365 }
366 
OVERLAY_gpencil_cache_populate(OVERLAY_Data * vedata,Object * ob)367 void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
368 {
369   const DRWContextState *draw_ctx = DRW_context_state_get();
370   View3D *v3d = draw_ctx->v3d;
371 
372   bGPdata *gpd = (bGPdata *)ob->data;
373   if (gpd == NULL) {
374     return;
375   }
376 
377   if (GPENCIL_ANY_MODE(gpd)) {
378     OVERLAY_edit_gpencil_cache_populate(vedata, ob);
379   }
380 
381   /* don't show object extras in set's */
382   if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
383     if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL) &&
384         DRW_state_show_text()) {
385       OVERLAY_gpencil_color_names(ob);
386     }
387   }
388 }
389 
OVERLAY_gpencil_draw(OVERLAY_Data * vedata)390 void OVERLAY_gpencil_draw(OVERLAY_Data *vedata)
391 {
392   OVERLAY_PassList *psl = vedata->psl;
393 
394   if (psl->gpencil_canvas_ps) {
395     DRW_draw_pass(psl->gpencil_canvas_ps);
396   }
397 }
398 
OVERLAY_edit_gpencil_draw(OVERLAY_Data * vedata)399 void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata)
400 {
401   OVERLAY_PassList *psl = vedata->psl;
402 
403   if (psl->edit_gpencil_gizmos_ps) {
404     DRW_draw_pass(psl->edit_gpencil_gizmos_ps);
405   }
406 
407   if (psl->edit_gpencil_ps) {
408     DRW_draw_pass(psl->edit_gpencil_ps);
409   }
410 }
411