Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_fill.c')
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c2485
1 files changed, 1249 insertions, 1236 deletions
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 76d15557055..8d3137ed3db 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -79,373 +79,393 @@
#define LEAK_HORZ 0
#define LEAK_VERT 1
-
- /* Temporary fill operation data (op->customdata) */
+/* Temporary fill operation data (op->customdata) */
typedef struct tGPDfill {
- bContext *C;
- struct Main *bmain;
- struct Depsgraph *depsgraph;
- /** window where painting originated */
- struct wmWindow *win;
- /** current scene from context */
- struct Scene *scene;
- /** current active gp object */
- struct Object *ob;
- /** area where painting originated */
- struct ScrArea *sa;
- /** region where painting originated */
- struct RegionView3D *rv3d;
- /** view3 where painting originated */
- struct View3D *v3d;
- /** region where painting originated */
- struct ARegion *ar;
- /** current GP datablock */
- struct bGPdata *gpd;
- /** current material */
- struct Material *mat;
- /** layer */
- struct bGPDlayer *gpl;
- /** frame */
- struct bGPDframe *gpf;
-
- /** flags */
- short flag;
- /** avoid too fast events */
- short oldkey;
- /** send to back stroke */
- bool on_back;
-
- /** mouse fill center position */
- int center[2];
- /** windows width */
- int sizex;
- /** window height */
- int sizey;
- /** lock to viewport axis */
- int lock_axis;
-
- /** number of pixel to consider the leak is too small (x 2) */
- short fill_leak;
- /** factor for transparency */
- float fill_threshold;
- /** number of simplify steps */
- int fill_simplylvl;
- /** boundary limits drawing mode */
- int fill_draw_mode;
- /* scaling factor */
- short fill_factor;
-
- /** number of elements currently in cache */
- short sbuffer_size;
- /** temporary points */
- void *sbuffer;
- /** depth array for reproject */
- float *depth_arr;
-
- /** temp image */
- Image *ima;
- /** temp points data */
- BLI_Stack *stack;
- /** handle for drawing strokes while operator is running 3d stuff */
- void *draw_handle_3d;
-
- /* tmp size x */
- int bwinx;
- /* tmp size y */
- int bwiny;
- rcti brect;
+ bContext *C;
+ struct Main *bmain;
+ struct Depsgraph *depsgraph;
+ /** window where painting originated */
+ struct wmWindow *win;
+ /** current scene from context */
+ struct Scene *scene;
+ /** current active gp object */
+ struct Object *ob;
+ /** area where painting originated */
+ struct ScrArea *sa;
+ /** region where painting originated */
+ struct RegionView3D *rv3d;
+ /** view3 where painting originated */
+ struct View3D *v3d;
+ /** region where painting originated */
+ struct ARegion *ar;
+ /** current GP datablock */
+ struct bGPdata *gpd;
+ /** current material */
+ struct Material *mat;
+ /** layer */
+ struct bGPDlayer *gpl;
+ /** frame */
+ struct bGPDframe *gpf;
+
+ /** flags */
+ short flag;
+ /** avoid too fast events */
+ short oldkey;
+ /** send to back stroke */
+ bool on_back;
+
+ /** mouse fill center position */
+ int center[2];
+ /** windows width */
+ int sizex;
+ /** window height */
+ int sizey;
+ /** lock to viewport axis */
+ int lock_axis;
+
+ /** number of pixel to consider the leak is too small (x 2) */
+ short fill_leak;
+ /** factor for transparency */
+ float fill_threshold;
+ /** number of simplify steps */
+ int fill_simplylvl;
+ /** boundary limits drawing mode */
+ int fill_draw_mode;
+ /* scaling factor */
+ short fill_factor;
+
+ /** number of elements currently in cache */
+ short sbuffer_size;
+ /** temporary points */
+ void *sbuffer;
+ /** depth array for reproject */
+ float *depth_arr;
+
+ /** temp image */
+ Image *ima;
+ /** temp points data */
+ BLI_Stack *stack;
+ /** handle for drawing strokes while operator is running 3d stuff */
+ void *draw_handle_3d;
+
+ /* tmp size x */
+ int bwinx;
+ /* tmp size y */
+ int bwiny;
+ rcti brect;
} tGPDfill;
-
/* draw a given stroke using same thickness and color for all points */
-static void gp_draw_basic_stroke(
- tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4],
- const bool cyclic, const float ink[4], const int flag, const float thershold)
+static void gp_draw_basic_stroke(tGPDfill *tgpf,
+ bGPDstroke *gps,
+ const float diff_mat[4][4],
+ const bool cyclic,
+ const float ink[4],
+ const int flag,
+ const float thershold)
{
- bGPDspoint *points = gps->points;
-
- Material *ma = tgpf->mat;
- MaterialGPencilStyle *gp_style = ma->gp_style;
-
- int totpoints = gps->totpoints;
- float fpt[3];
- float col[4];
-
- copy_v4_v4(col, ink);
-
- /* if cyclic needs more vertex */
- int cyclic_add = (cyclic) ? 1 : 0;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
-
- /* draw stroke curve */
- GPU_line_width(1.0f);
- immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
- const bGPDspoint *pt = points;
-
- for (int i = 0; i < totpoints; i++, pt++) {
-
- if (flag & GP_BRUSH_FILL_HIDE) {
- float alpha = gp_style->stroke_rgba[3] * pt->strength;
- CLAMP(alpha, 0.0f, 1.0f);
- col[3] = alpha <= thershold ? 0.0f : 1.0f;
- }
- else {
- col[3] = 1.0f;
- }
- /* set point */
- immAttr4fv(color, col);
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- immVertex3fv(pos, fpt);
- }
-
- if (cyclic && totpoints > 2) {
- /* draw line to first point to complete the cycle */
- immAttr4fv(color, col);
- mul_v3_m4v3(fpt, diff_mat, &points->x);
- immVertex3fv(pos, fpt);
- }
-
- immEnd();
- immUnbindProgram();
+ bGPDspoint *points = gps->points;
+
+ Material *ma = tgpf->mat;
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+
+ int totpoints = gps->totpoints;
+ float fpt[3];
+ float col[4];
+
+ copy_v4_v4(col, ink);
+
+ /* if cyclic needs more vertex */
+ int cyclic_add = (cyclic) ? 1 : 0;
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
+
+ /* draw stroke curve */
+ GPU_line_width(1.0f);
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
+ const bGPDspoint *pt = points;
+
+ for (int i = 0; i < totpoints; i++, pt++) {
+
+ if (flag & GP_BRUSH_FILL_HIDE) {
+ float alpha = gp_style->stroke_rgba[3] * pt->strength;
+ CLAMP(alpha, 0.0f, 1.0f);
+ col[3] = alpha <= thershold ? 0.0f : 1.0f;
+ }
+ else {
+ col[3] = 1.0f;
+ }
+ /* set point */
+ immAttr4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ if (cyclic && totpoints > 2) {
+ /* draw line to first point to complete the cycle */
+ immAttr4fv(color, col);
+ mul_v3_m4v3(fpt, diff_mat, &points->x);
+ immVertex3fv(pos, fpt);
+ }
+
+ immEnd();
+ immUnbindProgram();
}
/* loop all layers */
static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
{
- /* duplicated: etempFlags */
- enum {
- GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */
- GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */
- };
-
- Object *ob = tgpf->ob;
- bGPdata *gpd = tgpf->gpd;
- int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
-
- tGPDdraw tgpw;
- tgpw.rv3d = tgpf->rv3d;
- tgpw.depsgraph = tgpf->depsgraph;
- tgpw.ob = ob;
- tgpw.gpd = gpd;
- tgpw.offsx = 0;
- tgpw.offsy = 0;
- tgpw.winx = tgpf->ar->winx;
- tgpw.winy = tgpf->ar->winy;
- tgpw.dflag = 0;
- tgpw.disable_fill = 1;
- tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
-
- GPU_blend(true);
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* calculate parent position */
- ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
-
- /* do not draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE)
- continue;
-
- /* if active layer and no keyframe, create a new one */
- if (gpl == tgpf->gpl) {
- if ((gpl->actframe == NULL) || (gpl->actframe->framenum != cfra_eval)) {
- BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
- }
- }
-
- /* get frame to draw */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
- if (gpf == NULL)
- continue;
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* check if stroke can be drawn */
- if ((gps->points == NULL) || (gps->totpoints < 2)) {
- continue;
- }
- /* check if the color is visible */
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
- if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
- continue;
- }
-
- tgpw.gps = gps;
- tgpw.gpl = gpl;
- tgpw.gpf = gpf;
- tgpw.t_gpf = gpf;
-
- /* reduce thickness to avoid gaps */
- tgpw.is_fill_stroke = (tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ? false : true ;
- tgpw.lthick = gpl->line_change;
- tgpw.opacity = 1.0;
- copy_v4_v4(tgpw.tintcolor, ink);
- tgpw.onion = true;
- tgpw.custonion = true;
-
- bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE);
-
- /* normal strokes */
- if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) &&
- !textured_stroke)
- {
- ED_gp_draw_fill(&tgpw);
- }
-
- /* 3D Lines with basic shapes and invisible lines */
- if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) ||
- textured_stroke)
- {
- gp_draw_basic_stroke(
- tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink,
- tgpf->flag, tgpf->fill_threshold);
- }
- }
- }
-
- GPU_blend(false);
+ /* duplicated: etempFlags */
+ enum {
+ GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */
+ GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */
+ };
+
+ Object *ob = tgpf->ob;
+ bGPdata *gpd = tgpf->gpd;
+ int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ tGPDdraw tgpw;
+ tgpw.rv3d = tgpf->rv3d;
+ tgpw.depsgraph = tgpf->depsgraph;
+ tgpw.ob = ob;
+ tgpw.gpd = gpd;
+ tgpw.offsx = 0;
+ tgpw.offsy = 0;
+ tgpw.winx = tgpf->ar->winx;
+ tgpw.winy = tgpf->ar->winy;
+ tgpw.dflag = 0;
+ tgpw.disable_fill = 1;
+ tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
+
+ GPU_blend(true);
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
+
+ /* do not draw layer if hidden */
+ if (gpl->flag & GP_LAYER_HIDE)
+ continue;
+
+ /* if active layer and no keyframe, create a new one */
+ if (gpl == tgpf->gpl) {
+ if ((gpl->actframe == NULL) || (gpl->actframe->framenum != cfra_eval)) {
+ BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ }
+ }
+
+ /* get frame to draw */
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* check if stroke can be drawn */
+ if ((gps->points == NULL) || (gps->totpoints < 2)) {
+ continue;
+ }
+ /* check if the color is visible */
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
+ continue;
+ }
+
+ tgpw.gps = gps;
+ tgpw.gpl = gpl;
+ tgpw.gpf = gpf;
+ tgpw.t_gpf = gpf;
+
+ /* reduce thickness to avoid gaps */
+ tgpw.is_fill_stroke = (tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ? false : true;
+ tgpw.lthick = gpl->line_change;
+ tgpw.opacity = 1.0;
+ copy_v4_v4(tgpw.tintcolor, ink);
+ tgpw.onion = true;
+ tgpw.custonion = true;
+
+ bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE);
+
+ /* normal strokes */
+ if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) &&
+ !textured_stroke) {
+ ED_gp_draw_fill(&tgpw);
+ }
+
+ /* 3D Lines with basic shapes and invisible lines */
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) || textured_stroke) {
+ gp_draw_basic_stroke(tgpf,
+ gps,
+ tgpw.diff_mat,
+ gps->flag & GP_STROKE_CYCLIC,
+ ink,
+ tgpf->flag,
+ tgpf->fill_threshold);
+ }
+ }
+ }
+
+ GPU_blend(false);
}
/* draw strokes in offscreen buffer */
static bool gp_render_offscreen(tGPDfill *tgpf)
{
- bool is_ortho = false;
- float winmat[4][4];
-
- if (!tgpf->gpd) {
- return false;
- }
-
- /* set temporary new size */
- tgpf->bwinx = tgpf->ar->winx;
- tgpf->bwiny = tgpf->ar->winy;
- tgpf->brect = tgpf->ar->winrct;
-
- /* resize ar */
- tgpf->ar->winrct.xmin = 0;
- tgpf->ar->winrct.ymin = 0;
- tgpf->ar->winrct.xmax = (int)tgpf->ar->winx * tgpf->fill_factor;
- tgpf->ar->winrct.ymax = (int)tgpf->ar->winy * tgpf->fill_factor;
- tgpf->ar->winx = (short)abs(tgpf->ar->winrct.xmax - tgpf->ar->winrct.xmin);
- tgpf->ar->winy = (short)abs(tgpf->ar->winrct.ymax - tgpf->ar->winrct.ymin);
-
- /* save new size */
- tgpf->sizex = (int)tgpf->ar->winx;
- tgpf->sizey = (int)tgpf->ar->winy;
-
- /* adjust center */
- float center[2];
- center[0] = (float)tgpf->center[0] * ((float)tgpf->ar->winx / (float)tgpf->bwinx);
- center[1] = (float)tgpf->center[1] * ((float)tgpf->ar->winy / (float)tgpf->bwiny);
- round_v2i_v2fl(tgpf->center, center);
-
- char err_out[256] = "unknown";
- GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
- if (offscreen == NULL) {
- printf("GPencil - Fill - Unable to create fill buffer\n");
- return false;
- }
-
- GPU_offscreen_bind(offscreen, true);
- uint flag = IB_rect | IB_rectfloat;
- ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
-
- rctf viewplane;
- float clip_start, clip_end;
-
- is_ortho = ED_view3d_viewplane_get(
- tgpf->depsgraph, tgpf->v3d, tgpf->rv3d, tgpf->sizex, tgpf->sizey,
- &viewplane, &clip_start, &clip_end, NULL);
- if (is_ortho) {
- orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clip_end, clip_end);
- }
- else {
- perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clip_start, clip_end);
- }
-
- GPU_matrix_push_projection();
- GPU_matrix_identity_set();
- GPU_matrix_push();
- GPU_matrix_identity_set();
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- ED_view3d_update_viewmat(
- tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar,
- NULL, winmat, NULL);
- /* set for opengl */
- GPU_matrix_projection_set(tgpf->rv3d->winmat);
- GPU_matrix_set(tgpf->rv3d->viewmat);
-
- /* draw strokes */
- float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
- gp_draw_datablock(tgpf, ink);
-
- GPU_matrix_pop_projection();
- GPU_matrix_pop();
-
- /* create a image to see result of template */
- if (ibuf->rect_float) {
- GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
- }
- else if (ibuf->rect) {
- GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
- }
- if (ibuf->rect_float && ibuf->rect) {
- IMB_rect_from_float(ibuf);
- }
-
- tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
- tgpf->ima->id.tag |= LIB_TAG_DOIT;
-
- BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
-
- /* switch back to window-system-provided framebuffer */
- GPU_offscreen_unbind(offscreen, true);
- GPU_offscreen_free(offscreen);
-
- return true;
+ bool is_ortho = false;
+ float winmat[4][4];
+
+ if (!tgpf->gpd) {
+ return false;
+ }
+
+ /* set temporary new size */
+ tgpf->bwinx = tgpf->ar->winx;
+ tgpf->bwiny = tgpf->ar->winy;
+ tgpf->brect = tgpf->ar->winrct;
+
+ /* resize ar */
+ tgpf->ar->winrct.xmin = 0;
+ tgpf->ar->winrct.ymin = 0;
+ tgpf->ar->winrct.xmax = (int)tgpf->ar->winx * tgpf->fill_factor;
+ tgpf->ar->winrct.ymax = (int)tgpf->ar->winy * tgpf->fill_factor;
+ tgpf->ar->winx = (short)abs(tgpf->ar->winrct.xmax - tgpf->ar->winrct.xmin);
+ tgpf->ar->winy = (short)abs(tgpf->ar->winrct.ymax - tgpf->ar->winrct.ymin);
+
+ /* save new size */
+ tgpf->sizex = (int)tgpf->ar->winx;
+ tgpf->sizey = (int)tgpf->ar->winy;
+
+ /* adjust center */
+ float center[2];
+ center[0] = (float)tgpf->center[0] * ((float)tgpf->ar->winx / (float)tgpf->bwinx);
+ center[1] = (float)tgpf->center[1] * ((float)tgpf->ar->winy / (float)tgpf->bwiny);
+ round_v2i_v2fl(tgpf->center, center);
+
+ char err_out[256] = "unknown";
+ GPUOffScreen *offscreen = GPU_offscreen_create(
+ tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
+ if (offscreen == NULL) {
+ printf("GPencil - Fill - Unable to create fill buffer\n");
+ return false;
+ }
+
+ GPU_offscreen_bind(offscreen, true);
+ uint flag = IB_rect | IB_rectfloat;
+ ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
+
+ rctf viewplane;
+ float clip_start, clip_end;
+
+ is_ortho = ED_view3d_viewplane_get(tgpf->depsgraph,
+ tgpf->v3d,
+ tgpf->rv3d,
+ tgpf->sizex,
+ tgpf->sizey,
+ &viewplane,
+ &clip_start,
+ &clip_end,
+ NULL);
+ if (is_ortho) {
+ orthographic_m4(winmat,
+ viewplane.xmin,
+ viewplane.xmax,
+ viewplane.ymin,
+ viewplane.ymax,
+ -clip_end,
+ clip_end);
+ }
+ else {
+ perspective_m4(winmat,
+ viewplane.xmin,
+ viewplane.xmax,
+ viewplane.ymin,
+ viewplane.ymax,
+ clip_start,
+ clip_end);
+ }
+
+ GPU_matrix_push_projection();
+ GPU_matrix_identity_set();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ED_view3d_update_viewmat(tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, NULL, winmat, NULL);
+ /* set for opengl */
+ GPU_matrix_projection_set(tgpf->rv3d->winmat);
+ GPU_matrix_set(tgpf->rv3d->viewmat);
+
+ /* draw strokes */
+ float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ gp_draw_datablock(tgpf, ink);
+
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+
+ /* create a image to see result of template */
+ if (ibuf->rect_float) {
+ GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
+ }
+ else if (ibuf->rect) {
+ GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
+ if (ibuf->rect_float && ibuf->rect) {
+ IMB_rect_from_float(ibuf);
+ }
+
+ tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+
+ BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
+
+ /* switch back to window-system-provided framebuffer */
+ GPU_offscreen_unbind(offscreen, true);
+ GPU_offscreen_free(offscreen);
+
+ return true;
}
/* return pixel data (rgba) at index */
static void get_pixel(const ImBuf *ibuf, const int idx, float r_col[4])
{
- if (ibuf->rect_float) {
- const float *frgba = &ibuf->rect_float[idx * 4];
- copy_v4_v4(r_col, frgba);
- }
- else {
- /* XXX: This case probably doesn't happen, as we only write to the float buffer,
- * but we get compiler warnings about uninitialised vars otherwise
- */
- BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
- zero_v4(r_col);
- }
+ if (ibuf->rect_float) {
+ const float *frgba = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(r_col, frgba);
+ }
+ else {
+ /* XXX: This case probably doesn't happen, as we only write to the float buffer,
+ * but we get compiler warnings about uninitialised vars otherwise
+ */
+ BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
+ zero_v4(r_col);
+ }
}
/* set pixel data (rgba) at index */
static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
{
- //BLI_assert(idx <= ibuf->x * ibuf->y);
- if (ibuf->rect) {
- uint *rrect = &ibuf->rect[idx];
- uchar ccol[4];
-
- rgba_float_to_uchar(ccol, col);
- *rrect = *((uint *)ccol);
- }
-
- if (ibuf->rect_float) {
- float *rrectf = &ibuf->rect_float[idx * 4];
- copy_v4_v4(rrectf, col);
- }
+ //BLI_assert(idx <= ibuf->x * ibuf->y);
+ if (ibuf->rect) {
+ uint *rrect = &ibuf->rect[idx];
+ uchar ccol[4];
+
+ rgba_float_to_uchar(ccol, col);
+ *rrect = *((uint *)ccol);
+ }
+
+ if (ibuf->rect_float) {
+ float *rrectf = &ibuf->rect_float[idx * 4];
+ copy_v4_v4(rrectf, col);
+ }
}
/* check if the size of the leak is narrow to determine if the stroke is closed
@@ -460,96 +480,96 @@ static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
*/
static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type)
{
- float rgba[4];
- int i;
- int pt;
- bool t_a = false;
- bool t_b = false;
-
- /* Horizontal leak (check vertical pixels)
- * X
- * X
- * xB7
- * X
- * X
- */
- if (type == LEAK_HORZ) {
- /* pixels on top */
- for (i = 1; i <= limit; i++) {
- pt = index + (ibuf->x * i);
- if (pt <= maxpixel) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_a = true;
- break;
- }
- }
- else {
- /* edge of image*/
- t_a = true;
- break;
- }
- }
- /* pixels on bottom */
- for (i = 1; i <= limit; i++) {
- pt = index - (ibuf->x * i);
- if (pt >= 0) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_b = true;
- break;
- }
- }
- else {
- /* edge of image*/
- t_b = true;
- break;
- }
- }
- }
-
- /* Vertical leak (check horizontal pixels)
- *
- * XXXxB7XX
- */
- if (type == LEAK_VERT) {
- /* get pixel range of the row */
- int row = index / ibuf->x;
- int lowpix = row * ibuf->x;
- int higpix = lowpix + ibuf->x - 1;
-
- /* pixels to right */
- for (i = 0; i < limit; i++) {
- pt = index - (limit - i);
- if (pt >= lowpix) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_a = true;
- break;
- }
- }
- else {
- t_a = true; /* edge of image*/
- break;
- }
- }
- /* pixels to left */
- for (i = 0; i < limit; i++) {
- pt = index + (limit - i);
- if (pt <= higpix) {
- get_pixel(ibuf, pt, rgba);
- if (rgba[0] == 1.0f) {
- t_b = true;
- break;
- }
- }
- else {
- t_b = true; /* edge of image */
- break;
- }
- }
- }
- return (bool)(t_a && t_b);
+ float rgba[4];
+ int i;
+ int pt;
+ bool t_a = false;
+ bool t_b = false;
+
+ /* Horizontal leak (check vertical pixels)
+ * X
+ * X
+ * xB7
+ * X
+ * X
+ */
+ if (type == LEAK_HORZ) {
+ /* pixels on top */
+ for (i = 1; i <= limit; i++) {
+ pt = index + (ibuf->x * i);
+ if (pt <= maxpixel) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ /* edge of image*/
+ t_a = true;
+ break;
+ }
+ }
+ /* pixels on bottom */
+ for (i = 1; i <= limit; i++) {
+ pt = index - (ibuf->x * i);
+ if (pt >= 0) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ /* edge of image*/
+ t_b = true;
+ break;
+ }
+ }
+ }
+
+ /* Vertical leak (check horizontal pixels)
+ *
+ * XXXxB7XX
+ */
+ if (type == LEAK_VERT) {
+ /* get pixel range of the row */
+ int row = index / ibuf->x;
+ int lowpix = row * ibuf->x;
+ int higpix = lowpix + ibuf->x - 1;
+
+ /* pixels to right */
+ for (i = 0; i < limit; i++) {
+ pt = index - (limit - i);
+ if (pt >= lowpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_a = true;
+ break;
+ }
+ }
+ else {
+ t_a = true; /* edge of image*/
+ break;
+ }
+ }
+ /* pixels to left */
+ for (i = 0; i < limit; i++) {
+ pt = index + (limit - i);
+ if (pt <= higpix) {
+ get_pixel(ibuf, pt, rgba);
+ if (rgba[0] == 1.0f) {
+ t_b = true;
+ break;
+ }
+ }
+ else {
+ t_b = true; /* edge of image */
+ break;
+ }
+ }
+ }
+ return (bool)(t_a && t_b);
}
/* Boundary fill inside strokes
@@ -560,122 +580,122 @@ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index
*/
static void gpencil_boundaryfill_area(tGPDfill *tgpf)
{
- ImBuf *ibuf;
- float rgba[4];
- void *lock;
- const float fill_col[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
- ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
- const int maxpixel = (ibuf->x * ibuf->y) - 1;
-
- BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
-
- /* calculate index of the seed point using the position of the mouse */
- int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
- if ((index >= 0) && (index <= maxpixel)) {
- BLI_stack_push(stack, &index);
- }
-
- /* the fill use a stack to save the pixel list instead of the common recursive
- * 4-contact point method.
- * The problem with recursive calls is that for big fill areas, we can get max limit
- * of recursive calls and STACK_OVERFLOW error.
- *
- * The 4-contact point analyze the pixels to the left, right, bottom and top
- * -----------
- * | X |
- * | XoX |
- * | X |
- * -----------
- */
- while (!BLI_stack_is_empty(stack)) {
- int v;
-
- BLI_stack_pop(stack, &v);
-
- get_pixel(ibuf, v, rgba);
-
- if (true) { /* Was: 'rgba' */
- /* check if no border(red) or already filled color(green) */
- if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
- /* fill current pixel with green */
- set_pixel(ibuf, v, fill_col);
-
- /* add contact pixels */
- /* pixel left */
- if (v - 1 >= 0) {
- index = v - 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel right */
- if (v + 1 <= maxpixel) {
- index = v + 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel top */
- if (v + ibuf->x <= maxpixel) {
- index = v + ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel bottom */
- if (v - ibuf->x >= 0) {
- index = v - ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
- }
- }
- }
- }
-
- /* release ibuf */
- if (ibuf) {
- BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
- }
-
- tgpf->ima->id.tag |= LIB_TAG_DOIT;
- /* free temp stack data */
- BLI_stack_free(stack);
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ const float fill_col[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ const int maxpixel = (ibuf->x * ibuf->y) - 1;
+
+ BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
+
+ /* calculate index of the seed point using the position of the mouse */
+ int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
+ if ((index >= 0) && (index <= maxpixel)) {
+ BLI_stack_push(stack, &index);
+ }
+
+ /* the fill use a stack to save the pixel list instead of the common recursive
+ * 4-contact point method.
+ * The problem with recursive calls is that for big fill areas, we can get max limit
+ * of recursive calls and STACK_OVERFLOW error.
+ *
+ * The 4-contact point analyze the pixels to the left, right, bottom and top
+ * -----------
+ * | X |
+ * | XoX |
+ * | X |
+ * -----------
+ */
+ while (!BLI_stack_is_empty(stack)) {
+ int v;
+
+ BLI_stack_pop(stack, &v);
+
+ get_pixel(ibuf, v, rgba);
+
+ if (true) { /* Was: 'rgba' */
+ /* check if no border(red) or already filled color(green) */
+ if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
+ /* fill current pixel with green */
+ set_pixel(ibuf, v, fill_col);
+
+ /* add contact pixels */
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel right */
+ if (v + 1 <= maxpixel) {
+ index = v + 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel top */
+ if (v + ibuf->x <= maxpixel) {
+ index = v + ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom */
+ if (v - ibuf->x >= 0) {
+ index = v - ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ }
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+ /* free temp stack data */
+ BLI_stack_free(stack);
}
/* clean external border of image to avoid infinite loops */
static void gpencil_clean_borders(tGPDfill *tgpf)
{
- ImBuf *ibuf;
- void *lock;
- const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
- ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
- int idx;
- int pixel = 0;
-
- /* horizontal lines */
- for (idx = 0; idx < ibuf->x; idx++) {
- /* bottom line */
- set_pixel(ibuf, idx, fill_col);
- /* top line */
- pixel = idx + (ibuf->x * (ibuf->y - 1));
- set_pixel(ibuf, pixel, fill_col);
- }
- /* vertical lines */
- for (idx = 0; idx < ibuf->y; idx++) {
- /* left line */
- set_pixel(ibuf, ibuf->x * idx, fill_col);
- /* right line */
- pixel = ibuf->x * idx + (ibuf->x - 1);
- set_pixel(ibuf, pixel, fill_col);
- }
-
- /* release ibuf */
- if (ibuf) {
- BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
- }
-
- tgpf->ima->id.tag |= LIB_TAG_DOIT;
+ ImBuf *ibuf;
+ void *lock;
+ const float fill_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int idx;
+ int pixel = 0;
+
+ /* horizontal lines */
+ for (idx = 0; idx < ibuf->x; idx++) {
+ /* bottom line */
+ set_pixel(ibuf, idx, fill_col);
+ /* top line */
+ pixel = idx + (ibuf->x * (ibuf->y - 1));
+ set_pixel(ibuf, pixel, fill_col);
+ }
+ /* vertical lines */
+ for (idx = 0; idx < ibuf->y; idx++) {
+ /* left line */
+ set_pixel(ibuf, ibuf->x * idx, fill_col);
+ /* right line */
+ pixel = ibuf->x * idx + (ibuf->x - 1);
+ set_pixel(ibuf, pixel, fill_col);
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
}
/* Naive dilate
@@ -691,96 +711,96 @@ static void gpencil_clean_borders(tGPDfill *tgpf)
*/
static void dilate(ImBuf *ibuf)
{
- BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
- const float green[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
- const int maxpixel = (ibuf->x * ibuf->y) - 1;
- /* detect pixels and expand into red areas */
- for (int v = maxpixel; v != 0; v--) {
- float color[4];
- int index;
- int tp = 0;
- int bm = 0;
- int lt = 0;
- int rt = 0;
- get_pixel(ibuf, v, color);
- if (color[1] == 1.0f) {
- /* pixel left */
- if (v - 1 >= 0) {
- index = v - 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- lt = index;
- }
- }
- /* pixel right */
- if (v + 1 <= maxpixel) {
- index = v + 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- rt = index;
- }
- }
- /* pixel top */
- if (v + ibuf->x <= maxpixel) {
- index = v + ibuf->x;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- tp = index;
- }
- }
- /* pixel bottom */
- if (v - ibuf->x >= 0) {
- index = v - ibuf->x;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- bm = index;
- }
- }
- /* pixel top-left */
- if (tp && lt) {
- index = tp - 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel top-right */
- if (tp && rt) {
- index = tp + 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel bottom-left */
- if (bm && lt) {
- index = bm - 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- /* pixel bottom-right */
- if (bm && rt) {
- index = bm + 1;
- get_pixel(ibuf, index, color);
- if (color[0] == 1.0f) {
- BLI_stack_push(stack, &index);
- }
- }
- }
- }
- /* set dilated pixels */
- while (!BLI_stack_is_empty(stack)) {
- int v;
- BLI_stack_pop(stack, &v);
- set_pixel(ibuf, v, green);
- }
- BLI_stack_free(stack);
+ BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
+ const float green[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ const int maxpixel = (ibuf->x * ibuf->y) - 1;
+ /* detect pixels and expand into red areas */
+ for (int v = maxpixel; v != 0; v--) {
+ float color[4];
+ int index;
+ int tp = 0;
+ int bm = 0;
+ int lt = 0;
+ int rt = 0;
+ get_pixel(ibuf, v, color);
+ if (color[1] == 1.0f) {
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ lt = index;
+ }
+ }
+ /* pixel right */
+ if (v + 1 <= maxpixel) {
+ index = v + 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ rt = index;
+ }
+ }
+ /* pixel top */
+ if (v + ibuf->x <= maxpixel) {
+ index = v + ibuf->x;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ tp = index;
+ }
+ }
+ /* pixel bottom */
+ if (v - ibuf->x >= 0) {
+ index = v - ibuf->x;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ bm = index;
+ }
+ }
+ /* pixel top-left */
+ if (tp && lt) {
+ index = tp - 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel top-right */
+ if (tp && rt) {
+ index = tp + 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom-left */
+ if (bm && lt) {
+ index = bm - 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ /* pixel bottom-right */
+ if (bm && rt) {
+ index = bm + 1;
+ get_pixel(ibuf, index, color);
+ if (color[0] == 1.0f) {
+ BLI_stack_push(stack, &index);
+ }
+ }
+ }
+ }
+ /* set dilated pixels */
+ while (!BLI_stack_is_empty(stack)) {
+ int v;
+ BLI_stack_pop(stack, &v);
+ set_pixel(ibuf, v, green);
+ }
+ BLI_stack_free(stack);
}
/* Get the outline points of a shape using Moore Neighborhood algorithm
@@ -790,331 +810,325 @@ static void dilate(ImBuf *ibuf)
*/
static void gpencil_get_outline_points(tGPDfill *tgpf)
{
- ImBuf *ibuf;
- float rgba[4];
- void *lock;
- int v[2];
- int boundary_co[2];
- int start_co[2];
- int backtracked_co[2];
- int current_check_co[2];
- int prev_check_co[2];
- int backtracked_offset[1][2] = {{0, 0}};
- // bool boundary_found = false;
- bool start_found = false;
- const int NEIGHBOR_COUNT = 8;
-
- const int offset[8][2] = {
- {-1, -1},
- {0, -1},
- {1, -1},
- {1, 0},
- {1, 1},
- {0, 1},
- {-1, 1},
- {-1, 0},
- };
-
- tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
-
- ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
- int imagesize = ibuf->x * ibuf->y;
-
- /* dilate */
- dilate(ibuf);
-
- /* find the initial point to start outline analysis */
- for (int idx = imagesize - 1; idx != 0; idx--) {
- get_pixel(ibuf, idx, rgba);
- if (rgba[1] == 1.0f) {
- boundary_co[0] = idx % ibuf->x;
- boundary_co[1] = idx / ibuf->x;
- copy_v2_v2_int(start_co, boundary_co);
- backtracked_co[0] = (idx - 1) % ibuf->x;
- backtracked_co[1] = (idx - 1) / ibuf->x;
- backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
- backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
- copy_v2_v2_int(prev_check_co, start_co);
-
- BLI_stack_push(tgpf->stack, &boundary_co);
- start_found = true;
- break;
- }
- }
-
- while (start_found) {
- int cur_back_offset = -1;
- for (int i = 0; i < NEIGHBOR_COUNT; i++) {
- if (backtracked_offset[0][0] == offset[i][0] &&
- backtracked_offset[0][1] == offset[i][1])
- {
- /* Finding the bracktracked pixel offset index */
- cur_back_offset = i;
- break;
- }
- }
-
- int loop = 0;
- while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
- int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
- current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
- current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
-
- int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
- get_pixel(ibuf, image_idx, rgba);
-
- /* find next boundary pixel */
- if (rgba[1] == 1.0f) {
- copy_v2_v2_int(boundary_co, current_check_co);
- copy_v2_v2_int(backtracked_co, prev_check_co);
- backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
- backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
-
- BLI_stack_push(tgpf->stack, &boundary_co);
-
- break;
- }
- copy_v2_v2_int(prev_check_co, current_check_co);
- cur_back_offset++;
- loop++;
- }
- /* current pixel is equal to starting pixel */
- if (boundary_co[0] == start_co[0] &&
- boundary_co[1] == start_co[1])
- {
- BLI_stack_pop(tgpf->stack, &v);
- // boundary_found = true;
- break;
- }
- }
-
- /* release ibuf */
- if (ibuf) {
- BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
- }
+ ImBuf *ibuf;
+ float rgba[4];
+ void *lock;
+ int v[2];
+ int boundary_co[2];
+ int start_co[2];
+ int backtracked_co[2];
+ int current_check_co[2];
+ int prev_check_co[2];
+ int backtracked_offset[1][2] = {{0, 0}};
+ // bool boundary_found = false;
+ bool start_found = false;
+ const int NEIGHBOR_COUNT = 8;
+
+ const int offset[8][2] = {
+ {-1, -1},
+ {0, -1},
+ {1, -1},
+ {1, 0},
+ {1, 1},
+ {0, 1},
+ {-1, 1},
+ {-1, 0},
+ };
+
+ tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
+
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int imagesize = ibuf->x * ibuf->y;
+
+ /* dilate */
+ dilate(ibuf);
+
+ /* find the initial point to start outline analysis */
+ for (int idx = imagesize - 1; idx != 0; idx--) {
+ get_pixel(ibuf, idx, rgba);
+ if (rgba[1] == 1.0f) {
+ boundary_co[0] = idx % ibuf->x;
+ boundary_co[1] = idx / ibuf->x;
+ copy_v2_v2_int(start_co, boundary_co);
+ backtracked_co[0] = (idx - 1) % ibuf->x;
+ backtracked_co[1] = (idx - 1) / ibuf->x;
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+ copy_v2_v2_int(prev_check_co, start_co);
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+ start_found = true;
+ break;
+ }
+ }
+
+ while (start_found) {
+ int cur_back_offset = -1;
+ for (int i = 0; i < NEIGHBOR_COUNT; i++) {
+ if (backtracked_offset[0][0] == offset[i][0] && backtracked_offset[0][1] == offset[i][1]) {
+ /* Finding the bracktracked pixel offset index */
+ cur_back_offset = i;
+ break;
+ }
+ }
+
+ int loop = 0;
+ while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
+ int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
+ current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
+ current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
+
+ int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
+ get_pixel(ibuf, image_idx, rgba);
+
+ /* find next boundary pixel */
+ if (rgba[1] == 1.0f) {
+ copy_v2_v2_int(boundary_co, current_check_co);
+ copy_v2_v2_int(backtracked_co, prev_check_co);
+ backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
+ backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
+
+ BLI_stack_push(tgpf->stack, &boundary_co);
+
+ break;
+ }
+ copy_v2_v2_int(prev_check_co, current_check_co);
+ cur_back_offset++;
+ loop++;
+ }
+ /* current pixel is equal to starting pixel */
+ if (boundary_co[0] == start_co[0] && boundary_co[1] == start_co[1]) {
+ BLI_stack_pop(tgpf->stack, &v);
+ // boundary_found = true;
+ break;
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
}
/* get z-depth array to reproject on surface */
static void gpencil_get_depth_array(tGPDfill *tgpf)
{
- tGPspoint *ptc;
- ToolSettings *ts = tgpf->scene->toolsettings;
- int totpoints = tgpf->sbuffer_size;
- int i = 0;
-
- if (totpoints == 0) {
- return;
- }
-
- /* for surface sketching, need to set the right OpenGL context stuff so that
- * the conversions will project the values correctly...
- */
- if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
- /* need to restore the original projection settings before packing up */
- view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
- ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
-
- /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
- int depth_margin = 0;
-
- /* get an array of depths, far depths are blended */
- int mval_prev[2] = { 0 };
- int interp_depth = 0;
- int found_depth = 0;
-
- tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
-
- for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
-
- int mval_i[2];
- round_v2i_v2fl(mval_i, &ptc->x);
-
- if ((ED_view3d_autodist_depth(
- tgpf->ar, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
- (i && (ED_view3d_autodist_depth_seg(
- tgpf->ar, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0)))
- {
- interp_depth = true;
- }
- else {
- found_depth = true;
- }
-
- copy_v2_v2_int(mval_prev, mval_i);
- }
-
- if (found_depth == false) {
- /* eeh... not much we can do.. :/, ignore depth in this case */
- for (i = totpoints - 1; i >= 0; i--)
- tgpf->depth_arr[i] = 0.9999f;
- }
- else {
- if (interp_depth) {
- interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
- }
- }
- }
+ tGPspoint *ptc;
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ int totpoints = tgpf->sbuffer_size;
+ int i = 0;
+
+ if (totpoints == 0) {
+ return;
+ }
+
+ /* for surface sketching, need to set the right OpenGL context stuff so that
+ * the conversions will project the values correctly...
+ */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
+ /* need to restore the original projection settings before packing up */
+ view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
+ ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
+
+ /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
+ int depth_margin = 0;
+
+ /* get an array of depths, far depths are blended */
+ int mval_prev[2] = {0};
+ int interp_depth = 0;
+ int found_depth = 0;
+
+ tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
+
+ for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
+
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, &ptc->x);
+
+ if ((ED_view3d_autodist_depth(tgpf->ar, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
+ (i && (ED_view3d_autodist_depth_seg(
+ tgpf->ar, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) {
+ interp_depth = true;
+ }
+ else {
+ found_depth = true;
+ }
+
+ copy_v2_v2_int(mval_prev, mval_i);
+ }
+
+ if (found_depth == false) {
+ /* eeh... not much we can do.. :/, ignore depth in this case */
+ for (i = totpoints - 1; i >= 0; i--)
+ tgpf->depth_arr[i] = 0.9999f;
+ }
+ else {
+ if (interp_depth) {
+ interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
+ }
+ }
+ }
}
/* create array of points using stack as source */
static void gpencil_points_from_stack(tGPDfill *tgpf)
{
- tGPspoint *point2D;
- int totpoints = BLI_stack_count(tgpf->stack);
- if (totpoints == 0) {
- return;
- }
-
- tgpf->sbuffer_size = (short)totpoints;
- tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
-
- point2D = tgpf->sbuffer;
- while (!BLI_stack_is_empty(tgpf->stack)) {
- int v[2];
- BLI_stack_pop(tgpf->stack, &v);
- copy_v2fl_v2i(&point2D->x, v);
- /* shift points to center of pixel */
- add_v2_fl(&point2D->x, 0.5f);
- point2D->pressure = 1.0f;
- point2D->strength = 1.0f;
- point2D->time = 0.0f;
- point2D++;
- }
+ tGPspoint *point2D;
+ int totpoints = BLI_stack_count(tgpf->stack);
+ if (totpoints == 0) {
+ return;
+ }
+
+ tgpf->sbuffer_size = (short)totpoints;
+ tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
+
+ point2D = tgpf->sbuffer;
+ while (!BLI_stack_is_empty(tgpf->stack)) {
+ int v[2];
+ BLI_stack_pop(tgpf->stack, &v);
+ copy_v2fl_v2i(&point2D->x, v);
+ /* shift points to center of pixel */
+ add_v2_fl(&point2D->x, 0.5f);
+ point2D->pressure = 1.0f;
+ point2D->strength = 1.0f;
+ point2D->time = 0.0f;
+ point2D++;
+ }
}
/* create a grease pencil stroke using points in buffer */
static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
{
- const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
-
- ToolSettings *ts = tgpf->scene->toolsettings;
- const char *align_flag = &ts->gpencil_v3d_align;
- const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
- const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
- (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth);
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- if (brush == NULL) {
- return;
- }
-
- bGPDspoint *pt;
- MDeformVert *dvert = NULL;
- tGPspoint *point2D;
-
- if (tgpf->sbuffer_size == 0) {
- return;
- }
-
- /* get frame or create a new one */
- tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
-
- /* create new stroke */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
- gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
- gps->inittime = 0.0f;
-
- /* the polygon must be closed, so enabled cyclic */
- gps->flag |= GP_STROKE_CYCLIC;
- gps->flag |= GP_STROKE_3DSPACE;
-
- gps->mat_nr = BKE_gpencil_object_material_ensure(tgpf->bmain, tgpf->ob, tgpf->mat);
-
- /* allocate memory for storage points */
- gps->totpoints = tgpf->sbuffer_size;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
-
- /* initialize triangle memory to dummy data */
- gps->tot_triangles = 0;
- gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* add stroke to frame */
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
- BLI_addhead(&tgpf->gpf->strokes, gps);
- }
- else {
- BLI_addtail(&tgpf->gpf->strokes, gps);
- }
-
- /* add points */
- pt = gps->points;
- point2D = (tGPspoint *)tgpf->sbuffer;
-
- const int def_nr = tgpf->ob->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- dvert = gps->dvert;
- }
-
- for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++) {
- /* convert screen-coordinates to 3D coordinates */
- gp_stroke_convertcoords_tpoint(
- tgpf->scene, tgpf->ar, tgpf->ob,
- tgpf->gpl, point2D,
- tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
- &pt->x);
-
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = 0.0f;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
-
- dvert++;
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- dvert++;
- }
- }
- }
-
- /* smooth stroke */
- float reduce = 0.0f;
- float smoothfac = 1.0f;
- for (int r = 0; r < 1; r++) {
- for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
- }
- reduce += 0.25f; // reduce the factor
- }
-
- /* if axis locked, reproject to plane locked */
- if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
- float origin[3];
- ED_gp_get_drawing_reference(
- tgpf->scene, tgpf->ob, tgpf->gpl,
- ts->gpencil_v3d_align, origin);
- ED_gp_project_stroke_to_plane(
- tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin,
- tgpf->lock_axis - 1);
- }
-
- /* if parented change position relative to parent object */
- for (int a = 0; a < tgpf->sbuffer_size; a++) {
- pt = &gps->points[a];
- gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
- }
-
- /* if camera view, reproject flat to view to avoid perspective effect */
- if (is_camera) {
- ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps);
- }
-
- /* simplify stroke */
- for (int b = 0; b < tgpf->fill_simplylvl; b++) {
- BKE_gpencil_simplify_fixed(gps);
- }
+ const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
+
+ ToolSettings *ts = tgpf->scene->toolsettings;
+ const char *align_flag = &ts->gpencil_v3d_align;
+ const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
+ const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
+ (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth);
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ if (brush == NULL) {
+ return;
+ }
+
+ bGPDspoint *pt;
+ MDeformVert *dvert = NULL;
+ tGPspoint *point2D;
+
+ if (tgpf->sbuffer_size == 0) {
+ return;
+ }
+
+ /* get frame or create a new one */
+ tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+
+ /* create new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = brush->size;
+ gps->gradient_f = brush->gpencil_settings->gradient_f;
+ copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+ gps->inittime = 0.0f;
+
+ /* the polygon must be closed, so enabled cyclic */
+ gps->flag |= GP_STROKE_CYCLIC;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = BKE_gpencil_object_material_ensure(tgpf->bmain, tgpf->ob, tgpf->mat);
+
+ /* allocate memory for storage points */
+ gps->totpoints = tgpf->sbuffer_size;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
+
+ /* initialize triangle memory to dummy data */
+ gps->tot_triangles = 0;
+ gps->triangles = NULL;
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* add stroke to frame */
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
+ BLI_addhead(&tgpf->gpf->strokes, gps);
+ }
+ else {
+ BLI_addtail(&tgpf->gpf->strokes, gps);
+ }
+
+ /* add points */
+ pt = gps->points;
+ point2D = (tGPspoint *)tgpf->sbuffer;
+
+ const int def_nr = tgpf->ob->actdef - 1;
+ const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ BKE_gpencil_dvert_ensure(gps);
+ dvert = gps->dvert;
+ }
+
+ for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++) {
+ /* convert screen-coordinates to 3D coordinates */
+ gp_stroke_convertcoords_tpoint(tgpf->scene,
+ tgpf->ar,
+ tgpf->ob,
+ tgpf->gpl,
+ point2D,
+ tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
+ &pt->x);
+
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = 0.0f;
+
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
+ MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
+ if (dw) {
+ dw->weight = ts->vgroup_weight;
+ }
+
+ dvert++;
+ }
+ else {
+ if (dvert != NULL) {
+ dvert->totweight = 0;
+ dvert->dw = NULL;
+ dvert++;
+ }
+ }
+ }
+
+ /* smooth stroke */
+ float reduce = 0.0f;
+ float smoothfac = 1.0f;
+ for (int r = 0; r < 1; r++) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
+ }
+ reduce += 0.25f; // reduce the factor
+ }
+
+ /* if axis locked, reproject to plane locked */
+ if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) &&
+ ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
+ float origin[3];
+ ED_gp_get_drawing_reference(tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin);
+ ED_gp_project_stroke_to_plane(
+ tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1);
+ }
+
+ /* if parented change position relative to parent object */
+ for (int a = 0; a < tgpf->sbuffer_size; a++) {
+ pt = &gps->points[a];
+ gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
+ }
+
+ /* if camera view, reproject flat to view to avoid perspective effect */
+ if (is_camera) {
+ ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps);
+ }
+
+ /* simplify stroke */
+ for (int b = 0; b < tgpf->fill_simplylvl; b++) {
+ BKE_gpencil_simplify_fixed(gps);
+ }
}
/* ----------------------- */
@@ -1122,357 +1136,356 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
/* Helper: Draw status message while the user is running the operator */
static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf))
{
- const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
- ED_workspace_status_text(C, status_str);
+ const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
+ ED_workspace_status_text(C, status_str);
}
/* draw boundary lines to see fill limits */
static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgpf)
{
- if (!tgpf->gpd) {
- return;
- }
- const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
- gp_draw_datablock(tgpf, ink);
+ if (!tgpf->gpd) {
+ return;
+ }
+ const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ gp_draw_datablock(tgpf, ink);
}
/* Drawing callback for modal operator in 3d mode */
static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
- tGPDfill *tgpf = (tGPDfill *)arg;
- /* draw only in the region that originated operator. This is required for multiwindow */
- ARegion *ar = CTX_wm_region(C);
- if (ar != tgpf->ar) {
- return;
- }
-
- gpencil_draw_boundary_lines(C, tgpf);
+ tGPDfill *tgpf = (tGPDfill *)arg;
+ /* draw only in the region that originated operator. This is required for multiwindow */
+ ARegion *ar = CTX_wm_region(C);
+ if (ar != tgpf->ar) {
+ return;
+ }
+
+ gpencil_draw_boundary_lines(C, tgpf);
}
/* check if context is suitable for filling */
static bool gpencil_fill_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
-
- if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa->spacetype == SPACE_VIEW3D) {
- if ((obact == NULL) ||
- (obact->type != OB_GPENCIL) ||
- (obact->mode != OB_MODE_PAINT_GPENCIL))
- {
- return false;
- }
-
- return true;
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
- return false;
- }
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not set");
- return false;
- }
+ Object *obact = CTX_data_active_object(C);
+
+ if (ED_operator_regionactive(C)) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa->spacetype == SPACE_VIEW3D) {
+ if ((obact == NULL) || (obact->type != OB_GPENCIL) ||
+ (obact->mode != OB_MODE_PAINT_GPENCIL)) {
+ return false;
+ }
+
+ return true;
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
+ return false;
+ }
+ }
+ else {
+ CTX_wm_operator_poll_msg_set(C, "Active region not set");
+ return false;
+ }
}
/* Allocate memory and initialize values */
static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
{
- tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
-
- /* define initial values */
- ToolSettings *ts = CTX_data_tool_settings(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
- Main *bmain = CTX_data_main(C);
-
- /* set current scene and window info */
- tgpf->C = C;
- tgpf->bmain = CTX_data_main(C);
- tgpf->scene = CTX_data_scene(C);
- tgpf->ob = CTX_data_active_object(C);
- tgpf->sa = CTX_wm_area(C);
- tgpf->ar = CTX_wm_region(C);
- tgpf->rv3d = tgpf->ar->regiondata;
- tgpf->v3d = tgpf->sa->spacedata.first;
- tgpf->depsgraph = CTX_data_depsgraph(C);
- tgpf->win = CTX_wm_window(C);
-
- /* set GP datablock */
- tgpf->gpd = gpd;
- tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
- if (tgpf->gpl == NULL) {
- tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
- }
- tgpf->lock_axis = ts->gp_sculpt.lock_axis;
-
- tgpf->oldkey = -1;
- tgpf->sbuffer_size = 0;
- tgpf->sbuffer = NULL;
- tgpf->depth_arr = NULL;
-
- /* save filling parameters */
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- tgpf->flag = brush->gpencil_settings->flag;
- tgpf->fill_leak = brush->gpencil_settings->fill_leak;
- tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
- tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
- tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
- tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor, 8));
-
- int totcol = tgpf->ob->totcol;
-
- /* get color info */
- Material *ma = BKE_gpencil_object_material_ensure_from_active_input_brush(bmain, tgpf->ob, brush);
-
- tgpf->mat = ma;
-
- /* check whether the material was newly added */
- if (totcol != tgpf->ob->totcol) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
- }
-
- /* init undo */
- gpencil_undo_init(tgpf->gpd);
-
- /* return context data for running operator */
- return tgpf;
+ tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
+
+ /* define initial values */
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Main *bmain = CTX_data_main(C);
+
+ /* set current scene and window info */
+ tgpf->C = C;
+ tgpf->bmain = CTX_data_main(C);
+ tgpf->scene = CTX_data_scene(C);
+ tgpf->ob = CTX_data_active_object(C);
+ tgpf->sa = CTX_wm_area(C);
+ tgpf->ar = CTX_wm_region(C);
+ tgpf->rv3d = tgpf->ar->regiondata;
+ tgpf->v3d = tgpf->sa->spacedata.first;
+ tgpf->depsgraph = CTX_data_depsgraph(C);
+ tgpf->win = CTX_wm_window(C);
+
+ /* set GP datablock */
+ tgpf->gpd = gpd;
+ tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
+ if (tgpf->gpl == NULL) {
+ tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
+ }
+ tgpf->lock_axis = ts->gp_sculpt.lock_axis;
+
+ tgpf->oldkey = -1;
+ tgpf->sbuffer_size = 0;
+ tgpf->sbuffer = NULL;
+ tgpf->depth_arr = NULL;
+
+ /* save filling parameters */
+ Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
+ tgpf->flag = brush->gpencil_settings->flag;
+ tgpf->fill_leak = brush->gpencil_settings->fill_leak;
+ tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
+ tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
+ tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
+ tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor, 8));
+
+ int totcol = tgpf->ob->totcol;
+
+ /* get color info */
+ Material *ma = BKE_gpencil_object_material_ensure_from_active_input_brush(
+ bmain, tgpf->ob, brush);
+
+ tgpf->mat = ma;
+
+ /* check whether the material was newly added */
+ if (totcol != tgpf->ob->totcol) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
+ }
+
+ /* init undo */
+ gpencil_undo_init(tgpf->gpd);
+
+ /* return context data for running operator */
+ return tgpf;
}
/* end operator */
static void gpencil_fill_exit(bContext *C, wmOperator *op)
{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
-
- /* clear undo stack */
- gpencil_undo_finish();
-
- /* restore cursor to indicate end of fill */
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- tGPDfill *tgpf = op->customdata;
-
- /* don't assume that operator data exists at all */
- if (tgpf) {
- /* clear status message area */
- ED_workspace_status_text(C, NULL);
-
- MEM_SAFE_FREE(tgpf->sbuffer);
- MEM_SAFE_FREE(tgpf->depth_arr);
-
- /* remove drawing handler */
- if (tgpf->draw_handle_3d) {
- ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
- }
-
- /* delete temp image */
- if (tgpf->ima) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- if (ima == tgpf->ima) {
- BLI_remlink(&bmain->images, ima);
- BKE_image_free(tgpf->ima);
- MEM_SAFE_FREE(tgpf->ima);
- break;
- }
- }
- }
-
- /* finally, free memory used by temp data */
- MEM_freeN(tgpf);
- }
-
- /* clear pointer */
- op->customdata = NULL;
-
- /* drawing batch cache is dirty now */
- if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
- bGPdata *gpd2 = ob->data;
- DEG_id_tag_update(&gpd2->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
-
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* clear undo stack */
+ gpencil_undo_finish();
+
+ /* restore cursor to indicate end of fill */
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ tGPDfill *tgpf = op->customdata;
+
+ /* don't assume that operator data exists at all */
+ if (tgpf) {
+ /* clear status message area */
+ ED_workspace_status_text(C, NULL);
+
+ MEM_SAFE_FREE(tgpf->sbuffer);
+ MEM_SAFE_FREE(tgpf->depth_arr);
+
+ /* remove drawing handler */
+ if (tgpf->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
+ }
+
+ /* delete temp image */
+ if (tgpf->ima) {
+ for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
+ if (ima == tgpf->ima) {
+ BLI_remlink(&bmain->images, ima);
+ BKE_image_free(tgpf->ima);
+ MEM_SAFE_FREE(tgpf->ima);
+ break;
+ }
+ }
+ }
+
+ /* finally, free memory used by temp data */
+ MEM_freeN(tgpf);
+ }
+
+ /* clear pointer */
+ op->customdata = NULL;
+
+ /* drawing batch cache is dirty now */
+ if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
+ bGPdata *gpd2 = ob->data;
+ DEG_id_tag_update(&gpd2->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
}
static void gpencil_fill_cancel(bContext *C, wmOperator *op)
{
- /* this is just a wrapper around exit() */
- gpencil_fill_exit(C, op);
+ /* this is just a wrapper around exit() */
+ gpencil_fill_exit(C, op);
}
/* Init: Allocate memory and set init values */
static int gpencil_fill_init(bContext *C, wmOperator *op)
{
- tGPDfill *tgpf;
- /* cannot paint in locked layer */
- bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
- return 0;
- }
-
- /* check context */
- tgpf = op->customdata = gp_session_init_fill(C, op);
- if (tgpf == NULL) {
- /* something wasn't set correctly in context */
- gpencil_fill_exit(C, op);
- return 0;
- }
-
- /* everything is now setup ok */
- return 1;
+ tGPDfill *tgpf;
+ /* cannot paint in locked layer */
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
+ return 0;
+ }
+
+ /* check context */
+ tgpf = op->customdata = gp_session_init_fill(C, op);
+ if (tgpf == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_fill_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
}
/* start of interactive part of operator */
static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- tGPDfill *tgpf = NULL;
+ tGPDfill *tgpf = NULL;
- /* try to initialize context data needed */
- if (!gpencil_fill_init(C, op)) {
- gpencil_fill_exit(C, op);
- if (op->customdata)
- MEM_freeN(op->customdata);
- return OPERATOR_CANCELLED;
- }
- else {
- tgpf = op->customdata;
- }
+ /* try to initialize context data needed */
+ if (!gpencil_fill_init(C, op)) {
+ gpencil_fill_exit(C, op);
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ tgpf = op->customdata;
+ }
- /* Enable custom drawing handlers to show help lines */
- if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
- tgpf->draw_handle_3d = ED_region_draw_cb_activate(tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
- }
+ /* Enable custom drawing handlers to show help lines */
+ if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
+ tgpf->draw_handle_3d = ED_region_draw_cb_activate(
+ tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
+ }
- WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
- gpencil_fill_status_indicators(C, tgpf);
+ gpencil_fill_status_indicators(C, tgpf);
- DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- /* add a modal handler for this operator*/
- WM_event_add_modal_handler(C, op);
+ /* add a modal handler for this operator*/
+ WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
/* events handling during interactive part of operator */
static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGPDfill *tgpf = op->customdata;
-
- int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
-
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- estate = OPERATOR_CANCELLED;
- break;
- case LEFTMOUSE:
- tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
- /* first time the event is not enabled to show help lines */
- if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
- ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
- if (ar) {
- bool in_bounds = false;
-
- /* Perform bounds check */
- in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
-
- if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
- /* TODO GPXX: Verify the mouse click is right for any window size */
- tgpf->center[0] = event->mval[0];
- tgpf->center[1] = event->mval[1];
-
- /* render screen to temp image */
- if ( gp_render_offscreen(tgpf) ) {
-
- /* apply boundary fill */
- gpencil_boundaryfill_area(tgpf);
-
- /* clean borders to avoid infinite loops */
- gpencil_clean_borders(tgpf);
-
- /* analyze outline */
- gpencil_get_outline_points(tgpf);
-
- /* create array of points from stack */
- gpencil_points_from_stack(tgpf);
-
- /* create z-depth array for reproject */
- gpencil_get_depth_array(tgpf);
-
- /* create stroke and reproject */
- gpencil_stroke_from_buffer(tgpf);
-
- }
-
- /* restore size */
- tgpf->ar->winx = (short)tgpf->bwinx;
- tgpf->ar->winy = (short)tgpf->bwiny;
- tgpf->ar->winrct = tgpf->brect;
-
- /* free temp stack data */
- if (tgpf->stack) {
- BLI_stack_free(tgpf->stack);
- }
-
- /* push undo data */
- gpencil_undo_push(tgpf->gpd);
-
- estate = OPERATOR_FINISHED;
- }
- else {
- estate = OPERATOR_CANCELLED;
- }
- }
- else {
- estate = OPERATOR_CANCELLED;
- }
- }
- tgpf->oldkey = event->type;
- break;
- }
- /* process last operations before exiting */
- switch (estate) {
- case OPERATOR_FINISHED:
- gpencil_fill_exit(C, op);
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- break;
-
- case OPERATOR_CANCELLED:
- gpencil_fill_exit(C, op);
- break;
-
- case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
- break;
- }
-
- /* return status code */
- return estate;
+ tGPDfill *tgpf = op->customdata;
+
+ int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ estate = OPERATOR_CANCELLED;
+ break;
+ case LEFTMOUSE:
+ tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
+ /* first time the event is not enabled to show help lines */
+ if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
+ ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
+ if (ar) {
+ bool in_bounds = false;
+
+ /* Perform bounds check */
+ in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
+
+ if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
+ /* TODO GPXX: Verify the mouse click is right for any window size */
+ tgpf->center[0] = event->mval[0];
+ tgpf->center[1] = event->mval[1];
+
+ /* render screen to temp image */
+ if (gp_render_offscreen(tgpf)) {
+
+ /* apply boundary fill */
+ gpencil_boundaryfill_area(tgpf);
+
+ /* clean borders to avoid infinite loops */
+ gpencil_clean_borders(tgpf);
+
+ /* analyze outline */
+ gpencil_get_outline_points(tgpf);
+
+ /* create array of points from stack */
+ gpencil_points_from_stack(tgpf);
+
+ /* create z-depth array for reproject */
+ gpencil_get_depth_array(tgpf);
+
+ /* create stroke and reproject */
+ gpencil_stroke_from_buffer(tgpf);
+ }
+
+ /* restore size */
+ tgpf->ar->winx = (short)tgpf->bwinx;
+ tgpf->ar->winy = (short)tgpf->bwiny;
+ tgpf->ar->winrct = tgpf->brect;
+
+ /* free temp stack data */
+ if (tgpf->stack) {
+ BLI_stack_free(tgpf->stack);
+ }
+
+ /* push undo data */
+ gpencil_undo_push(tgpf->gpd);
+
+ estate = OPERATOR_FINISHED;
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ estate = OPERATOR_CANCELLED;
+ }
+ }
+ tgpf->oldkey = event->type;
+ break;
+ }
+ /* process last operations before exiting */
+ switch (estate) {
+ case OPERATOR_FINISHED:
+ gpencil_fill_exit(C, op);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ break;
+
+ case OPERATOR_CANCELLED:
+ gpencil_fill_exit(C, op);
+ break;
+
+ case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
+ break;
+ }
+
+ /* return status code */
+ return estate;
}
void GPENCIL_OT_fill(wmOperatorType *ot)
{
- PropertyRNA *prop;
+ PropertyRNA *prop;
- /* identifiers */
- ot->name = "Grease Pencil Fill";
- ot->idname = "GPENCIL_OT_fill";
- ot->description = "Fill with color the shape formed by strokes";
+ /* identifiers */
+ ot->name = "Grease Pencil Fill";
+ ot->idname = "GPENCIL_OT_fill";
+ ot->description = "Fill with color the shape formed by strokes";
- /* api callbacks */
- ot->invoke = gpencil_fill_invoke;
- ot->modal = gpencil_fill_modal;
- ot->poll = gpencil_fill_poll;
- ot->cancel = gpencil_fill_cancel;
+ /* api callbacks */
+ ot->invoke = gpencil_fill_invoke;
+ ot->modal = gpencil_fill_modal;
+ ot->poll = gpencil_fill_poll;
+ ot->cancel = gpencil_fill_cancel;
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
- prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}