diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 42 | ||||
-rw-r--r-- | source/blender/editors/gpencil/annotate_draw.c | 73 | ||||
-rw-r--r-- | source/blender/editors/gpencil/annotate_paint.c | 305 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_gpencil_types.h | 22 |
4 files changed, 419 insertions, 23 deletions
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 8638f1a2a27..b10b451c7f8 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -148,6 +148,8 @@ class _defs_annotate: def draw_settings_common(context, layout, tool): gpd = context.annotation_data + region_type = context.region.type + if gpd is not None: if gpd.layers.active_note is not None: text = gpd.layers.active_note @@ -160,17 +162,24 @@ class _defs_annotate: gpl = context.active_annotation_layer if gpl is not None: layout.label(text="Annotation:") - sub = layout.row(align=True) - sub.ui_units_x = 8 - - sub.prop(gpl, "color", text="") - sub.popover( - panel="TOPBAR_PT_annotation_layers", - text=text, - ) + if context.space_data.type == 'VIEW_3D': + if region_type == 'TOOL_HEADER': + sub = layout.split(align=True, factor=0.5) + sub.ui_units_x = 6.5 + sub.prop(gpl, "color", text="") + else: + sub = layout.row(align=True) + sub.prop(gpl, "color", text="") + sub.popover( + panel="TOPBAR_PT_annotation_layers", + text=text, + ) + else: + layout.prop(gpl, "color", text="") - tool_settings = context.tool_settings space_type = tool.space_type + tool_settings = context.tool_settings + if space_type == 'VIEW_3D': layout.separator() @@ -181,6 +190,21 @@ class _defs_annotate: elif tool_settings.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}: row.prop(tool_settings, "use_gpencil_stroke_endpoints") + if tool.idname == "builtin.annotate_line": + layout.separator() + + props = tool.operator_properties("gpencil.annotate") + if region_type == 'TOOL_HEADER': + row = layout.row() + row.ui_units_x = 15 + row.prop(props, "arrowstyle_start", text="Start") + row.separator() + row.prop(props, "arrowstyle_end", text="End") + else: + col = layout.row().column(align=True) + col.prop(props, "arrowstyle_start", text="Style Start") + col.prop(props, "arrowstyle_end", text="End") + @ToolDef.from_fn.with_args(draw_settings=draw_settings_common) def scribble(*, draw_settings): return dict( diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index 86423d907b5..22df7bbbf31 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -90,14 +90,54 @@ typedef enum eDrawStrokeFlags { /* ----- Tool Buffer Drawing ------ */ +static void annotation_draw_stroke_arrow_buffer(uint pos, + const float *corner_point, + const float *arrow_coords, + const int arrow_style) +{ + immBeginAtMost(GPU_PRIM_LINE_STRIP, arrow_style); + + switch (arrow_style) { + case GP_STROKE_ARROWSTYLE_SEGMENT: + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + break; + case GP_STROKE_ARROWSTYLE_CLOSED: + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + immVertex2f(pos, arrow_coords[4], arrow_coords[5]); + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + break; + case GP_STROKE_ARROWSTYLE_OPEN: + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, corner_point[0], corner_point[1]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + break; + case GP_STROKE_ARROWSTYLE_SQUARE: + immVertex2f(pos, corner_point[0], corner_point[1]); + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, arrow_coords[4], arrow_coords[5]); + immVertex2f(pos, arrow_coords[6], arrow_coords[7]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + immVertex2f(pos, corner_point[0], corner_point[1]); + break; + default: + break; + } + immEnd(); +} + /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ -static void annotation_draw_stroke_buffer(const tGPspoint *points, - int totpoints, +static void annotation_draw_stroke_buffer(bGPdata *gps, short thickness, short dflag, - short sflag, const float ink[4]) { + bGPdata_Runtime runtime = gps->runtime; + const tGPspoint *points = runtime.sbuffer; + int totpoints = runtime.sbuffer_used; + short sflag = runtime.sbuffer_sflag; + int draw_points = 0; /* error checking */ @@ -176,6 +216,26 @@ static void annotation_draw_stroke_buffer(const tGPspoint *points, } immEnd(); + + /* Draw arrow stroke. */ + if (totpoints > 1) { + /* Draw ending arrow stroke. */ + if ((sflag & GP_STROKE_USE_ARROW_END) && + (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) { + float end[2]; + copy_v2_fl2(end, points[1].x, points[1].y); + annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style); + } + /* Draw starting arrow stroke. */ + if ((sflag & GP_STROKE_USE_ARROW_START) && + (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) { + float start[2]; + copy_v2_fl2(start, points[0].x, points[0].y); + annotation_draw_stroke_arrow_buffer( + pos, start, runtime.arrow_start, runtime.arrow_start_style); + } + } + immUnbindProgram(); } @@ -653,12 +713,7 @@ static void annotation_draw_data_layers( * It should also be noted that sbuffer contains temporary point types * i.e. tGPspoints NOT bGPDspoints */ - annotation_draw_stroke_buffer(gpd->runtime.sbuffer, - gpd->runtime.sbuffer_used, - lthick, - dflag, - gpd->runtime.sbuffer_sflag, - ink); + annotation_draw_stroke_buffer(gpd, lthick, dflag, ink); } } } diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 8d50e24b7f0..8bbac80445a 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -418,6 +418,85 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) copy_v2_v2(&ptc->x, c); } +static void gp_stroke_arrow_calc_points_segment(float stroke_points[8], + const float ref_point[2], + const float dir_cw[2], + const float dir_ccw[2], + const float lenght, + const float sign) +{ + stroke_points[0] = ref_point[0] + dir_cw[0] * lenght * sign; + stroke_points[1] = ref_point[1] + dir_cw[1] * lenght * sign; + stroke_points[2] = ref_point[0] + dir_ccw[0] * lenght * sign; + stroke_points[3] = ref_point[1] + dir_ccw[1] * lenght * sign; +} + +static void gp_stroke_arrow_calc_points(tGPspoint *point, + const float stroke_dir[2], + float corner[2], + float stroke_points[8], + const int arrow_style) +{ + const int arrow_lenght = 8; + float norm_dir[2]; + copy_v2_v2(norm_dir, stroke_dir); + normalize_v2(norm_dir); + const float inv_norm_dir_clockwise[2] = {norm_dir[1], -norm_dir[0]}; + const float inv_norm_dir_counterclockwise[2] = {-norm_dir[1], norm_dir[0]}; + + switch (arrow_style) { + case GP_STROKE_ARROWSTYLE_OPEN: + mul_v2_fl(norm_dir, arrow_lenght); + stroke_points[0] = corner[0] + inv_norm_dir_clockwise[0] * arrow_lenght + norm_dir[0]; + stroke_points[1] = corner[1] + inv_norm_dir_clockwise[1] * arrow_lenght + norm_dir[1]; + stroke_points[2] = corner[0] + inv_norm_dir_counterclockwise[0] * arrow_lenght + norm_dir[0]; + stroke_points[3] = corner[1] + inv_norm_dir_counterclockwise[1] * arrow_lenght + norm_dir[1]; + break; + case GP_STROKE_ARROWSTYLE_SEGMENT: + gp_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght, + 1.0f); + break; + case GP_STROKE_ARROWSTYLE_CLOSED: + mul_v2_fl(norm_dir, arrow_lenght); + if (point != NULL) { + add_v2_v2(&point->x, norm_dir); + copy_v2_v2(corner, &point->x); + } + gp_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght, + -1.0f); + stroke_points[4] = corner[0] - norm_dir[0]; + stroke_points[5] = corner[1] - norm_dir[1]; + break; + case GP_STROKE_ARROWSTYLE_SQUARE: + mul_v2_fl(norm_dir, arrow_lenght * 1.5f); + if (point != NULL) { + add_v2_v2(&point->x, norm_dir); + copy_v2_v2(corner, &point->x); + } + gp_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght * 0.75f, + -1.0f); + stroke_points[4] = stroke_points[0] - norm_dir[0]; + stroke_points[5] = stroke_points[1] - norm_dir[1]; + stroke_points[6] = stroke_points[2] - norm_dir[0]; + stroke_points[7] = stroke_points[3] - norm_dir[1]; + break; + default: + break; + } +} + /* add current stroke-point to buffer (returns whether point was successfully added) */ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime) { @@ -457,6 +536,32 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */ gpd->runtime.sbuffer_used = 2; + + /* Arrows. */ + if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) { + /* Store start and end point coords for arrows. */ + float end[2]; + copy_v2_v2(end, &pt->x); + pt = ((tGPspoint *)(gpd->runtime.sbuffer)); + float start[2]; + copy_v2_v2(start, &pt->x); + + /* Arrow end corner. */ + if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) { + pt++; + float e_heading[2] = {start[0] - end[0], start[1] - end[1]}; + /* Calculate points for ending arrow. */ + gp_stroke_arrow_calc_points( + pt, e_heading, end, gpd->runtime.arrow_end, gpd->runtime.arrow_end_style); + } + /* Arrow start corner. */ + if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) { + float s_heading[2] = {end[0] - start[0], end[1] - start[1]}; + /* Calculate points for starting arrow. */ + gp_stroke_arrow_calc_points( + NULL, s_heading, start, gpd->runtime.arrow_start, gpd->runtime.arrow_start_style); + } + } } /* can keep carrying on this way :) */ @@ -490,7 +595,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure } else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { /* get pointer to destination point */ - pt = (tGPspoint *)(gpd->runtime.sbuffer); + pt = (tGPspoint *)gpd->runtime.sbuffer; /* store settings */ copy_v2_v2(&pt->x, mval); @@ -552,6 +657,123 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure return GP_STROKEADD_INVALID; } +static void gp_stroke_arrow_init_point_default(bGPDspoint *pt) +{ + pt->pressure = 1.0f; + pt->strength = 1.0f; + pt->time = 1.0f; +} + +static void gp_stroke_arrow_init_conv_point(bGPDspoint *pt, const float point[3]) +{ + copy_v3_v3(&pt->x, point); + gp_stroke_arrow_init_point_default(pt); +} + +static void gp_stroke_arrow_init_point( + tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float co[8], const int co_idx) +{ + /* Note: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */ + float real_co[2] = {co[co_idx], co[co_idx + 1]}; + copy_v2_v2(&ptc->x, real_co); + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gp_stroke_arrow_init_point_default(pt); +} + +static void gp_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints) +{ + /* Copy appropriate settings for stroke. */ + gps->totpoints = totpoints; + /* Allocate enough memory for a continuous array for storage points. */ + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); +} + +static void gp_arrow_create_open(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float corner_point[3], + const float arrow_points[8]) +{ + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_conv_point(pt, corner_point); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); +} + +static void gp_arrow_create_segm(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float arrow_points[8]) +{ + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); +} + +static void gp_arrow_create_closed(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float arrow_points[8]) +{ + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); +} + +static void gp_arrow_create_square(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float corner_point[3], + const float arrow_points[8]) +{ + gp_stroke_arrow_init_conv_point(pt, corner_point); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 6); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + pt++; + gp_stroke_arrow_init_conv_point(pt, corner_point); +} + +static void gp_arrow_create(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + bGPDstroke *arrow_stroke, + const float arrow_points[8], + const int style) +{ + float corner_conv[3]; + copy_v3_v3(corner_conv, &pt->x); + + switch (style) { + case GP_STROKE_ARROWSTYLE_SEGMENT: + gp_arrow_create_segm(p, ptc, pt, arrow_points); + break; + case GP_STROKE_ARROWSTYLE_CLOSED: + gp_arrow_create_closed(p, ptc, pt, arrow_points); + break; + case GP_STROKE_ARROWSTYLE_OPEN: + gp_arrow_create_open(p, ptc, pt, corner_conv, arrow_points); + break; + case GP_STROKE_ARROWSTYLE_SQUARE: + gp_arrow_create_square(p, ptc, pt, corner_conv, arrow_points); + break; + default: + break; + } + /* Link stroke to frame. */ + BLI_addtail(&p->gpf->strokes, arrow_stroke); +} + /* make a new stroke from the buffer data */ static void gp_stroke_newfrombuffer(tGPsdata *p) { @@ -637,17 +859,61 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } if (totelem == 2) { - /* last point if applicable */ - ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1); + bGPdata_Runtime runtime = gpd->runtime; - /* convert screen-coordinates to appropriate coordinates (and store them) */ + /* Last point if applicable. */ + ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); + + /* Convert screen-coordinates to appropriate coordinates (and store them). */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* copy pressure and time */ + /* Copy pressure and time. */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; + + /** Create arrow strokes. **/ + /* End arrow stroke. */ + if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) && + (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) { + int totarrowpoints = runtime.arrow_end_style; + + /* Setting up arrow stroke. */ + bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false); + gp_stroke_arrow_allocate(e_arrow_gps, totarrowpoints); + + /* Set pointer to first non-initialized point. */ + pt = e_arrow_gps->points + (e_arrow_gps->totpoints - totarrowpoints); + + /* End point. */ + ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gp_stroke_arrow_init_point_default(pt); + + /* Fill and convert arrow points to create arrow shape. */ + gp_arrow_create(p, ptc, pt, e_arrow_gps, runtime.arrow_end, runtime.arrow_end_style); + } + /* Start arrow stroke. */ + if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) && + (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) { + int totarrowpoints = runtime.arrow_start_style; + + /* Setting up arrow stroke. */ + bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false); + gp_stroke_arrow_allocate(s_arrow_gps, totarrowpoints); + + /* Set pointer to first non-initialized point. */ + pt = s_arrow_gps->points + (s_arrow_gps->totpoints - totarrowpoints); + + /* Start point. */ + ptc = runtime.sbuffer; + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gp_stroke_arrow_init_point_default(pt); + + /* Fill and convert arrow points to create arrow shape. */ + gp_arrow_create(p, ptc, pt, s_arrow_gps, runtime.arrow_start, runtime.arrow_start_style); + } } } else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { @@ -1902,6 +2168,16 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event if (p->paintmode == GP_PAINTMODE_ERASER) { gpencil_draw_toggle_eraser_cursor(C, p, true); } + else if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { + if (RNA_enum_get(op->ptr, "arrowstyle_start") != GP_STROKE_ARROWSTYLE_NONE) { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_START; + p->gpd->runtime.arrow_start_style = RNA_enum_get(op->ptr, "arrowstyle_start"); + } + if (RNA_enum_get(op->ptr, "arrowstyle_end") != GP_STROKE_ARROWSTYLE_NONE) { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_END; + p->gpd->runtime.arrow_end_style = RNA_enum_get(op->ptr, "arrowstyle_end"); + } + } /* set cursor * NOTE: This may change later (i.e. intentionally via brush toggle, * or unintentionally if the user scrolls outside the area)... @@ -2370,6 +2646,19 @@ static const EnumPropertyItem prop_gpencil_drawmodes[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem arrow_types[] = { + {GP_STROKE_ARROWSTYLE_NONE, "NONE", 0, "None", "Don't use any arrow/style in corner"}, + {GP_STROKE_ARROWSTYLE_CLOSED, "ARROW", 0, "Arrow", "Use closed arrow style"}, + {GP_STROKE_ARROWSTYLE_OPEN, "ARROW_OPEN", 0, "Open Arrow", "Use open arrow style"}, + {GP_STROKE_ARROWSTYLE_SEGMENT, + "ARROW_OPEN_INVERTED", + 0, + "Segment", + "Use perpendicular segment style"}, + {GP_STROKE_ARROWSTYLE_SQUARE, "DIAMOND", 0, "Square", "Use square style"}, + {0, NULL, 0, NULL, NULL}, +}; + void GPENCIL_OT_annotate(wmOperatorType *ot) { PropertyRNA *prop; @@ -2393,6 +2682,12 @@ void GPENCIL_OT_annotate(wmOperatorType *ot) ot->prop = RNA_def_enum( ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements"); + /* properties */ + prop = RNA_def_enum( + ot->srna, "arrowstyle_start", arrow_types, 0, "Start Arrow Style", "Stroke start style"); + prop = RNA_def_enum( + ot->srna, "arrowstyle_end", arrow_types, 0, "End Arrow Style", "Stroke end style"); + prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index bf9f228b53f..cfc9324a100 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -264,6 +264,10 @@ typedef enum eGPDstroke_Flag { /* Flag used to indicate that stroke is used for fill close and must use * fill color for stroke and no fill area */ GP_STROKE_NOFILL = (1 << 8), + /* only for use with stroke-buffer (while drawing arrows) */ + GP_STROKE_USE_ARROW_START = (1 << 12), + /* only for use with stroke-buffer (while drawing arrows) */ + GP_STROKE_USE_ARROW_END = (1 << 13), /* Tag for update geometry */ GP_STROKE_TAG = (1 << 14), /* only for use with stroke-buffer (while drawing eraser) */ @@ -280,6 +284,17 @@ typedef enum eGPDstroke_Caps { GP_STROKE_CAP_MAX, } GPDstroke_Caps; +/* Arrows ----------------------- */ + +/* bGPDataRuntime.arrowstyle */ +typedef enum eGPDstroke_Arrowstyle { + GP_STROKE_ARROWSTYLE_NONE = 0, + GP_STROKE_ARROWSTYLE_SEGMENT = 2, + GP_STROKE_ARROWSTYLE_OPEN = 3, + GP_STROKE_ARROWSTYLE_CLOSED = 4, + GP_STROKE_ARROWSTYLE_SQUARE = 6, +} eGPDstroke_Arrowstyle; + /* ***************************************** */ /* GP Frame */ @@ -511,6 +526,13 @@ typedef struct bGPdata_Runtime { /** Vertex Color applied to Fill (while drawing). */ float vert_color_fill[4]; + /** Arrow points for stroke corners **/ + float arrow_start[8]; + float arrow_end[8]; + /* Arrow style for each corner */ + int arrow_start_style; + int arrow_end_style; + /** Number of control-points for stroke. */ int tot_cp_points; char _pad2[4]; |