GPencil: Changes in Fill and new 3D Cursor View Plane
[blender.git] / source / blender / editors / gpencil / gpencil_fill.c
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) 2017, Blender Foundation
17  * This is a new part of Blender
18  */
19
20 /** \file
21  * \ingroup edgpencil
22  */
23
24 #include <stdio.h>
25
26 #include "MEM_guardedalloc.h"
27
28 #include "BLI_utildefines.h"
29 #include "BLI_blenlib.h"
30 #include "BLI_math.h"
31 #include "BLI_stack.h"
32
33 #include "BLT_translation.h"
34
35 #include "DNA_brush_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_image_types.h"
38 #include "DNA_meshdata_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_windowmanager_types.h"
41
42 #include "BKE_main.h"
43 #include "BKE_brush.h"
44 #include "BKE_deform.h"
45 #include "BKE_image.h"
46 #include "BKE_gpencil.h"
47 #include "BKE_material.h"
48 #include "BKE_context.h"
49 #include "BKE_screen.h"
50 #include "BKE_paint.h"
51
52 #include "ED_gpencil.h"
53 #include "ED_screen.h"
54 #include "ED_space_api.h"
55 #include "ED_view3d.h"
56
57 #include "RNA_access.h"
58 #include "RNA_define.h"
59
60 #include "IMB_imbuf.h"
61 #include "IMB_imbuf_types.h"
62
63 #include "GPU_immediate.h"
64 #include "GPU_draw.h"
65 #include "GPU_matrix.h"
66 #include "GPU_framebuffer.h"
67 #include "GPU_state.h"
68
69 #include "UI_interface.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "DEG_depsgraph.h"
75 #include "DEG_depsgraph_query.h"
76
77 #include "gpencil_intern.h"
78
79 #define LEAK_HORZ 0
80 #define LEAK_VERT 1
81
82
83   /* Temporary fill operation data (op->customdata) */
84 typedef struct tGPDfill {
85         bContext *C;
86         struct Main *bmain;
87         struct Depsgraph *depsgraph;
88         /** window where painting originated */
89         struct wmWindow *win;
90         /** current scene from context */
91         struct Scene *scene;
92         /** current active gp object */
93         struct Object *ob;
94         /** area where painting originated */
95         struct ScrArea *sa;
96         /** region where painting originated */
97         struct RegionView3D *rv3d;
98         /** view3 where painting originated */
99         struct View3D *v3d;
100         /** region where painting originated */
101         struct ARegion *ar;
102         /** current GP datablock */
103         struct bGPdata *gpd;
104         /** current material */
105         struct Material *mat;
106         /** layer */
107         struct bGPDlayer *gpl;
108         /** frame */
109         struct bGPDframe *gpf;
110
111         /** flags */
112         short flag;
113         /** avoid too fast events */
114         short oldkey;
115         /** send to back stroke */
116         bool on_back;
117
118         /** mouse fill center position */
119         int center[2];
120         /** windows width */
121         int sizex;
122         /** window height */
123         int sizey;
124         /** lock to viewport axis */
125         int lock_axis;
126
127         /** number of pixel to consider the leak is too small (x 2) */
128         short fill_leak;
129         /** factor for transparency */
130         float fill_threshold;
131         /** number of simplify steps */
132         int fill_simplylvl;
133         /** boundary limits drawing mode */
134         int fill_draw_mode;
135         /* scaling factor */
136         short fill_factor;
137
138         /** number of elements currently in cache */
139         short sbuffer_size;
140         /** temporary points */
141         void *sbuffer;
142         /** depth array for reproject */
143         float *depth_arr;
144
145         /** temp image */
146         Image *ima;
147         /** temp points data */
148         BLI_Stack *stack;
149         /** handle for drawing strokes while operator is running 3d stuff */
150         void *draw_handle_3d;
151
152         /* tmp size x */
153         int bwinx;
154         /* tmp size y */
155         int bwiny;
156         rcti brect;
157
158 } tGPDfill;
159
160
161 /* draw a given stroke using same thickness and color for all points */
162 static void gp_draw_basic_stroke(
163         tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4],
164         const bool cyclic, const float ink[4], const int flag, const float thershold)
165 {
166         bGPDspoint *points = gps->points;
167
168         Material *ma = tgpf->mat;
169         MaterialGPencilStyle *gp_style = ma->gp_style;
170
171         int totpoints = gps->totpoints;
172         float fpt[3];
173         float col[4];
174
175         copy_v4_v4(col, ink);
176
177         /* if cyclic needs more vertex */
178         int cyclic_add = (cyclic) ? 1 : 0;
179
180         GPUVertFormat *format = immVertexFormat();
181         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
182         uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
183
184         immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
185
186         /* draw stroke curve */
187         GPU_line_width(1.0f);
188         immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
189         const bGPDspoint *pt = points;
190
191         for (int i = 0; i < totpoints; i++, pt++) {
192
193                 if (flag & GP_BRUSH_FILL_HIDE) {
194                         float alpha = gp_style->stroke_rgba[3] * pt->strength;
195                         CLAMP(alpha, 0.0f, 1.0f);
196                         col[3] = alpha <= thershold ? 0.0f : 1.0f;
197                 }
198                 else {
199                         col[3] = 1.0f;
200                 }
201                 /* set point */
202                 immAttr4fv(color, col);
203                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
204                 immVertex3fv(pos, fpt);
205         }
206
207         if (cyclic && totpoints > 2) {
208                 /* draw line to first point to complete the cycle */
209                 immAttr4fv(color, col);
210                 mul_v3_m4v3(fpt, diff_mat, &points->x);
211                 immVertex3fv(pos, fpt);
212         }
213
214         immEnd();
215         immUnbindProgram();
216 }
217
218 /* loop all layers */
219 static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
220 {
221         /* duplicated: etempFlags */
222         enum {
223                 GP_DRAWFILLS_NOSTATUS = (1 << 0),   /* don't draw status info */
224                 GP_DRAWFILLS_ONLY3D = (1 << 1),   /* only draw 3d-strokes */
225         };
226
227         Object *ob = tgpf->ob;
228         bGPdata *gpd = tgpf->gpd;
229         int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
230
231         tGPDdraw tgpw;
232         tgpw.rv3d = tgpf->rv3d;
233         tgpw.depsgraph = tgpf->depsgraph;
234         tgpw.ob = ob;
235         tgpw.gpd = gpd;
236         tgpw.offsx = 0;
237         tgpw.offsy = 0;
238         tgpw.winx = tgpf->ar->winx;
239         tgpw.winy = tgpf->ar->winy;
240         tgpw.dflag = 0;
241         tgpw.disable_fill = 1;
242         tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
243         
244
245         glEnable(GL_BLEND);
246
247         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
248                 /* calculate parent position */
249                 ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
250
251                 /* do not draw layer if hidden */
252                 if (gpl->flag & GP_LAYER_HIDE)
253                         continue;
254
255                 /* if active layer and no keyframe, create a new one */
256                 if (gpl == tgpf->gpl) {
257                         if ((gpl->actframe == NULL) || (gpl->actframe->framenum != cfra_eval)) {
258                                 BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
259                         }
260                 }
261
262                 /* get frame to draw */
263                 bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
264                 if (gpf == NULL)
265                         continue;
266
267                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
268                         /* check if stroke can be drawn */
269                         if ((gps->points == NULL) || (gps->totpoints < 2)) {
270                                 continue;
271                         }
272                         /* check if the color is visible */
273                         MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
274                         if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
275                                 continue;
276                         }
277
278                         tgpw.gps = gps;
279                         tgpw.gpl = gpl;
280                         tgpw.gpf = gpf;
281                         tgpw.t_gpf = gpf;
282
283                         /* reduce thickness to avoid gaps */
284                         tgpw.is_fill_stroke = (tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ? false : true ;
285                         tgpw.lthick = gpl->line_change;
286                         tgpw.opacity = 1.0;
287                         copy_v4_v4(tgpw.tintcolor, ink);
288                         tgpw.onion = true;
289                         tgpw.custonion = true;
290
291                         bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE);
292
293                         /* normal strokes */
294                         if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
295                             (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) &&
296                                 !textured_stroke)
297                         {
298                                 ED_gp_draw_fill(&tgpw);
299                         }
300
301                         /* 3D Lines with basic shapes and invisible lines */
302                         if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
303                             (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) ||
304                                 textured_stroke)
305                         {
306                                 gp_draw_basic_stroke(
307                                         tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink,
308                                         tgpf->flag, tgpf->fill_threshold);
309                         }
310                 }
311         }
312
313         glDisable(GL_BLEND);
314 }
315
316 /* draw strokes in offscreen buffer */
317 static bool gp_render_offscreen(tGPDfill *tgpf)
318 {
319         bool is_ortho = false;
320         float winmat[4][4];
321
322         if (!tgpf->gpd) {
323                 return false;
324         }
325         
326         /* set temporary new size */
327         tgpf->bwinx = tgpf->ar->winx;
328         tgpf->bwiny = tgpf->ar->winy;
329         tgpf->brect = tgpf->ar->winrct;
330
331         /* resize ar */
332         tgpf->ar->winrct.xmin = 0;
333         tgpf->ar->winrct.ymin = 0;
334         tgpf->ar->winrct.xmax = (int)tgpf->ar->winx * tgpf->fill_factor;
335         tgpf->ar->winrct.ymax = (int)tgpf->ar->winy * tgpf->fill_factor;
336         tgpf->ar->winx = (short)abs(tgpf->ar->winrct.xmax - tgpf->ar->winrct.xmin);
337         tgpf->ar->winy = (short)abs(tgpf->ar->winrct.ymax - tgpf->ar->winrct.ymin);
338
339         /* save new size */
340         tgpf->sizex = (int)tgpf->ar->winx;
341         tgpf->sizey = (int)tgpf->ar->winy;
342
343         /* adjust center */
344         float center[2];
345         center[0] = (float)tgpf->center[0] * ((float)tgpf->ar->winx / (float)tgpf->bwinx);
346         center[1] = (float)tgpf->center[1] * ((float)tgpf->ar->winy / (float)tgpf->bwiny);
347         round_v2i_v2fl(tgpf->center, center);
348
349         char err_out[256] = "unknown";
350         GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
351         if (offscreen == NULL) {
352                 printf("GPencil - Fill - Unable to create fill buffer\n"); 
353                 return false;
354         }
355
356         GPU_offscreen_bind(offscreen, true);
357         uint flag = IB_rect | IB_rectfloat;
358         ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
359
360         rctf viewplane;
361         float clip_start, clip_end;
362
363         is_ortho = ED_view3d_viewplane_get(
364                 tgpf->depsgraph, tgpf->v3d, tgpf->rv3d, tgpf->sizex, tgpf->sizey,
365                 &viewplane, &clip_start, &clip_end, NULL);
366         if (is_ortho) {
367                 orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clip_end, clip_end);
368         }
369         else {
370                 perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clip_start, clip_end);
371         }
372
373         GPU_matrix_push_projection();
374         GPU_matrix_identity_set();
375         GPU_matrix_push();
376         GPU_matrix_identity_set();
377
378         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
379         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
380
381         ED_view3d_update_viewmat(
382                 tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar,
383                 NULL, winmat, NULL);
384         /* set for opengl */
385         GPU_matrix_projection_set(tgpf->rv3d->winmat);
386         GPU_matrix_set(tgpf->rv3d->viewmat);
387
388         /* draw strokes */
389         float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
390         gp_draw_datablock(tgpf, ink);
391
392         GPU_matrix_pop_projection();
393         GPU_matrix_pop();
394
395         /* create a image to see result of template */
396         if (ibuf->rect_float) {
397                 GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
398         }
399         else if (ibuf->rect) {
400                 GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
401         }
402         if (ibuf->rect_float && ibuf->rect) {
403                 IMB_rect_from_float(ibuf);
404         }
405
406         tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
407         tgpf->ima->id.tag |= LIB_TAG_DOIT;
408
409         BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
410
411         /* switch back to window-system-provided framebuffer */
412         GPU_offscreen_unbind(offscreen, true);
413         GPU_offscreen_free(offscreen);
414
415         return true;
416 }
417
418 /* return pixel data (rgba) at index */
419 static void get_pixel(const ImBuf *ibuf, const int idx, float r_col[4])
420 {
421         if (ibuf->rect_float) {
422                 const float *frgba = &ibuf->rect_float[idx * 4];
423                 copy_v4_v4(r_col, frgba);
424         }
425         else {
426                 /* XXX: This case probably doesn't happen, as we only write to the float buffer,
427                  * but we get compiler warnings about uninitialised vars otherwise
428                  */
429                 BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
430                 zero_v4(r_col);
431         }
432 }
433
434 /* set pixel data (rgba) at index */
435 static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
436 {
437         //BLI_assert(idx <= ibuf->x * ibuf->y);
438         if (ibuf->rect) {
439                 uint *rrect = &ibuf->rect[idx];
440                 uchar ccol[4];
441
442                 rgba_float_to_uchar(ccol, col);
443                 *rrect = *((uint *)ccol);
444         }
445
446         if (ibuf->rect_float) {
447                 float *rrectf = &ibuf->rect_float[idx * 4];
448                 copy_v4_v4(rrectf, col);
449         }
450 }
451
452 /* check if the size of the leak is narrow to determine if the stroke is closed
453  * this is used for strokes with small gaps between them to get a full fill
454  * and do not get a full screen fill.
455  *
456  * \param ibuf: Image pixel data
457  * \param maxpixel: Maximum index
458  * \param limit: Limit of pixels to analyze
459  * \param index: Index of current pixel
460  * \param type: 0-Horizontal 1-Vertical
461  */
462 static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type)
463 {
464         float rgba[4];
465         int i;
466         int pt;
467         bool t_a = false;
468         bool t_b = false;
469
470         /* Horizontal leak (check vertical pixels)
471          * X
472          * X
473          * xB7
474          * X
475          * X
476          */
477         if (type == LEAK_HORZ) {
478                 /* pixels on top */
479                 for (i = 1; i <= limit; i++) {
480                         pt = index + (ibuf->x * i);
481                         if (pt <= maxpixel) {
482                                 get_pixel(ibuf, pt, rgba);
483                                 if (rgba[0] == 1.0f) {
484                                         t_a = true;
485                                         break;
486                                 }
487                         }
488                         else {
489                                 /* edge of image*/
490                                 t_a = true;
491                                 break;
492                         }
493                 }
494                 /* pixels on bottom */
495                 for (i = 1; i <= limit; i++) {
496                         pt = index - (ibuf->x * i);
497                         if (pt >= 0) {
498                                 get_pixel(ibuf, pt, rgba);
499                                 if (rgba[0] == 1.0f) {
500                                         t_b = true;
501                                         break;
502                                 }
503                         }
504                         else {
505                                 /* edge of image*/
506                                 t_b = true;
507                                 break;
508                         }
509                 }
510         }
511
512         /* Vertical leak (check horizontal pixels)
513          *
514          * XXXxB7XX
515          */
516         if (type == LEAK_VERT) {
517                 /* get pixel range of the row */
518                 int row = index / ibuf->x;
519                 int lowpix = row * ibuf->x;
520                 int higpix = lowpix + ibuf->x - 1;
521
522                 /* pixels to right */
523                 for (i = 0; i < limit; i++) {
524                         pt = index - (limit - i);
525                         if (pt >= lowpix) {
526                                 get_pixel(ibuf, pt, rgba);
527                                 if (rgba[0] == 1.0f) {
528                                         t_a = true;
529                                         break;
530                                 }
531                         }
532                         else {
533                                 t_a = true; /* edge of image*/
534                                 break;
535                         }
536                 }
537                 /* pixels to left */
538                 for (i = 0; i < limit; i++) {
539                         pt = index + (limit - i);
540                         if (pt <= higpix) {
541                                 get_pixel(ibuf, pt, rgba);
542                                 if (rgba[0] == 1.0f) {
543                                         t_b = true;
544                                         break;
545                                 }
546                         }
547                         else {
548                                 t_b = true; /* edge of image */
549                                 break;
550                         }
551                 }
552         }
553         return (bool)(t_a && t_b);
554 }
555
556 /* Boundary fill inside strokes
557  * Fills the space created by a set of strokes using the stroke color as the boundary
558  * of the shape to fill.
559  *
560  * \param tgpf: Temporary fill data
561  */
562 static void gpencil_boundaryfill_area(tGPDfill *tgpf)
563 {
564         ImBuf *ibuf;
565         float rgba[4];
566         void *lock;
567         const float fill_col[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
568         ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
569         const int maxpixel = (ibuf->x * ibuf->y) - 1;
570
571         BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
572
573         /* calculate index of the seed point using the position of the mouse */
574         int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
575         if ((index >= 0) && (index <= maxpixel)) {
576                 BLI_stack_push(stack, &index);
577         }
578
579         /* the fill use a stack to save the pixel list instead of the common recursive
580          * 4-contact point method.
581          * The problem with recursive calls is that for big fill areas, we can get max limit
582          * of recursive calls and STACK_OVERFLOW error.
583          *
584          * The 4-contact point analyze the pixels to the left, right, bottom and top
585          *      -----------
586          *      |    X    |
587          *      |   XoX   |
588          *      |    X    |
589          *      -----------
590          */
591         while (!BLI_stack_is_empty(stack)) {
592                 int v;
593                 
594                 BLI_stack_pop(stack, &v);
595
596                 get_pixel(ibuf, v, rgba);
597
598                 if (true) { /* Was: 'rgba' */
599                         /* check if no border(red) or already filled color(green) */
600                         if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
601                                 /* fill current pixel with green */
602                                 set_pixel(ibuf, v, fill_col);
603
604                                 /* add contact pixels */
605                                 /* pixel left */
606                                 if (v - 1 >= 0) {
607                                         index = v - 1;
608                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
609                                                 BLI_stack_push(stack, &index);
610                                         }
611                                 }
612                                 /* pixel right */
613                                 if (v + 1 <= maxpixel) {
614                                         index = v + 1;
615                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
616                                                 BLI_stack_push(stack, &index);
617                                         }
618                                 }
619                                 /* pixel top */
620                                 if (v + ibuf->x <= maxpixel) {
621                                         index = v + ibuf->x;
622                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
623                                                 BLI_stack_push(stack, &index);
624                                         }
625                                 }
626                                 /* pixel bottom */
627                                 if (v - ibuf->x >= 0) {
628                                         index = v - ibuf->x;
629                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
630                                                 BLI_stack_push(stack, &index);
631                                         }
632                                 }
633                         }
634                 }
635         }
636
637         /* release ibuf */
638         if (ibuf) {
639                 BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
640         }
641
642         tgpf->ima->id.tag |= LIB_TAG_DOIT;
643         /* free temp stack data */
644         BLI_stack_free(stack);
645 }
646
647 /* clean external border of image to avoid infinite loops */
648 static void gpencil_clean_borders(tGPDfill *tgpf)
649 {
650         ImBuf *ibuf;
651         void *lock;
652         const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
653         ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
654         int idx;
655         int pixel = 0;
656
657         /* horizontal lines */
658         for (idx = 0; idx < ibuf->x; idx++) {
659                 /* bottom line */
660                 set_pixel(ibuf, idx, fill_col);
661                 /* top line */
662                 pixel = idx + (ibuf->x * (ibuf->y - 1));
663                 set_pixel(ibuf, pixel, fill_col);
664         }
665         /* vertical lines */
666         for (idx = 0; idx < ibuf->y; idx++) {
667                 /* left line */
668                 set_pixel(ibuf, ibuf->x * idx, fill_col);
669                 /* right line */
670                 pixel = ibuf->x * idx + (ibuf->x - 1);
671                 set_pixel(ibuf, pixel, fill_col);
672         }
673
674         /* release ibuf */
675         if (ibuf) {
676                 BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
677         }
678
679         tgpf->ima->id.tag |= LIB_TAG_DOIT;
680 }
681
682 /* Naive dilate
683  *
684  * Expand green areas into enclosing red areas.
685  * Using stack prevents creep when replacing colors directly.
686  * -----------
687  *  XXXXXXX
688  *  XoooooX
689  *  XXooXXX
690  *   XXXX
691  * -----------
692  */
693 static void dilate(ImBuf *ibuf)
694 {
695         BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
696         const float green[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
697         const int maxpixel = (ibuf->x * ibuf->y) - 1;
698         /* detect pixels and expand into red areas */
699         for (int v = maxpixel; v != 0; v--) {
700                 float color[4];
701                 int index;
702                 int tp = 0;
703                 int bm = 0;
704                 int lt = 0;
705                 int rt = 0;
706                 get_pixel(ibuf, v, color);
707                 if (color[1] == 1.0f) {
708                         /* pixel left */
709                         if (v - 1 >= 0) {
710                                 index = v - 1;
711                                 get_pixel(ibuf, index, color);
712                                 if (color[0] == 1.0f) {
713                                         BLI_stack_push(stack, &index);
714                                         lt = index;
715                                 }
716                         }
717                         /* pixel right */
718                         if (v + 1 <= maxpixel) {
719                                 index = v + 1;
720                                 get_pixel(ibuf, index, color);
721                                 if (color[0] == 1.0f) {
722                                         BLI_stack_push(stack, &index);
723                                         rt = index;
724                                 }
725                         }
726                         /* pixel top */
727                         if (v + ibuf->x <= maxpixel) {
728                                 index = v + ibuf->x;
729                                 get_pixel(ibuf, index, color);
730                                 if (color[0] == 1.0f) {
731                                         BLI_stack_push(stack, &index);
732                                         tp = index;
733                                 }
734                         }
735                         /* pixel bottom */
736                         if (v - ibuf->x >= 0) {
737                                 index = v - ibuf->x;
738                                 get_pixel(ibuf, index, color);
739                                 if (color[0] == 1.0f) {
740                                         BLI_stack_push(stack, &index);
741                                         bm = index;
742                                 }
743                         }
744                         /* pixel top-left */
745                         if (tp && lt) {
746                                 index = tp - 1;
747                                 get_pixel(ibuf, index, color);
748                                 if (color[0] == 1.0f) {
749                                         BLI_stack_push(stack, &index);
750                                 }
751                         }
752                         /* pixel top-right */
753                         if (tp && rt) {
754                                 index = tp + 1;
755                                 get_pixel(ibuf, index, color);
756                                 if (color[0] == 1.0f) {
757                                         BLI_stack_push(stack, &index);
758                                 }
759                         }
760                         /* pixel bottom-left */
761                         if (bm && lt) {
762                                 index = bm - 1;
763                                 get_pixel(ibuf, index, color);
764                                 if (color[0] == 1.0f) {
765                                         BLI_stack_push(stack, &index);
766                                 }
767                         }
768                         /* pixel bottom-right */
769                         if (bm && rt) {
770                                 index = bm + 1;
771                                 get_pixel(ibuf, index, color);
772                                 if (color[0] == 1.0f) {
773                                         BLI_stack_push(stack, &index);
774                                 }
775                         }
776                 }
777         }
778         /* set dilated pixels */
779         while (!BLI_stack_is_empty(stack)) {
780                 int v;
781                 BLI_stack_pop(stack, &v);
782                 set_pixel(ibuf, v, green);
783         }
784         BLI_stack_free(stack);
785 }
786
787 /* Get the outline points of a shape using Moore Neighborhood algorithm
788  *
789  * This is a Blender customized version of the general algorithm described
790  * in https://en.wikipedia.org/wiki/Moore_neighborhood
791  */
792 static void gpencil_get_outline_points(tGPDfill *tgpf)
793 {
794         ImBuf *ibuf;
795         float rgba[4];
796         void *lock;
797         int v[2];
798         int boundary_co[2];
799         int start_co[2];
800         int backtracked_co[2];
801         int current_check_co[2];
802         int prev_check_co[2];
803         int backtracked_offset[1][2] = {{0, 0}};
804         // bool boundary_found = false;
805         bool start_found = false;
806         const int NEIGHBOR_COUNT = 8;
807
808         const int offset[8][2] = {
809                 {-1, -1},
810                 {0, -1},
811                 {1, -1},
812                 {1, 0},
813                 {1, 1},
814                 {0, 1},
815                 {-1, 1},
816                 {-1, 0},
817         };
818
819         tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
820
821         ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
822         int imagesize = ibuf->x * ibuf->y;
823
824         /* dilate */
825         dilate(ibuf);
826
827         /* find the initial point to start outline analysis */
828         for (int idx = imagesize - 1; idx != 0; idx--) {
829                 get_pixel(ibuf, idx, rgba);
830                 if (rgba[1] == 1.0f) {
831                         boundary_co[0] = idx % ibuf->x;
832                         boundary_co[1] = idx / ibuf->x;
833                         copy_v2_v2_int(start_co, boundary_co);
834                         backtracked_co[0] = (idx - 1) % ibuf->x;
835                         backtracked_co[1] = (idx - 1) / ibuf->x;
836                         backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
837                         backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
838                         copy_v2_v2_int(prev_check_co, start_co);
839
840                         BLI_stack_push(tgpf->stack, &boundary_co);
841                         start_found = true;
842                         break;
843                 }
844         }
845
846         while (start_found) {
847                 int cur_back_offset = -1;
848                 for (int i = 0; i < NEIGHBOR_COUNT; i++) {
849                         if (backtracked_offset[0][0] == offset[i][0] &&
850                             backtracked_offset[0][1] == offset[i][1])
851                         {
852                                 /* Finding the bracktracked pixel offset index */
853                                 cur_back_offset = i;
854                                 break;
855                         }
856                 }
857
858                 int loop = 0;
859                 while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
860                         int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
861                         current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
862                         current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
863
864                         int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
865                         get_pixel(ibuf, image_idx, rgba);
866
867                         /* find next boundary pixel */
868                         if (rgba[1] == 1.0f) {
869                                 copy_v2_v2_int(boundary_co, current_check_co);
870                                 copy_v2_v2_int(backtracked_co, prev_check_co);
871                                 backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
872                                 backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
873
874                                 BLI_stack_push(tgpf->stack, &boundary_co);
875
876                                 break;
877                         }
878                         copy_v2_v2_int(prev_check_co, current_check_co);
879                         cur_back_offset++;
880                         loop++;
881                 }
882                 /* current pixel is equal to starting pixel */
883                 if (boundary_co[0] == start_co[0] &&
884                     boundary_co[1] == start_co[1])
885                 {
886                         BLI_stack_pop(tgpf->stack, &v);
887                         // boundary_found = true;
888                         break;
889                 }
890         }
891
892         /* release ibuf */
893         if (ibuf) {
894                 BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
895         }
896 }
897
898 /* get z-depth array to reproject on surface */
899 static void gpencil_get_depth_array(tGPDfill *tgpf)
900 {
901         tGPspoint *ptc;
902         ToolSettings *ts = tgpf->scene->toolsettings;
903         int totpoints = tgpf->sbuffer_size;
904         int i = 0;
905
906         if (totpoints == 0) {
907                 return;
908         }
909
910         /* for surface sketching, need to set the right OpenGL context stuff so that
911          * the conversions will project the values correctly...
912          */
913         if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
914                 /* need to restore the original projection settings before packing up */
915                 view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
916                 ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
917
918                 /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
919                 int depth_margin = 0;
920
921                 /* get an array of depths, far depths are blended */
922                 int mval_prev[2] = { 0 };
923                 int interp_depth = 0;
924                 int found_depth = 0;
925
926                 tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
927
928                 for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
929
930                         int mval_i[2];
931                         round_v2i_v2fl(mval_i, &ptc->x);
932
933                         if ((ED_view3d_autodist_depth(
934                                      tgpf->ar, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
935                             (i && (ED_view3d_autodist_depth_seg(
936                                            tgpf->ar, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0)))
937                         {
938                                 interp_depth = true;
939                         }
940                         else {
941                                 found_depth = true;
942                         }
943
944                         copy_v2_v2_int(mval_prev, mval_i);
945                 }
946
947                 if (found_depth == false) {
948                         /* eeh... not much we can do.. :/, ignore depth in this case */
949                         for (i = totpoints - 1; i >= 0; i--)
950                                 tgpf->depth_arr[i] = 0.9999f;
951                 }
952                 else {
953                         if (interp_depth) {
954                                 interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
955                         }
956                 }
957         }
958 }
959
960 /* create array of points using stack as source */
961 static void gpencil_points_from_stack(tGPDfill *tgpf)
962 {
963         tGPspoint *point2D;
964         int totpoints = BLI_stack_count(tgpf->stack);
965         if (totpoints == 0) {
966                 return;
967         }
968
969         tgpf->sbuffer_size = (short)totpoints;
970         tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
971
972         point2D = tgpf->sbuffer;
973         while (!BLI_stack_is_empty(tgpf->stack)) {
974                 int v[2];
975                 BLI_stack_pop(tgpf->stack, &v);
976                 copy_v2fl_v2i(&point2D->x, v);
977                 /* shift points to center of pixel */
978                 add_v2_fl(&point2D->x, 0.5f);
979                 point2D->pressure = 1.0f;
980                 point2D->strength = 1.0f;
981                 point2D->time = 0.0f;
982                 point2D++;
983         }
984 }
985
986 /* create a grease pencil stroke using points in buffer */
987 static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
988 {
989         const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
990
991         ToolSettings *ts = tgpf->scene->toolsettings;
992         const char *align_flag = &ts->gpencil_v3d_align;
993         const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
994         const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
995                 (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth);
996         Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
997         if (brush == NULL) {
998                 return;
999         }
1000
1001         bGPDspoint *pt;
1002         MDeformVert *dvert = NULL;
1003         tGPspoint *point2D;
1004
1005         if (tgpf->sbuffer_size == 0) {
1006                 return;
1007         }
1008
1009         /* get frame or create a new one */
1010         tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
1011
1012         /* create new stroke */
1013         bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
1014         gps->thickness = brush->size;
1015         gps->inittime = 0.0f;
1016
1017         /* the polygon must be closed, so enabled cyclic */
1018         gps->flag |= GP_STROKE_CYCLIC;
1019         gps->flag |= GP_STROKE_3DSPACE;
1020
1021         gps->mat_nr = BKE_gpencil_get_material_index(tgpf->ob, tgpf->mat) - 1;
1022         if (gps->mat_nr < 0) {
1023                 BKE_object_material_slot_add(tgpf->bmain, tgpf->ob);
1024                 assign_material(tgpf->bmain, tgpf->ob, tgpf->mat, tgpf->ob->totcol, BKE_MAT_ASSIGN_USERPREF);
1025                 gps->mat_nr = tgpf->ob->totcol - 1;
1026         }
1027
1028         /* allocate memory for storage points */
1029         gps->totpoints = tgpf->sbuffer_size;
1030         gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
1031
1032         /* initialize triangle memory to dummy data */
1033         gps->tot_triangles = 0;
1034         gps->triangles = NULL;
1035         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
1036
1037         /* add stroke to frame */
1038         if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
1039                 BLI_addhead(&tgpf->gpf->strokes, gps);
1040         }
1041         else {
1042                 BLI_addtail(&tgpf->gpf->strokes, gps);
1043         }
1044
1045         /* add points */
1046         pt = gps->points;
1047         point2D = (tGPspoint *)tgpf->sbuffer;
1048
1049         const int def_nr = tgpf->ob->actdef - 1;
1050         const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
1051
1052         if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
1053                 BKE_gpencil_dvert_ensure(gps);
1054                 dvert = gps->dvert;
1055         }
1056
1057         for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++) {
1058                 /* convert screen-coordinates to 3D coordinates */
1059                 gp_stroke_convertcoords_tpoint(
1060                         tgpf->scene, tgpf->ar, tgpf->ob,
1061                         tgpf->gpl, point2D,
1062                         tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
1063                         &pt->x);
1064
1065                 pt->pressure = 1.0f;
1066                 pt->strength = 1.0f;
1067                 pt->time = 0.0f;
1068
1069                 if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
1070                         MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
1071                         if (dw) {
1072                                 dw->weight = ts->vgroup_weight;
1073                         }
1074
1075                         dvert++;
1076                 }
1077                 else {
1078                         if (dvert != NULL) {
1079                                 dvert->totweight = 0;
1080                                 dvert->dw = NULL;
1081                                 dvert++;
1082                         }
1083                 }
1084         }
1085
1086         /* smooth stroke */
1087         float reduce = 0.0f;
1088         float smoothfac = 1.0f;
1089         for (int r = 0; r < 1; r++) {
1090                 for (int i = 0; i < gps->totpoints; i++) {
1091                         BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
1092                 }
1093                 reduce += 0.25f;  // reduce the factor
1094         }
1095
1096         /* if axis locked, reproject to plane locked */
1097         if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
1098                 float origin[3];
1099                 ED_gp_get_drawing_reference(
1100                         tgpf->scene, tgpf->ob, tgpf->gpl,
1101                         ts->gpencil_v3d_align, origin);
1102                 ED_gp_project_stroke_to_plane(
1103                         tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin,
1104                         tgpf->lock_axis - 1);
1105         }
1106
1107         /* if parented change position relative to parent object */
1108         for (int a = 0; a < tgpf->sbuffer_size; a++) {
1109                 pt = &gps->points[a];
1110                 gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
1111         }
1112
1113         /* if camera view, reproject flat to view to avoid perspective effect */
1114         if (is_camera) {
1115                 ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps);
1116         }
1117
1118         /* simplify stroke */
1119         for (int b = 0; b < tgpf->fill_simplylvl; b++) {
1120                 BKE_gpencil_simplify_fixed(gps);
1121         }
1122 }
1123
1124 /* ----------------------- */
1125 /* Drawing                 */
1126 /* Helper: Draw status message while the user is running the operator */
1127 static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf))
1128 {
1129         const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
1130         ED_workspace_status_text(C, status_str);
1131 }
1132
1133 /* draw boundary lines to see fill limits */
1134 static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgpf)
1135 {
1136         if (!tgpf->gpd) {
1137                 return;
1138         }
1139         const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
1140         gp_draw_datablock(tgpf, ink);
1141 }
1142
1143 /* Drawing callback for modal operator in 3d mode */
1144 static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
1145 {
1146         tGPDfill *tgpf = (tGPDfill *)arg;
1147         /* draw only in the region that originated operator. This is required for multiwindow */
1148         ARegion *ar = CTX_wm_region(C);
1149         if (ar != tgpf->ar) {
1150                 return;
1151         }
1152
1153         gpencil_draw_boundary_lines(C, tgpf);
1154 }
1155
1156 /* check if context is suitable for filling */
1157 static bool gpencil_fill_poll(bContext *C)
1158 {
1159         if (ED_operator_regionactive(C)) {
1160                 ScrArea *sa = CTX_wm_area(C);
1161                 if (sa->spacetype == SPACE_VIEW3D) {
1162                         return 1;
1163                 }
1164                 else {
1165                         CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
1166                         return 0;
1167                 }
1168         }
1169         else {
1170                 CTX_wm_operator_poll_msg_set(C, "Active region not set");
1171                 return 0;
1172         }
1173 }
1174
1175 /* Allocate memory and initialize values */
1176 static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
1177 {
1178         tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
1179
1180         /* define initial values */
1181         ToolSettings *ts = CTX_data_tool_settings(C);
1182         bGPdata *gpd = CTX_data_gpencil_data(C);
1183         Main *bmain = CTX_data_main(C);
1184
1185         /* set current scene and window info */
1186         tgpf->C = C;
1187         tgpf->bmain = CTX_data_main(C);
1188         tgpf->scene = CTX_data_scene(C);
1189         tgpf->ob = CTX_data_active_object(C);
1190         tgpf->sa = CTX_wm_area(C);
1191         tgpf->ar = CTX_wm_region(C);
1192         tgpf->rv3d = tgpf->ar->regiondata;
1193         tgpf->v3d = tgpf->sa->spacedata.first;
1194         tgpf->depsgraph = CTX_data_depsgraph(C);
1195         tgpf->win = CTX_wm_window(C);
1196
1197         /* set GP datablock */
1198         tgpf->gpd = gpd;
1199         tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
1200         if (tgpf->gpl == NULL) {
1201                 tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
1202         }
1203         tgpf->lock_axis = ts->gp_sculpt.lock_axis;
1204
1205         tgpf->oldkey = -1;
1206         tgpf->sbuffer_size = 0;
1207         tgpf->sbuffer = NULL;
1208         tgpf->depth_arr = NULL;
1209
1210         /* save filling parameters */
1211         Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
1212         tgpf->flag = brush->gpencil_settings->flag;
1213         tgpf->fill_leak = brush->gpencil_settings->fill_leak;
1214         tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
1215         tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
1216         tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
1217         tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor,8));
1218         
1219         /* get color info */
1220         Material *ma = BKE_gpencil_get_material_from_brush(brush);
1221         /* if no brush defaults, get material and color info */
1222         if ((ma == NULL) || (ma->gp_style == NULL)) {
1223                 ma = BKE_gpencil_material_ensure(bmain, tgpf->ob);
1224                 /* assign always the first material to the brush */
1225                 brush->gpencil_settings->material = give_current_material(tgpf->ob, 1);
1226         }
1227
1228         tgpf->mat = ma;
1229
1230         /* init undo */
1231         gpencil_undo_init(tgpf->gpd);
1232
1233         /* return context data for running operator */
1234         return tgpf;
1235 }
1236
1237 /* end operator */
1238 static void gpencil_fill_exit(bContext *C, wmOperator *op)
1239 {
1240         Main *bmain = CTX_data_main(C);
1241         Object *ob = CTX_data_active_object(C);
1242
1243         /* clear undo stack */
1244         gpencil_undo_finish();
1245
1246         /* restore cursor to indicate end of fill */
1247         WM_cursor_modal_restore(CTX_wm_window(C));
1248
1249         tGPDfill *tgpf = op->customdata;
1250
1251         /* don't assume that operator data exists at all */
1252         if (tgpf) {
1253                 /* clear status message area */
1254                 ED_workspace_status_text(C, NULL);
1255
1256                 MEM_SAFE_FREE(tgpf->sbuffer);
1257                 MEM_SAFE_FREE(tgpf->depth_arr);
1258
1259                 /* remove drawing handler */
1260                 if (tgpf->draw_handle_3d) {
1261                         ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
1262                 }
1263
1264                 /* delete temp image */
1265                 if (tgpf->ima) {
1266                         for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
1267                                 if (ima == tgpf->ima) {
1268                                         BLI_remlink(&bmain->images, ima);
1269                                         BKE_image_free(tgpf->ima);
1270                                         MEM_SAFE_FREE(tgpf->ima);
1271                                         break;
1272                                 }
1273                         }
1274                 }
1275
1276                 /* finally, free memory used by temp data */
1277                 MEM_freeN(tgpf);
1278         }
1279
1280         /* clear pointer */
1281         op->customdata = NULL;
1282
1283         /* drawing batch cache is dirty now */
1284         if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
1285                 bGPdata *gpd2 = ob->data;
1286                 DEG_id_tag_update(&gpd2->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1287                 gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
1288         }
1289
1290         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1291 }
1292
1293 static void gpencil_fill_cancel(bContext *C, wmOperator *op)
1294 {
1295         /* this is just a wrapper around exit() */
1296         gpencil_fill_exit(C, op);
1297 }
1298
1299 /* Init: Allocate memory and set init values */
1300 static int gpencil_fill_init(bContext *C, wmOperator *op)
1301 {
1302         tGPDfill *tgpf;
1303         /* cannot paint in locked layer */
1304         bGPdata *gpd = CTX_data_gpencil_data(C);
1305         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
1306         if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
1307                 return 0;
1308         }
1309
1310         /* check context */
1311         tgpf = op->customdata = gp_session_init_fill(C, op);
1312         if (tgpf == NULL) {
1313                 /* something wasn't set correctly in context */
1314                 gpencil_fill_exit(C, op);
1315                 return 0;
1316         }
1317
1318         /* everything is now setup ok */
1319         return 1;
1320 }
1321
1322 /* start of interactive part of operator */
1323 static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1324 {
1325         tGPDfill *tgpf = NULL;
1326
1327         /* try to initialize context data needed */
1328         if (!gpencil_fill_init(C, op)) {
1329                 gpencil_fill_exit(C, op);
1330                 if (op->customdata)
1331                         MEM_freeN(op->customdata);
1332                 return OPERATOR_CANCELLED;
1333         }
1334         else {
1335                 tgpf = op->customdata;
1336         }
1337
1338         /* Enable custom drawing handlers to show help lines */
1339         if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
1340                 tgpf->draw_handle_3d = ED_region_draw_cb_activate(tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
1341         }
1342
1343         WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
1344
1345         gpencil_fill_status_indicators(C, tgpf);
1346
1347         DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1348         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1349
1350         /* add a modal handler for this operator*/
1351         WM_event_add_modal_handler(C, op);
1352
1353         return OPERATOR_RUNNING_MODAL;
1354 }
1355
1356 /* events handling during interactive part of operator */
1357 static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
1358 {
1359         tGPDfill *tgpf = op->customdata;
1360
1361         int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
1362
1363         switch (event->type) {
1364                 case ESCKEY:
1365                 case RIGHTMOUSE:
1366                         estate = OPERATOR_CANCELLED;
1367                         break;
1368                 case LEFTMOUSE:
1369                         tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
1370                         /* first time the event is not enabled to show help lines */
1371                         if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
1372                                 ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
1373                                 if (ar) {
1374                                         bool in_bounds = false;
1375
1376                                         /* Perform bounds check */
1377                                         in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
1378
1379                                         if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
1380
1381                                                 /* TODO GPXX: Verify the mouse click is right for any window size */
1382                                                 tgpf->center[0] = event->mval[0];
1383                                                 tgpf->center[1] = event->mval[1];
1384
1385                                                 /* render screen to temp image */
1386                                                 if ( gp_render_offscreen(tgpf) ) {
1387
1388                                                         /* apply boundary fill */
1389                                                         gpencil_boundaryfill_area(tgpf);
1390
1391                                                         /* clean borders to avoid infinite loops */
1392                                                         gpencil_clean_borders(tgpf);
1393
1394                                                         /* analyze outline */
1395                                                         gpencil_get_outline_points(tgpf);
1396
1397                                                         /* create array of points from stack */
1398                                                         gpencil_points_from_stack(tgpf);
1399
1400                                                         /* create z-depth array for reproject */
1401                                                         gpencil_get_depth_array(tgpf);
1402
1403                                                         /* create stroke and reproject */
1404                                                         gpencil_stroke_from_buffer(tgpf);
1405
1406                                                 }
1407
1408                                                 /* restore size */
1409                                                 tgpf->ar->winx = (short)tgpf->bwinx;
1410                                                 tgpf->ar->winy = (short)tgpf->bwiny;
1411                                                 tgpf->ar->winrct = tgpf->brect;
1412
1413                                                 /* free temp stack data */
1414                                                 if (tgpf->stack) {
1415                                                         BLI_stack_free(tgpf->stack);
1416                                                 }
1417
1418                                                 /* push undo data */
1419                                                 gpencil_undo_push(tgpf->gpd);
1420
1421                                                 estate = OPERATOR_FINISHED;
1422                                         }
1423                                         else {
1424                                                 estate = OPERATOR_CANCELLED;
1425                                         }
1426                                 }
1427                                 else {
1428                                         estate = OPERATOR_CANCELLED;
1429                                 }
1430                         }
1431                         tgpf->oldkey = event->type;
1432                         break;
1433         }
1434         /* process last operations before exiting */
1435         switch (estate) {
1436                 case OPERATOR_FINISHED:
1437                         gpencil_fill_exit(C, op);
1438                         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1439                         break;
1440
1441                 case OPERATOR_CANCELLED:
1442                         gpencil_fill_exit(C, op);
1443                         break;
1444
1445                 case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
1446                         break;
1447         }
1448
1449         /* return status code */
1450         return estate;
1451 }
1452
1453 void GPENCIL_OT_fill(wmOperatorType *ot)
1454 {
1455         PropertyRNA *prop;
1456
1457         /* identifiers */
1458         ot->name = "Grease Pencil Fill";
1459         ot->idname = "GPENCIL_OT_fill";
1460         ot->description = "Fill with color the shape formed by strokes";
1461
1462         /* api callbacks */
1463         ot->invoke = gpencil_fill_invoke;
1464         ot->modal = gpencil_fill_modal;
1465         ot->poll = gpencil_fill_poll;
1466         ot->cancel = gpencil_fill_cancel;
1467
1468         /* flags */
1469         ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
1470
1471         prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
1472         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1473 }