Blender  V2.93
drawgpencil.c
Go to the documentation of this file.
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  * The Original Code is Copyright (C) 2008, Blender Foundation
17  * This is a new part of Blender
18  */
19 
24 #include <float.h>
25 #include <math.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_sys_types.h"
34 
35 #include "BLI_math.h"
36 #include "BLI_polyfill_2d.h"
37 #include "BLI_utildefines.h"
38 
39 #include "BLF_api.h"
40 #include "BLT_translation.h"
41 
42 #include "DNA_brush_types.h"
43 #include "DNA_gpencil_types.h"
44 #include "DNA_material_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_userdef_types.h"
50 #include "DNA_view3d_types.h"
51 
52 #include "BKE_brush.h"
53 #include "BKE_context.h"
54 #include "BKE_global.h"
55 #include "BKE_gpencil.h"
56 #include "BKE_image.h"
57 #include "BKE_material.h"
58 #include "BKE_paint.h"
59 
60 #include "DEG_depsgraph.h"
61 
62 #include "WM_api.h"
63 
64 #include "GPU_immediate.h"
65 #include "GPU_matrix.h"
66 #include "GPU_state.h"
67 
68 #include "ED_gpencil.h"
69 #include "ED_screen.h"
70 #include "ED_space_api.h"
71 #include "ED_view3d.h"
72 
73 #include "UI_interface_icons.h"
74 #include "UI_resources.h"
75 
76 #include "IMB_imbuf_types.h"
77 
78 #include "gpencil_intern.h"
79 
80 /* ************************************************** */
81 /* GREASE PENCIL DRAWING */
82 
83 /* ----- General Defines ------ */
84 /* flags for sflag */
85 typedef enum eDrawStrokeFlags {
89  GP_DRAWDATA_ONLY3D = (1 << 1),
91  GP_DRAWDATA_ONLYV2D = (1 << 2),
93  GP_DRAWDATA_ONLYI2D = (1 << 3),
97  GP_DRAWDATA_NO_XRAY = (1 << 5),
103  GP_DRAWDATA_FILL = (1 << 8),
105 
106 /* thickness above which we should use special drawing */
107 #if 0
108 # define GP_DRAWTHICKNESS_SPECIAL 3
109 #endif
110 
111 /* conversion utility (float --> normalized unsigned byte) */
112 #define F2UB(x) (uchar)(255.0f * x)
113 
114 /* ----- Tool Buffer Drawing ------ */
115 /* helper functions to set color of buffer point */
116 
118  const float ink[4],
119  uint attr_id,
120  bool fix_strength)
121 {
122  float alpha = ink[3] * pt->strength;
123  if ((fix_strength) && (alpha >= 0.1f)) {
124  alpha = 1.0f;
125  }
127  immAttr4ub(attr_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha));
128 }
129 
130 /* ----------- Volumetric Strokes --------------- */
131 
132 /* draw a 3D stroke in "volumetric" style */
134  int totpoints,
135  short thickness,
136  const float ink[4])
137 {
143 
146  immBegin(GPU_PRIM_POINTS, totpoints);
147 
148  const bGPDspoint *pt = points;
149  for (int i = 0; i < totpoints && pt; i++, pt++) {
150  gpencil_set_point_varying_color(pt, ink, color, false);
151  /* TODO: scale based on view transform */
152  immAttr1f(size, pt->pressure * thickness);
153  /* we can adjust size in vertex shader based on view/projection! */
154  immVertex3fv(pos, &pt->x);
155  }
156 
157  immEnd();
159  GPU_program_point_size(false);
160 }
161 
162 /* ----- Existing Strokes Drawing (3D and Point) ------ */
163 
164 /* draw a given stroke in 3d (i.e. in 3d-space) */
166  short thickness,
167  const float ink[4],
168  bool cyclic)
169 {
170  bGPDspoint *points = tgpw->gps->points;
171  int totpoints = tgpw->gps->totpoints;
172 
173  const float viewport[2] = {(float)tgpw->winx, (float)tgpw->winy};
174  const float min_thickness = 0.05f;
175 
176  float fpt[3];
177 
178  /* if cyclic needs more vertex */
179  int cyclic_add = (cyclic) ? 1 : 0;
180 
182  const struct {
183  uint pos, color, thickness;
184  } attr_id = {
186  .color = GPU_vertformat_attr_add(
188  .thickness = GPU_vertformat_attr_add(format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT),
189  };
190 
192  immUniform2fv("Viewport", viewport);
193  immUniform1f("pixsize", tgpw->rv3d->pixsize);
194  float obj_scale = tgpw->ob ?
195  (tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f :
196  1.0f;
197 
198  immUniform1f("objscale", obj_scale);
199  int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
200  immUniform1i("keep_size", keep_size);
201  immUniform1f("pixfactor", tgpw->gpd->pixfactor);
202  /* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */
203  immUniform1i("xraymode", GP_XRAY_3DSPACE);
204  immUniform1i("caps_start", (int)tgpw->gps->caps[0]);
205  immUniform1i("caps_end", (int)tgpw->gps->caps[1]);
206  immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke);
207 
208  /* draw stroke curve */
209  immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
210  const bGPDspoint *pt = points;
211 
212  for (int i = 0; i < totpoints; i++, pt++) {
213  /* first point for adjacency (not drawn) */
214  if (i == 0) {
215  gpencil_set_point_varying_color(points, ink, attr_id.color, (bool)tgpw->is_fill_stroke);
216 
217  if ((cyclic) && (totpoints > 2)) {
218  immAttr1f(attr_id.thickness,
219  max_ff((points + totpoints - 1)->pressure * thickness, min_thickness));
220  mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x);
221  }
222  else {
223  immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, min_thickness));
224  mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
225  }
226  immVertex3fv(attr_id.pos, fpt);
227  }
228  /* set point */
229  gpencil_set_point_varying_color(pt, ink, attr_id.color, (bool)tgpw->is_fill_stroke);
230  immAttr1f(attr_id.thickness, max_ff(pt->pressure * thickness, min_thickness));
231  mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x);
232  immVertex3fv(attr_id.pos, fpt);
233  }
234 
235  if (cyclic && totpoints > 2) {
236  /* draw line to first point to complete the cycle */
237  immAttr1f(attr_id.thickness, max_ff(points->pressure * thickness, 1.0f));
238  mul_v3_m4v3(fpt, tgpw->diff_mat, &points->x);
239  immVertex3fv(attr_id.pos, fpt);
240 
241  /* now add adjacency point (not drawn) */
242  immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f));
243  mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x);
244  immVertex3fv(attr_id.pos, fpt);
245  }
246  /* last adjacency point (not drawn) */
247  else {
249  points + totpoints - 2, ink, attr_id.color, (bool)tgpw->is_fill_stroke);
250 
251  immAttr1f(attr_id.thickness, max_ff((points + totpoints - 2)->pressure * thickness, 1.0f));
252  mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 2)->x);
253  immVertex3fv(attr_id.pos, fpt);
254  }
255 
256  immEnd();
258 }
259 
260 /* ----- Strokes Drawing ------ */
261 
262 /* Helper for doing all the checks on whether a stroke can be drawn */
263 static bool gpencil_can_draw_stroke(const bGPDstroke *gps, const int dflag)
264 {
265  /* skip stroke if it isn't in the right display space for this drawing context */
266  /* 1) 3D Strokes */
267  if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) {
268  return false;
269  }
270  if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) {
271  return false;
272  }
273 
274  /* 2) Screen Space 2D Strokes */
275  if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) {
276  return false;
277  }
278  if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) {
279  return false;
280  }
281 
282  /* 3) Image Space (2D) */
283  if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) {
284  return false;
285  }
286  if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) {
287  return false;
288  }
289 
290  /* skip stroke if it doesn't have any valid data */
291  if ((gps->points == NULL) || (gps->totpoints < 1)) {
292  return false;
293  }
294 
295  /* stroke can be drawn */
296  return true;
297 }
298 
299 /* draw a set of strokes */
300 static void gpencil_draw_strokes(tGPDdraw *tgpw)
301 {
302  float tcolor[4];
303  short sthickness;
304  float ink[4];
305  const bool is_unique = (tgpw->gps != NULL);
306  const bool use_mat = (tgpw->gpd->mat != NULL);
307 
309 
310  /* Do not write to depth (avoid self-occlusion). */
311  bool prev_depth_mask = GPU_depth_mask_get();
312  GPU_depth_mask(false);
313 
314  bGPDstroke *gps_init = (tgpw->gps) ? tgpw->gps : tgpw->t_gpf->strokes.first;
315 
316  for (bGPDstroke *gps = gps_init; gps; gps = gps->next) {
317  /* check if stroke can be drawn */
318  if (gpencil_can_draw_stroke(gps, tgpw->dflag) == false) {
319  continue;
320  }
321  /* check if the color is visible */
322  Material *ma = (use_mat) ? tgpw->gpd->mat[gps->mat_nr] : BKE_material_default_gpencil();
323  MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
324 
325  if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE) ||
326  /* if onion and ghost flag do not draw*/
327  (tgpw->onion && (gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN))) {
328  continue;
329  }
330 
331  /* if disable fill, the colors with fill must be omitted too except fill boundary strokes */
332  if ((tgpw->disable_fill == 1) && (gp_style->fill_rgba[3] > 0.0f) &&
333  ((gps->flag & GP_STROKE_NOFILL) == 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW)) {
334  continue;
335  }
336 
337  /* calculate thickness */
338  sthickness = gps->thickness + tgpw->lthick;
339 
340  if (tgpw->is_fill_stroke) {
341  sthickness = (short)max_ii(1, sthickness / 2);
342  }
343 
344  if (sthickness <= 0) {
345  continue;
346  }
347 
348  /* check which stroke-drawer to use */
349  if (tgpw->dflag & GP_DRAWDATA_ONLY3D) {
350  const int no_xray = (tgpw->dflag & GP_DRAWDATA_NO_XRAY);
351 
352  if (no_xray) {
354 
355  /* first arg is normally rv3d->dist, but this isn't
356  * available here and seems to work quite well without */
357  GPU_polygon_offset(1.0f, 1.0f);
358  }
359 
360  /* 3D Stroke */
361  /* set color using material tint color and opacity */
362  if (!tgpw->onion) {
363  interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
364  tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
365  copy_v4_v4(ink, tcolor);
366  }
367  else {
368  if (tgpw->custonion) {
369  copy_v4_v4(ink, tgpw->tintcolor);
370  }
371  else {
372  ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
373  copy_v4_v4(ink, tcolor);
374  }
375  }
376 
377  /* if used for fill, set opacity to 1 */
378  if (tgpw->is_fill_stroke) {
379  if (ink[3] >= GPENCIL_ALPHA_OPACITY_THRESH) {
380  ink[3] = 1.0f;
381  }
382  }
383 
384  if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
385  /* volumetric stroke drawing */
386  if (tgpw->disable_fill != 1) {
387  gpencil_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
388  }
389  }
390  else {
391  /* 3D Lines - OpenGL primitives-based */
392  if (gps->totpoints > 1) {
393  tgpw->gps = gps;
394  gpencil_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC);
395  }
396  }
397  if (no_xray) {
399 
400  GPU_polygon_offset(0.0f, 0.0f);
401  }
402  }
403  /* if only one stroke, exit from loop */
404  if (is_unique) {
405  break;
406  }
407  }
408 
409  GPU_depth_mask(prev_depth_mask);
410  GPU_program_point_size(false);
411 }
412 
413 /* ----- General Drawing ------ */
414 
415 /* wrapper to draw strokes for filling operator */
417 {
418  gpencil_draw_strokes(tgpw);
419 }
typedef float(TangentPoint)[2]
#define GPENCIL_ALPHA_OPACITY_THRESH
Definition: BKE_gpencil.h:177
#define GPENCIL_STRENGTH_MIN
Definition: BKE_gpencil.h:178
General operations, lookup, etc. for materials.
struct Material * BKE_material_default_gpencil(void)
Definition: material.c:1839
MINLINE float max_ff(float a, float b)
MINLINE int max_ii(int a, int b)
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
MINLINE void copy_v4_v4(float r[4], const float a[4])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
unsigned int uint
Definition: BLI_sys_types.h:83
#define ARRAY_SET_ITEMS(...)
#define UNPACK3(a)
@ GP_STROKE_NOFILL
@ GP_STROKE_2DIMAGE
@ GP_STROKE_CYCLIC
@ GP_STROKE_2DSPACE
@ GP_STROKE_3DSPACE
@ GP_XRAY_3DSPACE
@ GP_DATA_STROKE_KEEPTHICKNESS
@ GP_MATERIAL_HIDE_ONIONSKIN
@ GP_MATERIAL_HIDE
@ GP_MATERIAL_FILL_SHOW
@ GP_MATERIAL_MODE_DOT
Object is a sort of wrapper for general info.
void immUniform2fv(const char *name, const float data[2])
void immAttr4ub(uint attr_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
void immUnbindProgram(void)
void immAttr1f(uint attr_id, float x)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
void immUniform1f(const char *name, float x)
GPUVertFormat * immVertexFormat(void)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
void GPU_polygon_offset(float viewdist, float dist)
Definition: gpu_matrix.cc:758
@ GPU_PRIM_LINE_STRIP_ADJ
Definition: GPU_primitive.h:45
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:35
@ GPU_SHADER_GPENCIL_STROKE
Definition: GPU_shader.h:370
@ GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR
Definition: GPU_shader.h:363
void GPU_program_point_size(bool enable)
Definition: gpu_state.cc:191
void GPU_depth_mask(bool depth)
Definition: gpu_state.cc:117
bool GPU_depth_mask_get(void)
Definition: gpu_state.cc:293
@ GPU_DEPTH_LESS_EQUAL
Definition: GPU_state.h:81
@ GPU_DEPTH_NONE
Definition: GPU_state.h:78
void GPU_depth_test(eGPUDepthTest test)
Definition: gpu_state.cc:75
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U8
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
Group RGB to Bright Vector Camera CLAMP
eDrawStrokeFlags
Definition: annotate_draw.c:73
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
static CCL_NAMESPACE_BEGIN const double alpha
eDrawStrokeFlags
Definition: drawgpencil.c:85
@ GP_DRAWDATA_ONLYV2D
Definition: drawgpencil.c:91
@ GP_DRAWDATA_ONLY3D
Definition: drawgpencil.c:89
@ GP_DRAWDATA_FILL
Definition: drawgpencil.c:103
@ GP_DRAWDATA_NO_ONIONS
Definition: drawgpencil.c:99
@ GP_DRAWDATA_IEDITHACK
Definition: drawgpencil.c:95
@ GP_DRAWDATA_NO_XRAY
Definition: drawgpencil.c:97
@ GP_DRAWDATA_ONLYI2D
Definition: drawgpencil.c:93
@ GP_DRAWDATA_VOLUMETRIC
Definition: drawgpencil.c:101
@ GP_DRAWDATA_NOSTATUS
Definition: drawgpencil.c:87
#define F2UB(x)
Definition: drawgpencil.c:112
static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic)
Definition: drawgpencil.c:165
static bool gpencil_can_draw_stroke(const bGPDstroke *gps, const int dflag)
Definition: drawgpencil.c:263
static void gpencil_draw_stroke_volumetric_3d(const bGPDspoint *points, int totpoints, short thickness, const float ink[4])
Definition: drawgpencil.c:133
static void gpencil_set_point_varying_color(const bGPDspoint *pt, const float ink[4], uint attr_id, bool fix_strength)
Definition: drawgpencil.c:117
static void gpencil_draw_strokes(tGPDdraw *tgpw)
Definition: drawgpencil.c:300
void ED_gpencil_draw_fill(tGPDdraw *tgpw)
Definition: drawgpencil.c:416
uint pos
struct @612::@615 attr_id
format
Definition: logImageCore.h:47
void * first
Definition: DNA_listBase.h:47
struct MaterialGPencilStyle * gp_style
float scale[3]
ListBase strokes
bGPDspoint * points
struct bGPDstroke * next
struct Material ** mat
short lthick
float diff_mat[4][4]
int disable_fill
struct bGPdata * gpd
bool custonion
struct bGPDstroke * gps
float opacity
struct Object * ob
bool is_fill_stroke
float tintcolor[4]
struct bGPDframe * t_gpf
struct RegionView3D * rv3d