GPencil: Merge GSoC curve edit mode
Differential Revision: https://developer.blender.org/D8660 This patch is the result of the GSoC 2020 "Editing Grease Pencil Strokes Using Curves" project. It adds a submode to greasepencil edit mode that allows for the transformation of greasepencil strokes using bezier curves. More information about the project can be found here: https://wiki.blender.org/wiki/User:Filedescriptor/GSoC_2020.
This commit is contained in:
parent
9d28353b52
commit
0be88c7d15
Notes:
blender-bot
2023-02-14 06:37:09 +01:00
Referenced by issue #84260, NURBS Surface Edit Mode: Spline Cage of Unselected Surface Is Not Fully Rendered Referenced by issue #80192, GPencil: New Bezier edition (GSoC)
|
@ -191,6 +191,7 @@ _km_hierarchy = [
|
|||
]),
|
||||
|
||||
('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region)
|
||||
('Grease Pencil Stroke Curve Edit Mode', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Paint (Draw brush)', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Paint (Fill)', 'EMPTY', 'WINDOW', []),
|
||||
|
|
|
@ -3226,6 +3226,9 @@ def km_grease_pencil_stroke_edit_mode(params):
|
|||
{"properties": [("mode", 'GPENCIL_OPACITY')]}),
|
||||
# Proportional editing.
|
||||
*_template_items_proportional_editing(connected=True),
|
||||
# Curve edit mode toggle.
|
||||
("wm.context_toggle", {"type": 'U', "value": 'PRESS'},
|
||||
{"properties": [("data_path", 'gpencil_data.use_curve_edit')]}),
|
||||
# Add menu
|
||||
("object.gpencil_add", {"type": 'A', "value": 'PRESS', "shift": True}, None),
|
||||
# Vertex group menu
|
||||
|
@ -3253,6 +3256,20 @@ def km_grease_pencil_stroke_edit_mode(params):
|
|||
|
||||
return keymap
|
||||
|
||||
def km_grease_pencil_stroke_curve_edit_mode(params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Grease Pencil Stroke Curve Edit Mode",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
# Set handle type
|
||||
("gpencil.stroke_editcurve_set_handle_type", {"type": 'V', "value": 'PRESS'}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
def km_grease_pencil_stroke_paint_mode(params):
|
||||
items = []
|
||||
|
@ -6890,6 +6907,7 @@ def generate_keymaps(params=None):
|
|||
|
||||
# Modes.
|
||||
km_grease_pencil(params),
|
||||
km_grease_pencil_stroke_curve_edit_mode(params),
|
||||
km_grease_pencil_stroke_edit_mode(params),
|
||||
km_grease_pencil_stroke_paint_mode(params),
|
||||
km_grease_pencil_stroke_paint_draw_brush(params),
|
||||
|
|
|
@ -369,6 +369,8 @@ class DATA_PT_gpencil_strokes(DataButtonsPanel, Panel):
|
|||
sub.active = gpd.stroke_thickness_space == 'WORLDSPACE'
|
||||
sub.prop(gpd, "pixel_factor", text="Thickness Scale")
|
||||
|
||||
col.prop(gpd, "edit_curve_resolution")
|
||||
|
||||
|
||||
class DATA_PT_gpencil_display(DataButtonsPanel, Panel):
|
||||
bl_label = "Viewport Display"
|
||||
|
|
|
@ -661,7 +661,23 @@ class VIEW3D_HT_header(Header):
|
|||
# Select mode for Editing
|
||||
if gpd.use_stroke_edit_mode:
|
||||
row = layout.row(align=True)
|
||||
row.prop(tool_settings, "gpencil_selectmode_edit", text="", expand=True)
|
||||
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='POINT')
|
||||
row.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='STROKE')
|
||||
|
||||
subrow = row.row(align=True)
|
||||
subrow.enabled = not gpd.use_curve_edit
|
||||
subrow.prop_enum(tool_settings, "gpencil_selectmode_edit", text="", value='SEGMENT')
|
||||
|
||||
# Curve edit submode
|
||||
row = layout.row(align=True)
|
||||
row.prop(gpd, "use_curve_edit", text="",
|
||||
icon='IPO_BEZIER')
|
||||
sub = row.row(align=True)
|
||||
sub.active = gpd.use_curve_edit
|
||||
sub.popover(
|
||||
panel="VIEW3D_PT_gpencil_curve_edit",
|
||||
text="Curve Editing",
|
||||
)
|
||||
|
||||
# Select mode for Sculpt
|
||||
if gpd.is_stroke_sculpt_mode:
|
||||
|
@ -687,7 +703,7 @@ class VIEW3D_HT_header(Header):
|
|||
row.prop(gpd, "use_multiedit", text="", icon='GP_MULTIFRAME_EDITING')
|
||||
|
||||
sub = row.row(align=True)
|
||||
sub.active = gpd.use_multiedit
|
||||
sub.enabled = gpd.use_multiedit
|
||||
sub.popover(
|
||||
panel="VIEW3D_PT_gpencil_multi_frame",
|
||||
text="Multiframe",
|
||||
|
@ -6802,6 +6818,12 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
|
|||
|
||||
layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True)
|
||||
|
||||
# Handles for Curve Edit
|
||||
if context.object.mode == 'EDIT_GPENCIL':
|
||||
gpd = context.object.data
|
||||
if gpd.use_curve_edit:
|
||||
layout.prop(overlay, "display_handle", text="Handles")
|
||||
|
||||
if context.object.mode in {'PAINT_GPENCIL', 'VERTEX_GPENCIL'}:
|
||||
layout.label(text="Vertex Paint")
|
||||
row = layout.row()
|
||||
|
@ -6965,6 +6987,24 @@ class VIEW3D_PT_gpencil_multi_frame(Panel):
|
|||
layout.template_curve_mapping(settings, "multiframe_falloff_curve", brush=True)
|
||||
|
||||
|
||||
# Grease Pencil Object - Curve Editing tools
|
||||
class VIEW3D_PT_gpencil_curve_edit(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'HEADER'
|
||||
bl_label = "Curve Editing"
|
||||
|
||||
def draw(self, context):
|
||||
gpd = context.gpencil_data
|
||||
settings = context.tool_settings.gpencil_sculpt
|
||||
|
||||
layout = self.layout
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "edit_curve_resolution")
|
||||
col.prop(gpd, "curve_edit_threshold")
|
||||
col.prop(gpd, "curve_edit_corner_angle")
|
||||
col.prop(gpd, "use_adaptive_curve_resolution")
|
||||
|
||||
|
||||
class VIEW3D_MT_gpencil_edit_context_menu(Menu):
|
||||
bl_label = ""
|
||||
|
||||
|
@ -7606,6 +7646,7 @@ classes = (
|
|||
VIEW3D_PT_grease_pencil,
|
||||
VIEW3D_PT_annotation_onion,
|
||||
VIEW3D_PT_gpencil_multi_frame,
|
||||
VIEW3D_PT_gpencil_curve_edit,
|
||||
VIEW3D_PT_quad_view,
|
||||
VIEW3D_PT_view3d_stereo,
|
||||
VIEW3D_PT_shading,
|
||||
|
|
|
@ -48,6 +48,7 @@ struct bGPDlayer;
|
|||
struct bGPDlayer_Mask;
|
||||
struct bGPDspoint;
|
||||
struct bGPDstroke;
|
||||
struct bGPDcurve;
|
||||
struct bGPdata;
|
||||
|
||||
#define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
|
||||
|
@ -89,6 +90,7 @@ struct bGPdata;
|
|||
|
||||
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
|
||||
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_free_stroke_editcurve(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
|
||||
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
|
||||
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
|
||||
|
@ -102,6 +104,7 @@ void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
|
|||
void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
|
||||
|
||||
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_curve_sync_selection(struct bGPDstroke *gps);
|
||||
|
||||
struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
|
||||
struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
|
||||
|
@ -111,7 +114,10 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]);
|
|||
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
|
||||
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
|
||||
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
|
||||
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points);
|
||||
struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
|
||||
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src,
|
||||
const bool dup_points,
|
||||
const bool dup_curve);
|
||||
|
||||
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain,
|
||||
const struct bGPdata *gpd,
|
||||
|
@ -160,6 +166,8 @@ struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf,
|
|||
int totpoints,
|
||||
short thickness);
|
||||
|
||||
struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points);
|
||||
|
||||
/* Stroke and Fill - Alpha Visibility Threshold */
|
||||
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
|
||||
#define GPENCIL_STRENGTH_MIN 0.003f
|
||||
|
@ -247,6 +255,7 @@ float BKE_gpencil_multiframe_falloff_calc(
|
|||
void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene);
|
||||
|
||||
bool BKE_gpencil_from_image(struct SpaceImage *sima,
|
||||
struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
const float size,
|
||||
const bool mask);
|
||||
|
|
|
@ -30,6 +30,10 @@ extern "C" {
|
|||
struct Main;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
struct bGPdata;
|
||||
struct bGPDlayer;
|
||||
struct bGPDstroke;
|
||||
struct bGPDcurve;
|
||||
|
||||
void BKE_gpencil_convert_curve(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
|
@ -39,6 +43,23 @@ void BKE_gpencil_convert_curve(struct Main *bmain,
|
|||
const float scale_thickness,
|
||||
const float sample);
|
||||
|
||||
struct bGPDcurve *BKE_gpencil_stroke_editcurve_generate(struct bGPDstroke *gps,
|
||||
const float error_threshold,
|
||||
const float corner_angle,
|
||||
const float stroke_radius);
|
||||
void BKE_gpencil_stroke_editcurve_update(struct bGPdata *gpd,
|
||||
struct bGPDlayer *gpl,
|
||||
struct bGPDstroke *gps);
|
||||
void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPDstroke *gps, struct bGPDcurve *gpc);
|
||||
void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPDstroke *gps, struct bGPDcurve *gpc);
|
||||
void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd);
|
||||
void BKE_gpencil_strokes_selected_sync_selection_editcurve(struct bGPdata *gpd);
|
||||
void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps,
|
||||
const uint resolution,
|
||||
const bool is_adaptive);
|
||||
void BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -51,11 +51,17 @@ void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps);
|
|||
|
||||
/* stroke geometry utilities */
|
||||
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
|
||||
void BKE_gpencil_stroke_simplify_adaptive(struct bGPDstroke *gps, float epsilon);
|
||||
void BKE_gpencil_stroke_simplify_fixed(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_subdivide(struct bGPDstroke *gps, int level, int type);
|
||||
bool BKE_gpencil_stroke_trim(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_merge_distance(struct bGPDframe *gpf,
|
||||
void BKE_gpencil_stroke_simplify_adaptive(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
float epsilon);
|
||||
void BKE_gpencil_stroke_simplify_fixed(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_subdivide(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
int level,
|
||||
int type);
|
||||
bool BKE_gpencil_stroke_trim(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
const float threshold,
|
||||
const bool use_unselected);
|
||||
|
@ -72,7 +78,7 @@ void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
|
|||
const float scale,
|
||||
int *r_direction);
|
||||
void BKE_gpencil_stroke_fill_triangulate(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_geometry_update(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps);
|
||||
|
||||
void BKE_gpencil_transform(struct bGPdata *gpd, const float mat[4][4]);
|
||||
|
@ -91,19 +97,26 @@ void BKE_gpencil_point_coords_apply_with_mat4(struct bGPdata *gpd,
|
|||
const GPencilPointCoordinates *elem_data,
|
||||
const float mat[4][4]);
|
||||
|
||||
bool BKE_gpencil_stroke_sample(struct bGPDstroke *gps, const float dist, const bool select);
|
||||
bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
|
||||
struct bGPDstroke *gps,
|
||||
const float dist,
|
||||
const bool select);
|
||||
bool BKE_gpencil_stroke_smooth(struct bGPDstroke *gps, int i, float inf);
|
||||
bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence);
|
||||
bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence);
|
||||
bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence);
|
||||
bool BKE_gpencil_stroke_close(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_dissolve_points(struct bGPDframe *gpf, struct bGPDstroke *gps, const short tag);
|
||||
void BKE_gpencil_dissolve_points(struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
const short tag);
|
||||
|
||||
bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps, const float dist, const float tip_length);
|
||||
bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps,
|
||||
const int index_from,
|
||||
const int index_to);
|
||||
bool BKE_gpencil_stroke_split(struct bGPDframe *gpf,
|
||||
bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
|
||||
struct bGPDframe *gpf,
|
||||
struct bGPDstroke *gps,
|
||||
const int before_index,
|
||||
struct bGPDstroke **remaining_gps);
|
||||
|
|
|
@ -155,6 +155,11 @@ static void greasepencil_blend_write(BlendWriter *writer, ID *id, const void *id
|
|||
BLO_write_struct_array(writer, bGPDspoint, gps->totpoints, gps->points);
|
||||
BLO_write_struct_array(writer, bGPDtriangle, gps->tot_triangles, gps->triangles);
|
||||
BKE_defvert_blend_write(writer, gps->totpoints, gps->dvert);
|
||||
if (gps->editcurve != NULL) {
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
BLO_write_struct(writer, bGPDcurve, gpc);
|
||||
BLO_write_struct_array(writer, bGPDcurve_point, gpc->tot_curve_points, gpc->curve_points);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,6 +227,13 @@ void BKE_gpencil_blend_read_data(BlendDataReader *reader, bGPdata *gpd)
|
|||
/* Relink geometry*/
|
||||
BLO_read_data_address(reader, &gps->triangles);
|
||||
|
||||
/* relink stroke edit curve. */
|
||||
BLO_read_data_address(reader, &gps->editcurve);
|
||||
if (gps->editcurve != NULL) {
|
||||
/* relink curve point array */
|
||||
BLO_read_data_address(reader, &gps->editcurve->curve_points);
|
||||
}
|
||||
|
||||
/* relink weight data */
|
||||
if (gps->dvert) {
|
||||
BLO_read_data_address(reader, &gps->dvert);
|
||||
|
@ -341,6 +353,20 @@ void BKE_gpencil_free_stroke_weights(bGPDstroke *gps)
|
|||
}
|
||||
}
|
||||
|
||||
void BKE_gpencil_free_stroke_editcurve(bGPDstroke *gps)
|
||||
{
|
||||
if (gps == NULL) {
|
||||
return;
|
||||
}
|
||||
bGPDcurve *editcurve = gps->editcurve;
|
||||
if (editcurve == NULL) {
|
||||
return;
|
||||
}
|
||||
MEM_freeN(editcurve->curve_points);
|
||||
MEM_freeN(editcurve);
|
||||
gps->editcurve = NULL;
|
||||
}
|
||||
|
||||
/* free stroke, doesn't unlink from any listbase */
|
||||
void BKE_gpencil_free_stroke(bGPDstroke *gps)
|
||||
{
|
||||
|
@ -358,6 +384,9 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
|
|||
if (gps->triangles) {
|
||||
MEM_freeN(gps->triangles);
|
||||
}
|
||||
if (gps->editcurve != NULL) {
|
||||
BKE_gpencil_free_stroke_editcurve(gps);
|
||||
}
|
||||
|
||||
MEM_freeN(gps);
|
||||
}
|
||||
|
@ -688,6 +717,13 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
|
|||
|
||||
gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
|
||||
|
||||
gpd->curve_edit_resolution = GP_DEFAULT_CURVE_RESOLUTION;
|
||||
gpd->curve_edit_threshold = GP_DEFAULT_CURVE_ERROR;
|
||||
gpd->curve_edit_corner_angle = GP_DEFAULT_CURVE_EDIT_CORNER_ANGLE;
|
||||
|
||||
/* use adaptive curve resolution by default */
|
||||
gpd->flag |= GP_DATA_CURVE_ADAPTIVE_RESOLUTION;
|
||||
|
||||
gpd->zdepth_offset = 0.150f;
|
||||
|
||||
/* grid settings */
|
||||
|
@ -776,6 +812,8 @@ bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
|
|||
|
||||
gps->mat_nr = mat_idx;
|
||||
|
||||
gps->editcurve = NULL;
|
||||
|
||||
return gps;
|
||||
}
|
||||
|
||||
|
@ -827,6 +865,16 @@ bGPDstroke *BKE_gpencil_stroke_add_existing_style(
|
|||
return gps;
|
||||
}
|
||||
|
||||
bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points)
|
||||
{
|
||||
bGPDcurve *new_gp_curve = (bGPDcurve *)MEM_callocN(sizeof(bGPDcurve), __func__);
|
||||
new_gp_curve->tot_curve_points = tot_curve_points;
|
||||
new_gp_curve->curve_points = (bGPDcurve_point *)MEM_callocN(
|
||||
sizeof(bGPDcurve_point) * tot_curve_points, __func__);
|
||||
|
||||
return new_gp_curve;
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
/* Data Duplication */
|
||||
|
||||
|
@ -845,13 +893,28 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d
|
|||
BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
|
||||
}
|
||||
|
||||
/* Make a copy of a given gpencil stroke editcurve */
|
||||
bGPDcurve *BKE_gpencil_stroke_curve_duplicate(bGPDcurve *gpc_src)
|
||||
{
|
||||
bGPDcurve *gpc_dst = MEM_dupallocN(gpc_src);
|
||||
|
||||
if (gpc_src->curve_points != NULL) {
|
||||
gpc_dst->curve_points = MEM_dupallocN(gpc_src->curve_points);
|
||||
}
|
||||
|
||||
return gpc_dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a copy of a given grease-pencil stroke.
|
||||
* \param gps_src: Source grease pencil strokes.
|
||||
* \param dup_points: Duplicate points data.
|
||||
* \param dup_curve: Duplicate curve data.
|
||||
* \return Pointer to new stroke.
|
||||
*/
|
||||
bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src, const bool dup_points)
|
||||
bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
|
||||
const bool dup_points,
|
||||
const bool dup_curve)
|
||||
{
|
||||
bGPDstroke *gps_dst = NULL;
|
||||
|
||||
|
@ -871,6 +934,10 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src, const bool dup_poi
|
|||
}
|
||||
}
|
||||
|
||||
if (dup_curve && gps_src->editcurve != NULL) {
|
||||
gps_dst->editcurve = BKE_gpencil_stroke_curve_duplicate(gps_src->editcurve);
|
||||
}
|
||||
|
||||
/* return new stroke */
|
||||
return gps_dst;
|
||||
}
|
||||
|
@ -898,7 +965,7 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
|
|||
BLI_listbase_clear(&gpf_dst->strokes);
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
|
||||
/* make copy of source stroke */
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
|
||||
BLI_addtail(&gpf_dst->strokes, gps_dst);
|
||||
}
|
||||
|
||||
|
@ -923,7 +990,7 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
|
|||
BLI_listbase_clear(&gpf_dst->strokes);
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
|
||||
/* make copy of source stroke */
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
|
||||
BLI_addtail(&gpf_dst->strokes, gps_dst);
|
||||
}
|
||||
}
|
||||
|
@ -1037,6 +1104,39 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
|
|||
}
|
||||
}
|
||||
|
||||
void BKE_gpencil_curve_sync_selection(bGPDstroke *gps)
|
||||
{
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
if (gpc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
gpc->flag &= ~GP_CURVE_SELECT;
|
||||
|
||||
bool is_selected = false;
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
|
||||
if (BEZT_ISSEL_ANY(bezt)) {
|
||||
gpc_pt->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
else {
|
||||
gpc_pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
if (gpc_pt->flag & GP_SPOINT_SELECT) {
|
||||
is_selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_selected) {
|
||||
gpc->flag |= GP_CURVE_SELECT;
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************** */
|
||||
/* GP Frame API */
|
||||
|
||||
|
@ -2304,12 +2404,14 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
|
|||
/**
|
||||
* Create grease pencil strokes from image
|
||||
* \param sima: Image
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gpf: Grease pencil frame
|
||||
* \param size: Size
|
||||
* \param mask: Mask
|
||||
* \return True if done
|
||||
*/
|
||||
bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size, const bool mask)
|
||||
bool BKE_gpencil_from_image(
|
||||
SpaceImage *sima, bGPdata *gpd, bGPDframe *gpf, const float size, const bool mask)
|
||||
{
|
||||
Image *image = sima->image;
|
||||
bool done = false;
|
||||
|
@ -2357,7 +2459,7 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size,
|
|||
pt->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,8 +37,10 @@
|
|||
#include "BLT_translation.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_gpencil_curve.h"
|
||||
|
@ -47,8 +49,16 @@
|
|||
#include "BKE_material.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "curve_fit_nd.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#define COORD_FITTING_INFLUENCE 20.0f
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Convert to curve object
|
||||
* \{ */
|
||||
|
||||
/* Helper: Check materials with same color. */
|
||||
static int gpencil_check_same_material_color(Object *ob_gp,
|
||||
const float color_stroke[4],
|
||||
|
@ -295,6 +305,7 @@ static void gpencil_convert_spline(Main *bmain,
|
|||
bGPDframe *gpf,
|
||||
Nurb *nu)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob_gp->data;
|
||||
bool cyclic = true;
|
||||
|
||||
/* Create Stroke. */
|
||||
|
@ -445,11 +456,22 @@ static void gpencil_convert_spline(Main *bmain,
|
|||
}
|
||||
|
||||
if (sample > 0.0f) {
|
||||
BKE_gpencil_stroke_sample(gps, sample, false);
|
||||
BKE_gpencil_stroke_sample(gpd, gps, sample, false);
|
||||
}
|
||||
|
||||
/* Recalc fill geometry. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
static void gpencil_editstroke_deselect_all(bGPDcurve *gpc)
|
||||
{
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
|
||||
BEZT_DESEL_ALL(bezt);
|
||||
}
|
||||
gpc->flag &= ~GP_CURVE_SELECT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -536,3 +558,851 @@ void BKE_gpencil_convert_curve(Main *bmain,
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Editcurve kernel functions
|
||||
* \{ */
|
||||
|
||||
static bGPDcurve *gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps,
|
||||
const float stroke_radius)
|
||||
{
|
||||
BLI_assert(gps->totpoints < 3);
|
||||
|
||||
if (gps->totpoints == 1) {
|
||||
bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(1);
|
||||
bGPDspoint *pt = &gps->points[0];
|
||||
bGPDcurve_point *cpt = &editcurve->curve_points[0];
|
||||
BezTriple *bezt = &cpt->bezt;
|
||||
|
||||
/* Handles are twice as long as the radius of the point. */
|
||||
float offset = (pt->pressure * stroke_radius) * 2.0f;
|
||||
|
||||
float tmp_vec[3];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
copy_v3_v3(tmp_vec, &pt->x);
|
||||
/* Move handles along the x-axis away from the control point */
|
||||
tmp_vec[0] += (float)(j - 1) * offset;
|
||||
copy_v3_v3(bezt->vec[j], tmp_vec);
|
||||
}
|
||||
|
||||
cpt->pressure = pt->pressure;
|
||||
cpt->strength = pt->strength;
|
||||
copy_v4_v4(cpt->vert_color, pt->vert_color);
|
||||
|
||||
/* default handle type */
|
||||
bezt->h1 = HD_FREE;
|
||||
bezt->h2 = HD_FREE;
|
||||
|
||||
cpt->point_index = 0;
|
||||
|
||||
return editcurve;
|
||||
}
|
||||
if (gps->totpoints == 2) {
|
||||
bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(2);
|
||||
bGPDspoint *first_pt = &gps->points[0];
|
||||
bGPDspoint *last_pt = &gps->points[1];
|
||||
|
||||
float length = len_v3v3(&first_pt->x, &last_pt->x);
|
||||
float offset = length / 3;
|
||||
float dir[3];
|
||||
sub_v3_v3v3(dir, &last_pt->x, &first_pt->x);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
bGPDcurve_point *cpt = &editcurve->curve_points[i];
|
||||
BezTriple *bezt = &cpt->bezt;
|
||||
|
||||
float tmp_vec[3];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
copy_v3_v3(tmp_vec, dir);
|
||||
normalize_v3_length(tmp_vec, (float)(j - 1) * offset);
|
||||
add_v3_v3v3(bezt->vec[j], &pt->x, tmp_vec);
|
||||
}
|
||||
|
||||
cpt->pressure = pt->pressure;
|
||||
cpt->strength = pt->strength;
|
||||
copy_v4_v4(cpt->vert_color, pt->vert_color);
|
||||
|
||||
/* default handle type */
|
||||
bezt->h1 = HD_VECT;
|
||||
bezt->h2 = HD_VECT;
|
||||
|
||||
cpt->point_index = 0;
|
||||
}
|
||||
|
||||
return editcurve;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
|
||||
*/
|
||||
bGPDcurve *BKE_gpencil_stroke_editcurve_generate(bGPDstroke *gps,
|
||||
const float error_threshold,
|
||||
const float corner_angle,
|
||||
const float stroke_radius)
|
||||
{
|
||||
if (gps->totpoints < 3) {
|
||||
return gpencil_stroke_editcurve_generate_edgecases(gps, stroke_radius);
|
||||
}
|
||||
#define POINT_DIM 9
|
||||
|
||||
float *points = MEM_callocN(sizeof(float) * gps->totpoints * POINT_DIM, __func__);
|
||||
float diag_length = len_v3v3(gps->boundbox_min, gps->boundbox_max);
|
||||
float tmp_vec[3];
|
||||
|
||||
for (int i = 0; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
int row = i * POINT_DIM;
|
||||
|
||||
/* normalize coordinate to 0..1 */
|
||||
sub_v3_v3v3(tmp_vec, &pt->x, gps->boundbox_min);
|
||||
mul_v3_v3fl(&points[row], tmp_vec, COORD_FITTING_INFLUENCE / diag_length);
|
||||
points[row + 3] = pt->pressure / diag_length;
|
||||
|
||||
/* strength and color are already normalized */
|
||||
points[row + 4] = pt->strength / diag_length;
|
||||
mul_v4_v4fl(&points[row + 5], pt->vert_color, 1.0f / diag_length);
|
||||
}
|
||||
|
||||
uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
|
||||
if (gps->totpoints > 2 && gps->flag & GP_STROKE_CYCLIC) {
|
||||
calc_flag |= CURVE_FIT_CALC_CYCLIC;
|
||||
}
|
||||
|
||||
float *r_cubic_array = NULL;
|
||||
unsigned int r_cubic_array_len = 0;
|
||||
unsigned int *r_cubic_orig_index = NULL;
|
||||
unsigned int *r_corners_index_array = NULL;
|
||||
unsigned int r_corners_index_len = 0;
|
||||
int r = curve_fit_cubic_to_points_refit_fl(points,
|
||||
gps->totpoints,
|
||||
POINT_DIM,
|
||||
error_threshold,
|
||||
calc_flag,
|
||||
NULL,
|
||||
0,
|
||||
corner_angle,
|
||||
&r_cubic_array,
|
||||
&r_cubic_array_len,
|
||||
&r_cubic_orig_index,
|
||||
&r_corners_index_array,
|
||||
&r_corners_index_len);
|
||||
|
||||
if (r != 0 || r_cubic_array_len < 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint curve_point_size = 3 * POINT_DIM;
|
||||
|
||||
bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_new(r_cubic_array_len);
|
||||
|
||||
for (int i = 0; i < r_cubic_array_len; i++) {
|
||||
bGPDcurve_point *cpt = &editcurve->curve_points[i];
|
||||
BezTriple *bezt = &cpt->bezt;
|
||||
float *curve_point = &r_cubic_array[i * curve_point_size];
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
float *bez = &curve_point[j * POINT_DIM];
|
||||
madd_v3_v3v3fl(bezt->vec[j], gps->boundbox_min, bez, diag_length / COORD_FITTING_INFLUENCE);
|
||||
}
|
||||
|
||||
float *ctrl_point = &curve_point[1 * POINT_DIM];
|
||||
cpt->pressure = ctrl_point[3] * diag_length;
|
||||
cpt->strength = ctrl_point[4] * diag_length;
|
||||
mul_v4_v4fl(cpt->vert_color, &ctrl_point[5], diag_length);
|
||||
|
||||
/* default handle type */
|
||||
bezt->h1 = HD_ALIGN;
|
||||
bezt->h2 = HD_ALIGN;
|
||||
|
||||
cpt->point_index = r_cubic_orig_index[i];
|
||||
}
|
||||
|
||||
if (r_corners_index_len > 0 && r_corners_index_array != NULL) {
|
||||
int start = 0, end = r_corners_index_len;
|
||||
if ((r_corners_index_len > 1) && (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) {
|
||||
start = 1;
|
||||
end = r_corners_index_len - 1;
|
||||
}
|
||||
for (int i = start; i < end; i++) {
|
||||
bGPDcurve_point *cpt = &editcurve->curve_points[r_corners_index_array[i]];
|
||||
BezTriple *bezt = &cpt->bezt;
|
||||
bezt->h1 = HD_FREE;
|
||||
bezt->h2 = HD_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(points);
|
||||
if (r_cubic_array) {
|
||||
free(r_cubic_array);
|
||||
}
|
||||
if (r_corners_index_array) {
|
||||
free(r_corners_index_array);
|
||||
}
|
||||
if (r_cubic_orig_index) {
|
||||
free(r_cubic_orig_index);
|
||||
}
|
||||
|
||||
#undef POINT_DIM
|
||||
return editcurve;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the editcurve for a stroke. Frees the old curve if one exists and generates a new one.
|
||||
*/
|
||||
void BKE_gpencil_stroke_editcurve_update(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
|
||||
{
|
||||
if (gps == NULL || gps->totpoints < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gps->editcurve != NULL) {
|
||||
BKE_gpencil_free_stroke_editcurve(gps);
|
||||
}
|
||||
|
||||
float defaultpixsize = 1000.0f / gpd->pixfactor;
|
||||
float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f;
|
||||
|
||||
bGPDcurve *editcurve = BKE_gpencil_stroke_editcurve_generate(
|
||||
gps, gpd->curve_edit_threshold, gpd->curve_edit_corner_angle, stroke_radius);
|
||||
if (editcurve == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
gps->editcurve = editcurve;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync the selection from stroke to editcurve
|
||||
*/
|
||||
void BKE_gpencil_editcurve_stroke_sync_selection(bGPDstroke *gps, bGPDcurve *gpc)
|
||||
{
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
gpc->flag |= GP_CURVE_SELECT;
|
||||
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
bGPDspoint *pt = &gps->points[gpc_pt->point_index];
|
||||
if (pt->flag & GP_SPOINT_SELECT) {
|
||||
gpc_pt->flag |= GP_CURVE_POINT_SELECT;
|
||||
BEZT_SEL_ALL(&gpc_pt->bezt);
|
||||
}
|
||||
else {
|
||||
gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
|
||||
BEZT_DESEL_ALL(&gpc_pt->bezt);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
gpc->flag &= ~GP_CURVE_SELECT;
|
||||
gpencil_editstroke_deselect_all(gpc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync the selection from editcurve to stroke
|
||||
*/
|
||||
void BKE_gpencil_stroke_editcurve_sync_selection(bGPDstroke *gps, bGPDcurve *gpc)
|
||||
{
|
||||
if (gpc->flag & GP_CURVE_SELECT) {
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
|
||||
for (int i = 0; i < gpc->tot_curve_points - 1; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
bGPDspoint *pt = &gps->points[gpc_pt->point_index];
|
||||
bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + 1];
|
||||
|
||||
if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
if (gpc_pt_next->flag & GP_CURVE_POINT_SELECT) {
|
||||
/* select all the points after */
|
||||
for (int j = gpc_pt->point_index + 1; j < gpc_pt_next->point_index; j++) {
|
||||
bGPDspoint *pt_next = &gps->points[j];
|
||||
pt_next->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
/* deselect all points after */
|
||||
for (int j = gpc_pt->point_index + 1; j < gpc_pt_next->point_index; j++) {
|
||||
bGPDspoint *pt_next = &gps->points[j];
|
||||
pt_next->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bGPDcurve_point *gpc_first = &gpc->curve_points[0];
|
||||
bGPDcurve_point *gpc_last = &gpc->curve_points[gpc->tot_curve_points - 1];
|
||||
bGPDspoint *last_pt = &gps->points[gpc_last->point_index];
|
||||
if (gpc_last->flag & GP_CURVE_POINT_SELECT) {
|
||||
last_pt->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
else {
|
||||
last_pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
if (gps->flag & GP_STROKE_CYCLIC) {
|
||||
if (gpc_first->flag & GP_CURVE_POINT_SELECT && gpc_last->flag & GP_CURVE_POINT_SELECT) {
|
||||
for (int i = gpc_last->point_index + 1; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt_next = &gps->points[i];
|
||||
pt_next->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = gpc_last->point_index + 1; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt_next = &gps->points[i];
|
||||
pt_next->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
for (int i = 0; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_interpolate_fl_from_to(
|
||||
float from, float to, float *point_offset, int it, int stride)
|
||||
{
|
||||
/* smooth interpolation */
|
||||
float *r = point_offset;
|
||||
for (int i = 0; i <= it; i++) {
|
||||
float fac = (float)i / (float)it;
|
||||
fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; // smooth
|
||||
*r = interpf(to, from, fac);
|
||||
r = POINTER_OFFSET(r, stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_interpolate_v4_from_to(
|
||||
float from[4], float to[4], float *point_offset, int it, int stride)
|
||||
{
|
||||
/* smooth interpolation */
|
||||
float *r = point_offset;
|
||||
for (int i = 0; i <= it; i++) {
|
||||
float fac = (float)i / (float)it;
|
||||
fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; // smooth
|
||||
interp_v4_v4v4(r, from, to, fac);
|
||||
r = POINTER_OFFSET(r, stride);
|
||||
}
|
||||
}
|
||||
|
||||
static float gpencil_approximate_curve_segment_arclength(bGPDcurve_point *cpt_start,
|
||||
bGPDcurve_point *cpt_end)
|
||||
{
|
||||
BezTriple *bezt_start = &cpt_start->bezt;
|
||||
BezTriple *bezt_end = &cpt_end->bezt;
|
||||
|
||||
float chord_len = len_v3v3(bezt_start->vec[1], bezt_end->vec[1]);
|
||||
float net_len = len_v3v3(bezt_start->vec[1], bezt_start->vec[2]);
|
||||
net_len += len_v3v3(bezt_start->vec[2], bezt_end->vec[0]);
|
||||
net_len += len_v3v3(bezt_end->vec[0], bezt_end->vec[1]);
|
||||
|
||||
return (chord_len + net_len) / 2.0f;
|
||||
}
|
||||
|
||||
static void gpencil_calculate_stroke_points_curve_segment(
|
||||
bGPDcurve_point *cpt, bGPDcurve_point *cpt_next, float *points_offset, int resolu, int stride)
|
||||
{
|
||||
/* sample points on all 3 axis between two curve points */
|
||||
for (uint axis = 0; axis < 3; axis++) {
|
||||
BKE_curve_forward_diff_bezier(cpt->bezt.vec[1][axis],
|
||||
cpt->bezt.vec[2][axis],
|
||||
cpt_next->bezt.vec[0][axis],
|
||||
cpt_next->bezt.vec[1][axis],
|
||||
POINTER_OFFSET(points_offset, sizeof(float) * axis),
|
||||
(int)resolu,
|
||||
stride);
|
||||
}
|
||||
|
||||
/* interpolate other attributes */
|
||||
gpencil_interpolate_fl_from_to(cpt->pressure,
|
||||
cpt_next->pressure,
|
||||
POINTER_OFFSET(points_offset, sizeof(float) * 3),
|
||||
resolu,
|
||||
stride);
|
||||
gpencil_interpolate_fl_from_to(cpt->strength,
|
||||
cpt_next->strength,
|
||||
POINTER_OFFSET(points_offset, sizeof(float) * 4),
|
||||
resolu,
|
||||
stride);
|
||||
gpencil_interpolate_v4_from_to(cpt->vert_color,
|
||||
cpt_next->vert_color,
|
||||
POINTER_OFFSET(points_offset, sizeof(float) * 5),
|
||||
resolu,
|
||||
stride);
|
||||
}
|
||||
|
||||
static float *gpencil_stroke_points_from_editcurve_adaptive_resolu(
|
||||
bGPDcurve_point *curve_point_array,
|
||||
int curve_point_array_len,
|
||||
int resolution,
|
||||
bool is_cyclic,
|
||||
int *r_points_len)
|
||||
{
|
||||
/* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */
|
||||
const uint stride = sizeof(float[9]);
|
||||
const uint cpt_last = curve_point_array_len - 1;
|
||||
const uint num_segments = (is_cyclic) ? curve_point_array_len : curve_point_array_len - 1;
|
||||
int *segment_point_lengths = MEM_callocN(sizeof(int) * num_segments, __func__);
|
||||
|
||||
uint points_len = 1;
|
||||
for (int i = 0; i < cpt_last; i++) {
|
||||
bGPDcurve_point *cpt = &curve_point_array[i];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
|
||||
float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
|
||||
int segment_resolu = (int)floorf(arclen * resolution);
|
||||
CLAMP_MIN(segment_resolu, 1);
|
||||
|
||||
segment_point_lengths[i] = segment_resolu;
|
||||
points_len += segment_resolu;
|
||||
}
|
||||
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt = &curve_point_array[cpt_last];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[0];
|
||||
float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next);
|
||||
int segment_resolu = (int)floorf(arclen * resolution);
|
||||
CLAMP_MIN(segment_resolu, 1);
|
||||
|
||||
segment_point_lengths[cpt_last] = segment_resolu;
|
||||
points_len += segment_resolu;
|
||||
}
|
||||
|
||||
float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__);
|
||||
float *points_offset = &r_points[0][0];
|
||||
int point_index = 0;
|
||||
for (int i = 0; i < cpt_last; i++) {
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[i];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
|
||||
int segment_resolu = segment_point_lengths[i];
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, segment_resolu, stride);
|
||||
/* update the index */
|
||||
cpt_curr->point_index = point_index;
|
||||
point_index += segment_resolu;
|
||||
points_offset = POINTER_OFFSET(points_offset, segment_resolu * stride);
|
||||
}
|
||||
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[cpt_last];
|
||||
cpt_curr->point_index = point_index;
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[0];
|
||||
int segment_resolu = segment_point_lengths[cpt_last];
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, segment_resolu, stride);
|
||||
}
|
||||
|
||||
MEM_freeN(segment_point_lengths);
|
||||
|
||||
*r_points_len = points_len;
|
||||
return (float(*))r_points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: calculate the points on a curve with a fixed resolution.
|
||||
*/
|
||||
static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point *curve_point_array,
|
||||
int curve_point_array_len,
|
||||
int resolution,
|
||||
bool is_cyclic,
|
||||
int *r_points_len)
|
||||
{
|
||||
/* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */
|
||||
const uint stride = sizeof(float[9]);
|
||||
const uint array_last = curve_point_array_len - 1;
|
||||
const uint resolu_stride = resolution * stride;
|
||||
const uint points_len = BKE_curve_calc_coords_axis_len(
|
||||
curve_point_array_len, resolution, is_cyclic, false);
|
||||
|
||||
float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__);
|
||||
float *points_offset = &r_points[0][0];
|
||||
for (unsigned int i = 0; i < array_last; i++) {
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[i];
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[i + 1];
|
||||
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, resolution, stride);
|
||||
/* update the index */
|
||||
cpt_curr->point_index = i * resolution;
|
||||
points_offset = POINTER_OFFSET(points_offset, resolu_stride);
|
||||
}
|
||||
|
||||
bGPDcurve_point *cpt_curr = &curve_point_array[array_last];
|
||||
cpt_curr->point_index = array_last * resolution;
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt_next = &curve_point_array[0];
|
||||
gpencil_calculate_stroke_points_curve_segment(
|
||||
cpt_curr, cpt_next, points_offset, resolution, stride);
|
||||
}
|
||||
|
||||
*r_points_len = points_len;
|
||||
return (float(*))r_points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate stroke points with the editcurve of the stroke.
|
||||
*/
|
||||
void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps,
|
||||
const uint resolution,
|
||||
const bool adaptive)
|
||||
{
|
||||
if (gps == NULL || gps->editcurve == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bGPDcurve *editcurve = gps->editcurve;
|
||||
bGPDcurve_point *curve_point_array = editcurve->curve_points;
|
||||
int curve_point_array_len = editcurve->tot_curve_points;
|
||||
if (curve_point_array_len == 0) {
|
||||
return;
|
||||
}
|
||||
/* Handle case for single curve point. */
|
||||
if (curve_point_array_len == 1) {
|
||||
bGPDcurve_point *cpt = &curve_point_array[0];
|
||||
/* resize stroke point array */
|
||||
gps->totpoints = 1;
|
||||
gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints);
|
||||
if (gps->dvert != NULL) {
|
||||
gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints);
|
||||
}
|
||||
|
||||
bGPDspoint *pt = &gps->points[0];
|
||||
copy_v3_v3(&pt->x, cpt->bezt.vec[1]);
|
||||
|
||||
pt->pressure = cpt->pressure;
|
||||
pt->strength = cpt->strength;
|
||||
|
||||
copy_v4_v4(pt->vert_color, cpt->vert_color);
|
||||
|
||||
/* deselect */
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
|
||||
|
||||
int points_len = 0;
|
||||
float(*points)[9] = NULL;
|
||||
if (adaptive) {
|
||||
points = (float(*)[9])gpencil_stroke_points_from_editcurve_adaptive_resolu(
|
||||
curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
|
||||
}
|
||||
else {
|
||||
points = (float(*)[9])gpencil_stroke_points_from_editcurve_fixed_resolu(
|
||||
curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len);
|
||||
}
|
||||
|
||||
if (points == NULL || points_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* resize stroke point array */
|
||||
gps->totpoints = points_len;
|
||||
gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints);
|
||||
if (gps->dvert != NULL) {
|
||||
gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints);
|
||||
}
|
||||
|
||||
/* write new data to stroke point array */
|
||||
for (int i = 0; i < points_len; i++) {
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
copy_v3_v3(&pt->x, &points[i][0]);
|
||||
|
||||
pt->pressure = points[i][3];
|
||||
pt->strength = points[i][4];
|
||||
|
||||
copy_v4_v4(pt->vert_color, &points[i][5]);
|
||||
|
||||
/* deselect points */
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
|
||||
/* free temp data */
|
||||
MEM_freeN(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate the handles of the edit curve of a grease pencil stroke
|
||||
*/
|
||||
void BKE_gpencil_editcurve_recalculate_handles(bGPDstroke *gps)
|
||||
{
|
||||
if (gps == NULL || gps->editcurve == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
if (gpc->tot_curve_points < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpc->tot_curve_points == 1) {
|
||||
BKE_nurb_handle_calc(
|
||||
&(gpc->curve_points[0].bezt), NULL, &(gpc->curve_points[0].bezt), false, 0);
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
}
|
||||
|
||||
for (int i = 1; i < gpc->tot_curve_points - 1; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
bGPDcurve_point *gpc_pt_prev = &gpc->curve_points[i - 1];
|
||||
bGPDcurve_point *gpc_pt_next = &gpc->curve_points[i + 1];
|
||||
/* update handle if point or neighbour is selected */
|
||||
if (gpc_pt->flag & GP_CURVE_POINT_SELECT || gpc_pt_prev->flag & GP_CURVE_POINT_SELECT ||
|
||||
gpc_pt_next->flag & GP_CURVE_POINT_SELECT) {
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
BezTriple *bezt_prev = &gpc_pt_prev->bezt;
|
||||
BezTriple *bezt_next = &gpc_pt_next->bezt;
|
||||
|
||||
BKE_nurb_handle_calc(bezt, bezt_prev, bezt_next, false, 0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bGPDcurve_point *gpc_first = &gpc->curve_points[0];
|
||||
bGPDcurve_point *gpc_last = &gpc->curve_points[gpc->tot_curve_points - 1];
|
||||
bGPDcurve_point *gpc_first_next = &gpc->curve_points[1];
|
||||
bGPDcurve_point *gpc_last_prev = &gpc->curve_points[gpc->tot_curve_points - 2];
|
||||
if (gps->flag & GP_STROKE_CYCLIC) {
|
||||
if (gpc_first->flag & GP_CURVE_POINT_SELECT || gpc_last->flag & GP_CURVE_POINT_SELECT) {
|
||||
BezTriple *bezt_first = &gpc_first->bezt;
|
||||
BezTriple *bezt_last = &gpc_last->bezt;
|
||||
BezTriple *bezt_first_next = &gpc_first_next->bezt;
|
||||
BezTriple *bezt_last_prev = &gpc_last_prev->bezt;
|
||||
|
||||
BKE_nurb_handle_calc(bezt_first, bezt_last, bezt_first_next, false, 0);
|
||||
BKE_nurb_handle_calc(bezt_last, bezt_last_prev, bezt_first, false, 0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gpc_first->flag & GP_CURVE_POINT_SELECT || gpc_last->flag & GP_CURVE_POINT_SELECT) {
|
||||
BezTriple *bezt_first = &gpc_first->bezt;
|
||||
BezTriple *bezt_last = &gpc_last->bezt;
|
||||
BezTriple *bezt_first_next = &gpc_first_next->bezt;
|
||||
BezTriple *bezt_last_prev = &gpc_last_prev->bezt;
|
||||
|
||||
BKE_nurb_handle_calc(bezt_first, NULL, bezt_first_next, false, 0);
|
||||
BKE_nurb_handle_calc(bezt_last, bezt_last_prev, NULL, false, 0);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper: count how many new curve points must be generated. */
|
||||
static int gpencil_editcurve_subdivide_count(bGPDcurve *gpc, bool is_cyclic)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < gpc->tot_curve_points - 1; i++) {
|
||||
bGPDcurve_point *cpt = &gpc->curve_points[i];
|
||||
bGPDcurve_point *cpt_next = &gpc->curve_points[i + 1];
|
||||
|
||||
if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt = &gpc->curve_points[0];
|
||||
bGPDcurve_point *cpt_next = &gpc->curve_points[gpc->tot_curve_points - 1];
|
||||
|
||||
if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void gpencil_editcurve_subdivide_curve_segment(bGPDcurve_point *cpt_start,
|
||||
bGPDcurve_point *cpt_end,
|
||||
bGPDcurve_point *cpt_new)
|
||||
{
|
||||
BezTriple *bezt_start = &cpt_start->bezt;
|
||||
BezTriple *bezt_end = &cpt_end->bezt;
|
||||
BezTriple *bezt_new = &cpt_new->bezt;
|
||||
for (int axis = 0; axis < 3; axis++) {
|
||||
float p0, p1, p2, p3, m0, m1, q0, q1, b;
|
||||
p0 = bezt_start->vec[1][axis];
|
||||
p1 = bezt_start->vec[2][axis];
|
||||
p2 = bezt_end->vec[0][axis];
|
||||
p3 = bezt_end->vec[1][axis];
|
||||
|
||||
m0 = (p0 + p1) / 2;
|
||||
q0 = (p0 + 2 * p1 + p2) / 4;
|
||||
b = (p0 + 3 * p1 + 3 * p2 + p3) / 8;
|
||||
q1 = (p1 + 2 * p2 + p3) / 4;
|
||||
m1 = (p2 + p3) / 2;
|
||||
|
||||
bezt_new->vec[0][axis] = q0;
|
||||
bezt_new->vec[2][axis] = q1;
|
||||
bezt_new->vec[1][axis] = b;
|
||||
|
||||
bezt_start->vec[2][axis] = m0;
|
||||
bezt_end->vec[0][axis] = m1;
|
||||
}
|
||||
|
||||
cpt_new->pressure = interpf(cpt_end->pressure, cpt_start->pressure, 0.5f);
|
||||
cpt_new->strength = interpf(cpt_end->strength, cpt_start->strength, 0.5f);
|
||||
interp_v4_v4v4(cpt_new->vert_color, cpt_start->vert_color, cpt_end->vert_color, 0.5f);
|
||||
}
|
||||
|
||||
void BKE_gpencil_editcurve_subdivide(bGPDstroke *gps, const int cuts)
|
||||
{
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
if (gpc == NULL || gpc->tot_curve_points < 2) {
|
||||
return;
|
||||
}
|
||||
bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
|
||||
|
||||
/* repeat for number of cuts */
|
||||
for (int s = 0; s < cuts; s++) {
|
||||
int old_tot_curve_points = gpc->tot_curve_points;
|
||||
int new_num_curve_points = gpencil_editcurve_subdivide_count(gpc, is_cyclic);
|
||||
if (new_num_curve_points == 0) {
|
||||
break;
|
||||
}
|
||||
int new_tot_curve_points = old_tot_curve_points + new_num_curve_points;
|
||||
|
||||
bGPDcurve_point *temp_curve_points = (bGPDcurve_point *)MEM_callocN(
|
||||
sizeof(bGPDcurve_point) * new_tot_curve_points, __func__);
|
||||
|
||||
bool prev_subdivided = false;
|
||||
int j = 0;
|
||||
for (int i = 0; i < old_tot_curve_points - 1; i++, j++) {
|
||||
bGPDcurve_point *cpt = &gpc->curve_points[i];
|
||||
bGPDcurve_point *cpt_next = &gpc->curve_points[i + 1];
|
||||
|
||||
if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
|
||||
bGPDcurve_point *cpt_new = &temp_curve_points[j + 1];
|
||||
gpencil_editcurve_subdivide_curve_segment(cpt, cpt_next, cpt_new);
|
||||
|
||||
memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
|
||||
memcpy(&temp_curve_points[j + 2], cpt_next, sizeof(bGPDcurve_point));
|
||||
|
||||
cpt_new->flag |= GP_CURVE_POINT_SELECT;
|
||||
cpt_new->bezt.h1 = HD_ALIGN;
|
||||
cpt_new->bezt.h2 = HD_ALIGN;
|
||||
BEZT_SEL_ALL(&cpt_new->bezt);
|
||||
|
||||
prev_subdivided = true;
|
||||
j++;
|
||||
}
|
||||
else if (!prev_subdivided) {
|
||||
memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
|
||||
prev_subdivided = false;
|
||||
}
|
||||
else {
|
||||
prev_subdivided = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_cyclic) {
|
||||
bGPDcurve_point *cpt = &gpc->curve_points[old_tot_curve_points - 1];
|
||||
bGPDcurve_point *cpt_next = &gpc->curve_points[0];
|
||||
|
||||
if (cpt->flag & GP_CURVE_POINT_SELECT && cpt_next->flag & GP_CURVE_POINT_SELECT) {
|
||||
bGPDcurve_point *cpt_new = &temp_curve_points[j + 1];
|
||||
gpencil_editcurve_subdivide_curve_segment(cpt, cpt_next, cpt_new);
|
||||
|
||||
memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
|
||||
memcpy(&temp_curve_points[0], cpt_next, sizeof(bGPDcurve_point));
|
||||
|
||||
cpt_new->flag |= GP_CURVE_POINT_SELECT;
|
||||
cpt_new->bezt.h1 = HD_ALIGN;
|
||||
cpt_new->bezt.h2 = HD_ALIGN;
|
||||
BEZT_SEL_ALL(&cpt_new->bezt);
|
||||
}
|
||||
else if (!prev_subdivided) {
|
||||
memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
|
||||
}
|
||||
}
|
||||
else {
|
||||
bGPDcurve_point *cpt = &gpc->curve_points[old_tot_curve_points - 1];
|
||||
memcpy(&temp_curve_points[j], cpt, sizeof(bGPDcurve_point));
|
||||
}
|
||||
|
||||
MEM_freeN(gpc->curve_points);
|
||||
gpc->curve_points = temp_curve_points;
|
||||
gpc->tot_curve_points = new_tot_curve_points;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_gpencil_strokes_selected_update_editcurve(bGPdata *gpd)
|
||||
{
|
||||
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
|
||||
/* For all selected strokes, update edit curve. */
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
if (!BKE_gpencil_layer_is_editable(gpl)) {
|
||||
continue;
|
||||
}
|
||||
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
|
||||
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
|
||||
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && is_multiedit)) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
/* skip deselected stroke */
|
||||
if (!(gps->flag & GP_STROKE_SELECT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Generate the curve if there is none or the stroke was changed */
|
||||
if (gps->editcurve == NULL) {
|
||||
BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
|
||||
/* Continue if curve could not be generated. */
|
||||
if (gps->editcurve == NULL) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (gps->editcurve->flag & GP_CURVE_NEEDS_STROKE_UPDATE) {
|
||||
BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
|
||||
}
|
||||
/* Update the selection from the stroke to the curve. */
|
||||
BKE_gpencil_editcurve_stroke_sync_selection(gps, gps->editcurve);
|
||||
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_gpencil_strokes_selected_sync_selection_editcurve(bGPdata *gpd)
|
||||
{
|
||||
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
|
||||
/* Sync selection for all strokes with editcurve. */
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
if (!BKE_gpencil_layer_is_editable(gpl)) {
|
||||
continue;
|
||||
}
|
||||
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
|
||||
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
|
||||
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && is_multiedit)) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
if (gpc != NULL) {
|
||||
/* Update the selection of every stroke that has an editcurve */
|
||||
BKE_gpencil_stroke_editcurve_sync_selection(gps, gpc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -45,8 +45,11 @@
|
|||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_gpencil_curve.h"
|
||||
#include "BKE_gpencil_geom.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
|
@ -415,10 +418,11 @@ static void stroke_interpolate_deform_weights(
|
|||
|
||||
/**
|
||||
* Resample a stroke
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Stroke to sample
|
||||
* \param dist: Distance of one segment
|
||||
*/
|
||||
bool BKE_gpencil_stroke_sample(bGPDstroke *gps, const float dist, const bool select)
|
||||
bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, const bool select)
|
||||
{
|
||||
bGPDspoint *pt = gps->points;
|
||||
bGPDspoint *pt1 = NULL;
|
||||
|
@ -515,7 +519,7 @@ bool BKE_gpencil_stroke_sample(bGPDstroke *gps, const float dist, const bool sel
|
|||
gps->totpoints = i;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -628,13 +632,15 @@ bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const
|
|||
|
||||
/**
|
||||
* Split stroke.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gpf: Grease pencil frame
|
||||
* \param gps: Grease pencil original stroke
|
||||
* \param before_index: Position of the point to split
|
||||
* \param remaining_gps: Secondary stroke after split.
|
||||
* \return True if the split was done
|
||||
*/
|
||||
bool BKE_gpencil_stroke_split(bGPDframe *gpf,
|
||||
bool BKE_gpencil_stroke_split(bGPdata *gpd,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke *gps,
|
||||
const int before_index,
|
||||
bGPDstroke **remaining_gps)
|
||||
|
@ -684,7 +690,7 @@ bool BKE_gpencil_stroke_split(bGPDframe *gpf,
|
|||
* Keep the end point. */
|
||||
|
||||
BKE_gpencil_stroke_trim_points(gps, 0, old_count);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1273,14 +1279,31 @@ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
|
|||
|
||||
/**
|
||||
* Recalc all internal geometry data for the stroke
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Grease pencil stroke
|
||||
*/
|
||||
void BKE_gpencil_stroke_geometry_update(bGPDstroke *gps)
|
||||
void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps)
|
||||
{
|
||||
if (gps == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gps->editcurve != NULL) {
|
||||
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
|
||||
/* curve geometry was updated: stroke needs recalculation */
|
||||
if (gps->flag & GP_STROKE_NEEDS_CURVE_UPDATE) {
|
||||
bool is_adaptive = gpd->flag & GP_DATA_CURVE_ADAPTIVE_RESOLUTION;
|
||||
BKE_gpencil_stroke_update_geometry_from_editcurve(
|
||||
gps, gpd->curve_edit_resolution, is_adaptive);
|
||||
gps->flag &= ~GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* stroke geometry was updated: editcurve needs recalculation */
|
||||
gps->editcurve->flag |= GP_CURVE_NEEDS_STROKE_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (gps->totpoints > 2) {
|
||||
BKE_gpencil_stroke_fill_triangulate(gps);
|
||||
}
|
||||
|
@ -1326,7 +1349,7 @@ float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
|
|||
* Trim stroke to the first intersection or loop.
|
||||
* \param gps: Stroke data
|
||||
*/
|
||||
bool BKE_gpencil_stroke_trim(bGPDstroke *gps)
|
||||
bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps)
|
||||
{
|
||||
if (gps->totpoints < 4) {
|
||||
return false;
|
||||
|
@ -1413,7 +1436,7 @@ bool BKE_gpencil_stroke_trim(bGPDstroke *gps)
|
|||
MEM_SAFE_FREE(old_dvert);
|
||||
}
|
||||
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
return intersect;
|
||||
}
|
||||
|
@ -1509,11 +1532,12 @@ bool BKE_gpencil_stroke_close(bGPDstroke *gps)
|
|||
|
||||
/**
|
||||
* Dissolve points in stroke.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gpf: Grease pencil frame
|
||||
* \param gps: Grease pencil stroke
|
||||
* \param tag: Type of tag for point
|
||||
*/
|
||||
void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short tag)
|
||||
void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, const short tag)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
MDeformVert *dvert = NULL;
|
||||
|
@ -1589,7 +1613,7 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta
|
|||
gps->totpoints = tot;
|
||||
|
||||
/* triangles cache needs to be recalculated */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1635,10 +1659,11 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
|
|||
*
|
||||
* Ramer - Douglas - Peucker algorithm
|
||||
* by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Grease pencil stroke
|
||||
* \param epsilon: Epsilon value to define precision of the algorithm
|
||||
*/
|
||||
void BKE_gpencil_stroke_simplify_adaptive(bGPDstroke *gps, float epsilon)
|
||||
void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float epsilon)
|
||||
{
|
||||
bGPDspoint *old_points = MEM_dupallocN(gps->points);
|
||||
int totpoints = gps->totpoints;
|
||||
|
@ -1735,7 +1760,7 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPDstroke *gps, float epsilon)
|
|||
gps->totpoints = j;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
MEM_SAFE_FREE(old_points);
|
||||
MEM_SAFE_FREE(old_dvert);
|
||||
|
@ -1744,9 +1769,10 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPDstroke *gps, float epsilon)
|
|||
|
||||
/**
|
||||
* Simplify alternate vertex of stroke except extremes.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Grease pencil stroke
|
||||
*/
|
||||
void BKE_gpencil_stroke_simplify_fixed(bGPDstroke *gps)
|
||||
void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps)
|
||||
{
|
||||
if (gps->totpoints < 5) {
|
||||
return;
|
||||
|
@ -1800,19 +1826,20 @@ void BKE_gpencil_stroke_simplify_fixed(bGPDstroke *gps)
|
|||
|
||||
gps->totpoints = j;
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
MEM_SAFE_FREE(old_points);
|
||||
MEM_SAFE_FREE(old_dvert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subdivide grease pencil stroke.
|
||||
* \param gps: Grease pencil stroke
|
||||
* Subdivide a stroke
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gps: Stroke
|
||||
* \param level: Level of subdivision
|
||||
* \param type: Type of subdivision
|
||||
*/
|
||||
void BKE_gpencil_stroke_subdivide(bGPDstroke *gps, int level, int type)
|
||||
void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int type)
|
||||
{
|
||||
bGPDspoint *temp_points;
|
||||
MDeformVert *temp_dverts = NULL;
|
||||
|
@ -1921,7 +1948,7 @@ void BKE_gpencil_stroke_subdivide(bGPDstroke *gps, int level, int type)
|
|||
}
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
/* Merge by distance ------------------------------------- */
|
||||
|
@ -1930,12 +1957,14 @@ void BKE_gpencil_stroke_subdivide(bGPDstroke *gps, int level, int type)
|
|||
* Reduce a series of points when the distance is below a threshold.
|
||||
* Special case for first and last points (both are keeped) for other points,
|
||||
* the merge point always is at first point.
|
||||
* \param gpd: Grease pencil data-block
|
||||
* \param gpf: Grease Pencil frame
|
||||
* \param gps: Grease Pencil stroke
|
||||
* \param threshold: Distance between points
|
||||
* \param use_unselected: Set to true to analyze all stroke and not only selected points
|
||||
*/
|
||||
void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf,
|
||||
void BKE_gpencil_stroke_merge_distance(bGPdata *gpd,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke *gps,
|
||||
const float threshold,
|
||||
const bool use_unselected)
|
||||
|
@ -2000,11 +2029,11 @@ void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf,
|
|||
|
||||
/* Dissolve tagged points */
|
||||
if (tagged) {
|
||||
BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG);
|
||||
BKE_gpencil_dissolve_points(gpd, gpf, gps, GP_SPOINT_TAG);
|
||||
}
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
typedef struct GpEdge {
|
||||
|
@ -2093,6 +2122,7 @@ static int gpencil_walk_edge(GHash *v_table,
|
|||
}
|
||||
|
||||
static void gpencil_generate_edgeloops(Object *ob,
|
||||
bGPdata *gpd,
|
||||
bGPDframe *gpf_stroke,
|
||||
int stroke_mat_index,
|
||||
const float angle,
|
||||
|
@ -2218,7 +2248,7 @@ static void gpencil_generate_edgeloops(Object *ob,
|
|||
pt->strength = 1.0f;
|
||||
}
|
||||
|
||||
BKE_gpencil_stroke_geometry_update(gps_stroke);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps_stroke);
|
||||
}
|
||||
|
||||
/* Free memory. */
|
||||
|
@ -2397,10 +2427,10 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
|
|||
}
|
||||
/* If has only 3 points subdivide. */
|
||||
if (mp->totloop == 3) {
|
||||
BKE_gpencil_stroke_subdivide(gps_fill, 1, GP_SUBDIV_SIMPLE);
|
||||
BKE_gpencil_stroke_subdivide(gpd, gps_fill, 1, GP_SUBDIV_SIMPLE);
|
||||
}
|
||||
|
||||
BKE_gpencil_stroke_geometry_update(gps_fill);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps_fill);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2417,7 +2447,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
|
|||
gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW);
|
||||
|
||||
gpencil_generate_edgeloops(
|
||||
ob_eval, gpf_stroke, stroke_mat_index, angle, thickness, offset, matrix, use_seams);
|
||||
ob_eval, gpd, gpf_stroke, stroke_mat_index, angle, thickness, offset, matrix, use_seams);
|
||||
|
||||
/* Tag for recalculation */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
|
||||
|
@ -2457,7 +2487,7 @@ void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4])
|
|||
}
|
||||
|
||||
/* Distortion may mean we need to re-triangulate. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2549,7 +2579,7 @@ void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates
|
|||
}
|
||||
|
||||
/* Distortion may mean we need to re-triangulate. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2586,7 +2616,7 @@ void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd,
|
|||
}
|
||||
|
||||
/* Distortion may mean we need to re-triangulate. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -698,7 +698,9 @@ void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *o
|
|||
}
|
||||
|
||||
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_eval);
|
||||
const bool do_modifiers = (bool)((!is_multiedit) && (ob->greasepencil_modifiers.first != NULL) &&
|
||||
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd_eval);
|
||||
const bool do_modifiers = (bool)((!is_multiedit) && (!is_curve_edit) &&
|
||||
(ob->greasepencil_modifiers.first != NULL) &&
|
||||
(!GPENCIL_SIMPLIFY_MODIF(scene)));
|
||||
if ((!do_modifiers) && (!do_parent)) {
|
||||
return;
|
||||
|
@ -734,8 +736,10 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
|
|||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
|
||||
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
|
||||
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
|
||||
const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
|
||||
const bool do_modifiers = (bool)((!is_multiedit) && (ob->greasepencil_modifiers.first != NULL) &&
|
||||
const bool do_modifiers = (bool)((!is_multiedit) && (!is_curve_edit) &&
|
||||
(ob->greasepencil_modifiers.first != NULL) &&
|
||||
(!GPENCIL_SIMPLIFY_MODIF(scene)));
|
||||
if (!do_modifiers) {
|
||||
return;
|
||||
|
|
|
@ -4871,7 +4871,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
gps->fill_opacity_fac = 1.0f;
|
||||
|
||||
/* Calc geometry data because in old versions this data was not saved. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill);
|
||||
int i;
|
||||
|
|
|
@ -1067,6 +1067,20 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
part->phystype = PART_PHYS_NO;
|
||||
}
|
||||
}
|
||||
/* Init grease pencil default curve resolution. */
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "int", "curve_edit_resolution")) {
|
||||
LISTBASE_FOREACH (bGPdata *, gpd, &bmain->gpencils) {
|
||||
gpd->curve_edit_resolution = GP_DEFAULT_CURVE_RESOLUTION;
|
||||
gpd->flag |= GP_DATA_CURVE_ADAPTIVE_RESOLUTION;
|
||||
}
|
||||
}
|
||||
/* Init grease pencil curve editing error threshold. */
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "curve_edit_threshold")) {
|
||||
LISTBASE_FOREACH (bGPdata *, gpd, &bmain->gpencils) {
|
||||
gpd->curve_edit_threshold = GP_DEFAULT_CURVE_ERROR;
|
||||
gpd->curve_edit_corner_angle = GP_DEFAULT_CURVE_EDIT_CORNER_ANGLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 291, 9)) {
|
||||
|
|
|
@ -49,6 +49,10 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
|
|||
pd->edit_gpencil_wires_grp = NULL;
|
||||
psl->edit_gpencil_ps = NULL;
|
||||
|
||||
pd->edit_gpencil_curve_handle_grp = NULL;
|
||||
pd->edit_gpencil_curve_points_grp = NULL;
|
||||
psl->edit_gpencil_curve_ps = NULL;
|
||||
|
||||
const DRWContextState *draw_ctx = DRW_context_state_get();
|
||||
View3D *v3d = draw_ctx->v3d;
|
||||
Object *ob = draw_ctx->obact;
|
||||
|
@ -105,7 +109,8 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
|
|||
(GPENCIL_EDIT_MODE(gpd) &&
|
||||
(ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
|
||||
|
||||
if ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask) {
|
||||
if ((!GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) &&
|
||||
((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask)) {
|
||||
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
|
||||
DRW_STATE_BLEND_ALPHA;
|
||||
DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state);
|
||||
|
@ -132,6 +137,37 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
|
|||
}
|
||||
}
|
||||
|
||||
/* Handles and curve point for Curve Edit submode. */
|
||||
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
|
||||
DRWState state = DRW_STATE_WRITE_COLOR;
|
||||
DRW_PASS_CREATE(psl->edit_gpencil_curve_ps, state | pd->clipping_state);
|
||||
|
||||
/* Edit lines. */
|
||||
if (show_lines) {
|
||||
sh = OVERLAY_shader_edit_gpencil_wire();
|
||||
pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_ps);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select);
|
||||
DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity);
|
||||
DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
|
||||
}
|
||||
|
||||
sh = OVERLAY_shader_edit_curve_handle();
|
||||
pd->edit_gpencil_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_ps);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles);
|
||||
DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display);
|
||||
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
|
||||
|
||||
sh = OVERLAY_shader_edit_curve_point();
|
||||
pd->edit_gpencil_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_curve_ps);
|
||||
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
|
||||
DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles);
|
||||
DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display);
|
||||
}
|
||||
|
||||
/* control points for primitives and speed guide */
|
||||
const bool is_cppoint = (gpd->runtime.tot_cp_points > 0);
|
||||
const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide &&
|
||||
|
@ -182,6 +218,7 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
|
|||
void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
|
||||
{
|
||||
OVERLAY_PassList *psl = vedata->psl;
|
||||
OVERLAY_PrivateData *pd = vedata->stl->pd;
|
||||
struct GPUShader *sh;
|
||||
DRWShadingGroup *grp;
|
||||
|
||||
|
@ -196,6 +233,9 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
|
|||
ToolSettings *ts = scene->toolsettings;
|
||||
const View3DCursor *cursor = &scene->cursor;
|
||||
|
||||
pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE;
|
||||
pd->edit_curve.handle_display = v3d->overlay.handle_display;
|
||||
|
||||
if (gpd == NULL || ob->type != OB_GPENCIL) {
|
||||
return;
|
||||
}
|
||||
|
@ -303,6 +343,20 @@ static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob
|
|||
struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra);
|
||||
DRW_shgroup_call_no_cull(grp, geom, ob);
|
||||
}
|
||||
|
||||
if (pd->edit_gpencil_curve_handle_grp) {
|
||||
struct GPUBatch *geom = DRW_cache_gpencil_edit_curve_handles_get(ob, pd->cfra);
|
||||
if (geom) {
|
||||
DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_handle_grp, geom, ob);
|
||||
}
|
||||
}
|
||||
|
||||
if (pd->edit_gpencil_curve_points_grp) {
|
||||
struct GPUBatch *geom = DRW_cache_gpencil_edit_curve_points_get(ob, pd->cfra);
|
||||
if (geom) {
|
||||
DRW_shgroup_call_no_cull(pd->edit_gpencil_curve_points_grp, geom, ob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl),
|
||||
|
@ -407,4 +461,9 @@ void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata)
|
|||
if (psl->edit_gpencil_ps) {
|
||||
DRW_draw_pass(psl->edit_gpencil_ps);
|
||||
}
|
||||
|
||||
/* Curve edit handles. */
|
||||
if (psl->edit_gpencil_curve_ps) {
|
||||
DRW_draw_pass(psl->edit_gpencil_curve_ps);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ typedef struct OVERLAY_PassList {
|
|||
DRWPass *edit_curve_handle_ps;
|
||||
DRWPass *edit_gpencil_ps;
|
||||
DRWPass *edit_gpencil_gizmos_ps;
|
||||
DRWPass *edit_gpencil_curve_ps;
|
||||
DRWPass *edit_lattice_ps;
|
||||
DRWPass *edit_mesh_depth_ps[2];
|
||||
DRWPass *edit_mesh_verts_ps[2];
|
||||
|
@ -252,6 +253,8 @@ typedef struct OVERLAY_PrivateData {
|
|||
DRWShadingGroup *edit_lattice_wires_grp;
|
||||
DRWShadingGroup *edit_gpencil_points_grp;
|
||||
DRWShadingGroup *edit_gpencil_wires_grp;
|
||||
DRWShadingGroup *edit_gpencil_curve_handle_grp;
|
||||
DRWShadingGroup *edit_gpencil_curve_points_grp;
|
||||
DRWShadingGroup *edit_mesh_depth_grp[2];
|
||||
DRWShadingGroup *edit_mesh_faces_grp[2];
|
||||
DRWShadingGroup *edit_mesh_faces_cage_grp[2];
|
||||
|
|
|
@ -53,6 +53,9 @@ void main()
|
|||
bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERT_SELECTED) != 0);
|
||||
bool handle_selected = (showCurveHandles &&
|
||||
(((vertFlag[1] | vertFlag[0]) & VERT_SELECTED_BEZT_HANDLE) != 0));
|
||||
/* It reuses freestyle flag because the flag is 8 bits and all are already used and this
|
||||
* flag is not used in this context. */
|
||||
bool is_gpencil = ((vertFlag[1] & EDGE_FREESTYLE) != 0);
|
||||
|
||||
/* If handle type is only selected and the edge is not selected, don't show. */
|
||||
if ((curveHandleDisplay != CURVE_HANDLE_ALL) && (!handle_selected)) {
|
||||
|
@ -61,6 +64,9 @@ void main()
|
|||
if ((!is_u_segment) && (color_id <= 4)) {
|
||||
return;
|
||||
}
|
||||
if (is_gpencil) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 inner_color;
|
||||
|
|
|
@ -17,16 +17,17 @@ void main()
|
|||
{
|
||||
GPU_INTEL_VERTEX_SHADER_WORKAROUND
|
||||
|
||||
/* Reuse the FREESTYLE flag to determine is GPencil. */
|
||||
if ((data & VERT_SELECTED) != 0) {
|
||||
if ((data & VERT_ACTIVE) != 0) {
|
||||
finalColor = colorEditMeshActive;
|
||||
}
|
||||
else {
|
||||
finalColor = colorVertexSelect;
|
||||
finalColor = ((data & EDGE_FREESTYLE) == 0) ? colorVertexSelect : colorGpencilVertexSelect;
|
||||
}
|
||||
}
|
||||
else {
|
||||
finalColor = colorVertex;
|
||||
finalColor = ((data & EDGE_FREESTYLE) == 0) ? colorVertex : colorGpencilVertex;
|
||||
}
|
||||
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
|
|
|
@ -253,6 +253,8 @@ struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra);
|
|||
struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra);
|
||||
struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra);
|
||||
struct GPUBatch *DRW_cache_gpencil_edit_points_get(struct Object *ob, int cfra);
|
||||
struct GPUBatch *DRW_cache_gpencil_edit_curve_handles_get(struct Object *ob, int cfra);
|
||||
struct GPUBatch *DRW_cache_gpencil_edit_curve_points_get(struct Object *ob, int cfra);
|
||||
struct GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(struct Object *ob);
|
||||
struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
|
@ -43,6 +44,9 @@
|
|||
#include "draw_cache.h"
|
||||
#include "draw_cache_impl.h"
|
||||
|
||||
#define BEZIER_HANDLE 1 << 3
|
||||
#define COLOR_SHIFT 5
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
typedef struct GpencilBatchCache {
|
||||
/** Instancing Data */
|
||||
|
@ -59,6 +63,10 @@ typedef struct GpencilBatchCache {
|
|||
GPUVertBuf *edit_vbo;
|
||||
GPUBatch *edit_lines_batch;
|
||||
GPUBatch *edit_points_batch;
|
||||
/** Edit Curve Mode */
|
||||
GPUVertBuf *edit_curve_vbo;
|
||||
GPUBatch *edit_curve_handles_batch;
|
||||
GPUBatch *edit_curve_points_batch;
|
||||
|
||||
/** Cache is dirty */
|
||||
bool is_dirty;
|
||||
|
@ -123,6 +131,10 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
|
|||
GPU_BATCH_DISCARD_SAFE(cache->edit_points_batch);
|
||||
GPU_VERTBUF_DISCARD_SAFE(cache->edit_vbo);
|
||||
|
||||
GPU_BATCH_DISCARD_SAFE(cache->edit_curve_handles_batch);
|
||||
GPU_BATCH_DISCARD_SAFE(cache->edit_curve_points_batch);
|
||||
GPU_VERTBUF_DISCARD_SAFE(cache->edit_curve_vbo);
|
||||
|
||||
cache->is_dirty = true;
|
||||
}
|
||||
|
||||
|
@ -196,6 +208,23 @@ static GPUVertFormat *gpencil_edit_stroke_format(void)
|
|||
return &format;
|
||||
}
|
||||
|
||||
/* MUST match the format below. */
|
||||
typedef struct gpEditCurveVert {
|
||||
float pos[3];
|
||||
int data;
|
||||
} gpEditCurveVert;
|
||||
|
||||
static GPUVertFormat *gpencil_edit_curve_format(void)
|
||||
{
|
||||
static GPUVertFormat format = {0};
|
||||
if (format.attr_len == 0) {
|
||||
/* initialize vertex formats */
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
|
||||
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
|
||||
}
|
||||
return &format;
|
||||
}
|
||||
|
||||
/* MUST match the format below. */
|
||||
typedef struct gpColorVert {
|
||||
float vcol[4]; /* Vertex color */
|
||||
|
@ -228,6 +257,7 @@ typedef struct gpIterData {
|
|||
GPUIndexBufBuilder ibo;
|
||||
int vert_len;
|
||||
int tri_len;
|
||||
int curve_len;
|
||||
} gpIterData;
|
||||
|
||||
static GPUVertBuf *gpencil_dummy_buffer_get(void)
|
||||
|
@ -383,6 +413,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr
|
|||
.ibo = {0},
|
||||
.vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */
|
||||
.tri_len = 0,
|
||||
.curve_len = 0,
|
||||
};
|
||||
BKE_gpencil_visible_stroke_iter(
|
||||
NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra);
|
||||
|
@ -653,6 +684,11 @@ typedef struct gpEditIterData {
|
|||
int vgindex;
|
||||
} gpEditIterData;
|
||||
|
||||
typedef struct gpEditCurveIterData {
|
||||
gpEditCurveVert *verts;
|
||||
int vgindex;
|
||||
} gpEditCurveIterData;
|
||||
|
||||
static uint32_t gpencil_point_edit_flag(const bool layer_lock,
|
||||
const bGPDspoint *pt,
|
||||
int v,
|
||||
|
@ -698,6 +734,92 @@ static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl,
|
|||
vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex);
|
||||
}
|
||||
|
||||
static void gpencil_edit_curve_stroke_count_cb(bGPDlayer *gpl,
|
||||
bGPDframe *UNUSED(gpf),
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
if (gpl->flag & GP_LAYER_LOCKED) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpIterData *iter = (gpIterData *)thunk;
|
||||
|
||||
if (gps->editcurve == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store first index offset */
|
||||
gps->runtime.curve_start = iter->curve_len;
|
||||
iter->curve_len += gps->editcurve->tot_curve_points * 4;
|
||||
}
|
||||
|
||||
static char gpencil_beztriple_vflag_get(char flag,
|
||||
char col_id,
|
||||
bool handle_point,
|
||||
const bool handle_selected)
|
||||
{
|
||||
char vflag = 0;
|
||||
SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED);
|
||||
SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE);
|
||||
SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_VERT_SELECTED_BEZT_HANDLE);
|
||||
/* Reuse flag of Freestyle to indicate is GPencil data. */
|
||||
vflag |= VFLAG_EDGE_FREESTYLE;
|
||||
|
||||
/* Handle color id. */
|
||||
vflag |= col_id << COLOR_SHIFT;
|
||||
return vflag;
|
||||
}
|
||||
|
||||
static void gpencil_edit_curve_stroke_iter_cb(bGPDlayer *gpl,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke *gps,
|
||||
void *thunk)
|
||||
{
|
||||
if (gpl->flag & GP_LAYER_LOCKED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gps->editcurve == NULL) {
|
||||
return;
|
||||
}
|
||||
bGPDcurve *editcurve = gps->editcurve;
|
||||
gpEditCurveIterData *iter = (gpEditCurveIterData *)thunk;
|
||||
const int v = gps->runtime.curve_start;
|
||||
gpEditCurveVert *vert_ptr = iter->verts + v;
|
||||
/* Hide points when the curve is unselected. Passing the control point
|
||||
* as handle produces the point shader skip it if you are not in ALL mode. */
|
||||
const bool hide = !(editcurve->flag & GP_CURVE_SELECT);
|
||||
|
||||
for (int i = 0; i < editcurve->tot_curve_points; i++) {
|
||||
BezTriple *bezt = &editcurve->curve_points[i].bezt;
|
||||
const bool handle_selected = BEZT_ISSEL_ANY(bezt);
|
||||
const char vflag[3] = {
|
||||
gpencil_beztriple_vflag_get(bezt->f1, bezt->h1, true, handle_selected),
|
||||
gpencil_beztriple_vflag_get(bezt->f2, bezt->h1, hide, handle_selected),
|
||||
gpencil_beztriple_vflag_get(bezt->f3, bezt->h2, true, handle_selected),
|
||||
};
|
||||
|
||||
/* First segment. */
|
||||
copy_v3_v3(vert_ptr->pos, bezt->vec[0]);
|
||||
vert_ptr->data = vflag[0];
|
||||
vert_ptr++;
|
||||
|
||||
copy_v3_v3(vert_ptr->pos, bezt->vec[1]);
|
||||
vert_ptr->data = vflag[1];
|
||||
vert_ptr++;
|
||||
|
||||
/* Second segment. */
|
||||
copy_v3_v3(vert_ptr->pos, bezt->vec[1]);
|
||||
vert_ptr->data = vflag[1];
|
||||
vert_ptr++;
|
||||
|
||||
copy_v3_v3(vert_ptr->pos, bezt->vec[2]);
|
||||
vert_ptr->data = vflag[2];
|
||||
vert_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
|
@ -737,6 +859,46 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in
|
|||
|
||||
cache->edit_lines_batch = GPU_batch_create(GPU_PRIM_LINE_STRIP, cache->vbo, NULL);
|
||||
GPU_batch_vertbuf_add(cache->edit_lines_batch, cache->edit_vbo);
|
||||
}
|
||||
|
||||
/* Curve Handles and Points for Editing. */
|
||||
if (cache->edit_curve_vbo == NULL) {
|
||||
gpIterData iterdata = {
|
||||
.gpd = gpd,
|
||||
.verts = NULL,
|
||||
.ibo = {0},
|
||||
.vert_len = 0,
|
||||
.tri_len = 0,
|
||||
.curve_len = 0,
|
||||
};
|
||||
|
||||
/* Create VBO. */
|
||||
GPUVertFormat *format = gpencil_edit_curve_format();
|
||||
cache->edit_curve_vbo = GPU_vertbuf_create_with_format(format);
|
||||
|
||||
/* Count data. */
|
||||
BKE_gpencil_visible_stroke_iter(
|
||||
NULL, ob, NULL, gpencil_edit_curve_stroke_count_cb, &iterdata, false, cfra);
|
||||
|
||||
gpEditCurveIterData iter;
|
||||
int vert_len = iterdata.curve_len;
|
||||
if (vert_len > 0) {
|
||||
|
||||
GPU_vertbuf_data_alloc(cache->edit_curve_vbo, vert_len);
|
||||
iter.verts = (gpEditCurveVert *)GPU_vertbuf_get_data(cache->edit_curve_vbo);
|
||||
|
||||
/* Fill buffers with data. */
|
||||
BKE_gpencil_visible_stroke_iter(
|
||||
NULL, ob, NULL, gpencil_edit_curve_stroke_iter_cb, &iter, false, cfra);
|
||||
|
||||
cache->edit_curve_handles_batch = GPU_batch_create(
|
||||
GPU_PRIM_LINES, cache->edit_curve_vbo, NULL);
|
||||
GPU_batch_vertbuf_add(cache->edit_curve_handles_batch, cache->edit_curve_vbo);
|
||||
|
||||
cache->edit_curve_points_batch = GPU_batch_create(
|
||||
GPU_PRIM_POINTS, cache->edit_curve_vbo, NULL);
|
||||
GPU_batch_vertbuf_add(cache->edit_curve_points_batch, cache->edit_curve_vbo);
|
||||
}
|
||||
|
||||
gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
|
||||
cache->is_dirty = false;
|
||||
|
@ -761,4 +923,22 @@ GPUBatch *DRW_cache_gpencil_edit_points_get(Object *ob, int cfra)
|
|||
return cache->edit_points_batch;
|
||||
}
|
||||
|
||||
GPUBatch *DRW_cache_gpencil_edit_curve_handles_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
gpencil_edit_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->edit_curve_handles_batch;
|
||||
}
|
||||
|
||||
GPUBatch *DRW_cache_gpencil_edit_curve_points_get(Object *ob, int cfra)
|
||||
{
|
||||
GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
|
||||
gpencil_batches_ensure(ob, cache, cfra);
|
||||
gpencil_edit_batches_ensure(ob, cache, cfra);
|
||||
|
||||
return cache->edit_curve_points_batch;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -42,6 +42,7 @@ set(SRC
|
|||
gpencil_convert.c
|
||||
gpencil_data.c
|
||||
gpencil_edit.c
|
||||
gpencil_edit_curve.c
|
||||
gpencil_fill.c
|
||||
gpencil_interpolate.c
|
||||
gpencil_merge.c
|
||||
|
|
|
@ -910,7 +910,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
|
|||
int totarrowpoints = runtime.arrow_end_style;
|
||||
|
||||
/* Setting up arrow stroke. */
|
||||
bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false);
|
||||
bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false, false);
|
||||
annotation_stroke_arrow_allocate(e_arrow_gps, totarrowpoints);
|
||||
|
||||
/* Set pointer to first non-initialized point. */
|
||||
|
@ -931,7 +931,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
|
|||
int totarrowpoints = runtime.arrow_start_style;
|
||||
|
||||
/* Setting up arrow stroke. */
|
||||
bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false);
|
||||
bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false, false);
|
||||
annotation_stroke_arrow_allocate(s_arrow_gps, totarrowpoints);
|
||||
|
||||
/* Set pointer to first non-initialized point. */
|
||||
|
@ -1198,7 +1198,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
|
|||
|
||||
/* Second Pass: Remove any points that are tagged */
|
||||
if (do_cull) {
|
||||
gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
|
||||
gpencil_stroke_delete_tagged_points(p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -486,7 +486,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
|
|||
*/
|
||||
for (gps = gpfs->strokes.first; gps; gps = gps->next) {
|
||||
/* make a copy of stroke, then of its points array */
|
||||
gpsn = BKE_gpencil_stroke_duplicate(gps, true);
|
||||
gpsn = BKE_gpencil_stroke_duplicate(gps, true, true);
|
||||
|
||||
/* append stroke to frame */
|
||||
BLI_addtail(&gpf->strokes, gpsn);
|
||||
|
|
|
@ -861,115 +861,115 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
|
|||
/* generate strokes */
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data0, 270, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data1, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data2, 18, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data3, 64, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data4, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data5, 64, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data6, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 18, 40, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data7, 18, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data8, 49, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data9, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data10, 49, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data11, 18, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data12, 18, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data13, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data14, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 65, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data15, 65, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data16, 34, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data17, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 40, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data18, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 40, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data19, 34, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data20, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 64, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data21, 64, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data22, 26, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data23, 26, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data24, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data25, 18, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data26, 18, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data27, 33, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
/* update depsgraph */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
|
|
|
@ -249,7 +249,7 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
|
|||
/* generate stroke */
|
||||
gps = BKE_gpencil_stroke_add(frame_lines, color_black, 175, 75, false);
|
||||
BKE_gpencil_stroke_add_points(gps, data0, 175, mat);
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
/* update depsgraph */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
|
|
|
@ -1855,12 +1855,12 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op)
|
|||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true);
|
||||
bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, CFRA);
|
||||
done = BKE_gpencil_from_image(sima, gpf, size, is_mask);
|
||||
done = BKE_gpencil_from_image(sima, gpd, gpf, size, is_mask);
|
||||
|
||||
if (done) {
|
||||
/* Delete any selected point. */
|
||||
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
|
||||
gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
|
||||
gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
|
||||
}
|
||||
|
||||
BKE_reportf(op->reports, RPT_INFO, "Object created");
|
||||
|
|
|
@ -580,7 +580,7 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op)
|
|||
LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
|
||||
|
||||
/* Make copy of source stroke. */
|
||||
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
|
||||
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
|
||||
|
||||
/* Check if material is in destination object,
|
||||
* otherwise add the slot with the material. */
|
||||
|
@ -1531,6 +1531,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op)
|
|||
const int direction = RNA_enum_get(op->ptr, "direction");
|
||||
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
|
||||
|
||||
bool changed = false;
|
||||
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
|
||||
/* temp listbase to store selected strokes */
|
||||
ListBase selected = {NULL};
|
||||
|
@ -1589,7 +1590,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op)
|
|||
break;
|
||||
/* Bring Forward */
|
||||
case GP_STROKE_MOVE_UP:
|
||||
for (LinkData *link = selected.last; link; link = link->prev) {
|
||||
LISTBASE_FOREACH_BACKWARD (LinkData *, link, &selected) {
|
||||
gps = link->data;
|
||||
BLI_listbase_link_move(&gpf->strokes, gps, 1);
|
||||
}
|
||||
|
@ -1603,7 +1604,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op)
|
|||
break;
|
||||
/* Send to Back */
|
||||
case GP_STROKE_MOVE_BOTTOM:
|
||||
for (LinkData *link = selected.last; link; link = link->prev) {
|
||||
LISTBASE_FOREACH_BACKWARD (LinkData *, link, &selected) {
|
||||
gps = link->data;
|
||||
BLI_remlink(&gpf->strokes, gps);
|
||||
BLI_addhead(&gpf->strokes, gps);
|
||||
|
@ -1612,6 +1613,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op)
|
|||
default:
|
||||
BLI_assert(0);
|
||||
break;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
BLI_freelistN(&selected);
|
||||
|
@ -1625,9 +1627,11 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
if (changed) {
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@ -1693,6 +1697,7 @@ static int gpencil_stroke_change_color_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
/* loop all strokes */
|
||||
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
|
||||
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
|
||||
|
@ -1717,6 +1722,8 @@ static int gpencil_stroke_change_color_exec(bContext *C, wmOperator *op)
|
|||
|
||||
/* assign new color */
|
||||
gps->mat_nr = idx;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1728,9 +1735,11 @@ static int gpencil_stroke_change_color_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
if (changed) {
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@ -1757,9 +1766,7 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot)
|
|||
static int gpencil_material_lock_unsused_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
short *totcol = BKE_object_material_len_p(ob);
|
||||
|
||||
/* sanity checks */
|
||||
|
@ -1776,6 +1783,7 @@ static int gpencil_material_lock_unsused_exec(bContext *C, wmOperator *UNUSED(op
|
|||
}
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
/* loop all selected strokes and unlock any color */
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
/* only editable and visible layers are considered */
|
||||
|
@ -1793,19 +1801,24 @@ static int gpencil_material_lock_unsused_exec(bContext *C, wmOperator *UNUSED(op
|
|||
tmp_ma->gp_style->flag &= ~GP_MATERIAL_LOCKED;
|
||||
DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* updates */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
/* copy on write tag is needed, or else no refresh happens */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
|
||||
if (changed) {
|
||||
/* updates */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
|
||||
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
/* copy on write tag is needed, or else no refresh happens */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
|
||||
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@ -3476,7 +3489,6 @@ static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bool changed = false;
|
||||
|
||||
/* Sanity checks. */
|
||||
if (gpd == NULL) {
|
||||
|
@ -3484,6 +3496,7 @@ static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
/* Loop all selected strokes. */
|
||||
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2008, Blender Foundation
|
||||
* This is a new part of Blender
|
||||
* Operators for editing Grease Pencil strokes
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup edgpencil
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_gpencil_curve.h"
|
||||
#include "BKE_gpencil_geom.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "ED_gpencil.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "gpencil_intern.h"
|
||||
|
||||
/* Poll callback for checking if there is an active layer and we are in curve edit mode. */
|
||||
static bool gpencil_curve_edit_mode_poll(bContext *C)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
|
||||
return false;
|
||||
}
|
||||
bGPdata *gpd = (bGPdata *)ob->data;
|
||||
if (!GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
|
||||
return (gpl != NULL);
|
||||
}
|
||||
|
||||
static int gpencil_stroke_enter_editcurve_mode_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
bGPdata *gpd = ob->data;
|
||||
|
||||
float error_threshold = RNA_float_get(op->ptr, "error_threshold");
|
||||
gpd->curve_edit_threshold = error_threshold;
|
||||
|
||||
if (ELEM(NULL, gpd)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
|
||||
if (gpf == gpl->actframe) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
/* only allow selected and non-converted strokes to be transformed */
|
||||
if ((gps->flag & GP_STROKE_SELECT && gps->editcurve == NULL) ||
|
||||
(gps->editcurve != NULL && gps->editcurve->flag & GP_CURVE_NEEDS_STROKE_UPDATE)) {
|
||||
BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
|
||||
/* Update the selection from the stroke to the curve. */
|
||||
BKE_gpencil_editcurve_stroke_sync_selection(gps, gps->editcurve);
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gpd->flag |= GP_DATA_CURVE_EDIT_MODE;
|
||||
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_stroke_enter_editcurve_mode(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Enter curve edit mode";
|
||||
ot->idname = "GPENCIL_OT_stroke_enter_editcurve_mode";
|
||||
ot->description = "Called to transform a stroke into a curve";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = gpencil_stroke_enter_editcurve_mode_exec;
|
||||
ot->poll = gpencil_active_layer_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
prop = RNA_def_float(ot->srna,
|
||||
"error_threshold",
|
||||
0.1f,
|
||||
FLT_MIN,
|
||||
100.0f,
|
||||
"Error Threshold",
|
||||
"Threshold on the maximum deviation from the actual stroke",
|
||||
FLT_MIN,
|
||||
10.f);
|
||||
RNA_def_property_ui_range(prop, FLT_MIN, 10.0f, 0.1f, 5);
|
||||
}
|
||||
|
||||
static int gpencil_editcurve_set_handle_type_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
bGPdata *gpd = ob->data;
|
||||
const int handle_type = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
if (ELEM(NULL, gpd)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
|
||||
{
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
|
||||
if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
|
||||
if (bezt->f2 & SELECT) {
|
||||
bezt->h1 = handle_type;
|
||||
bezt->h2 = handle_type;
|
||||
}
|
||||
else {
|
||||
if (bezt->f1 & SELECT) {
|
||||
bezt->h1 = handle_type;
|
||||
}
|
||||
if (bezt->f3 & SELECT) {
|
||||
bezt->h2 = handle_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BKE_gpencil_editcurve_recalculate_handles(gps);
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
GP_EDITABLE_CURVES_END(gps_iter);
|
||||
|
||||
/* notifiers */
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_stroke_editcurve_set_handle_type(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem editcurve_handle_type_items[] = {
|
||||
{HD_FREE, "FREE", 0, "Free", ""},
|
||||
{HD_AUTO, "AUTOMATIC", 0, "Automatic", ""},
|
||||
{HD_VECT, "VECTOR", 0, "Vector", ""},
|
||||
{HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Set handle type";
|
||||
ot->idname = "GPENCIL_OT_stroke_editcurve_set_handle_type";
|
||||
ot->description = "Set the type of a edit curve handle";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = WM_menu_invoke;
|
||||
ot->exec = gpencil_editcurve_set_handle_type_exec;
|
||||
ot->poll = gpencil_curve_edit_mode_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -1299,11 +1299,11 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
|
|||
|
||||
/* simplify stroke */
|
||||
for (int b = 0; b < tgpf->fill_simplylvl; b++) {
|
||||
BKE_gpencil_stroke_simplify_fixed(gps);
|
||||
BKE_gpencil_stroke_simplify_fixed(tgpf->gpd, gps);
|
||||
}
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(tgpf->gpd, gps);
|
||||
}
|
||||
|
||||
/* ----------------------- */
|
||||
|
|
|
@ -343,7 +343,8 @@ struct GHash *gpencil_copybuf_validate_colormap(struct bContext *C);
|
|||
|
||||
/* Stroke Editing ------------------------------------ */
|
||||
|
||||
void gpencil_stroke_delete_tagged_points(bGPDframe *gpf,
|
||||
void gpencil_stroke_delete_tagged_points(bGPdata *gpd,
|
||||
bGPDframe *gpf,
|
||||
bGPDstroke *gps,
|
||||
bGPDstroke *next_stroke,
|
||||
int tag_flags,
|
||||
|
@ -351,7 +352,7 @@ void gpencil_stroke_delete_tagged_points(bGPDframe *gpf,
|
|||
int limit);
|
||||
int gpencil_delete_selected_point_wrap(bContext *C);
|
||||
|
||||
void gpencil_subdivide_stroke(bGPDstroke *gps, const int subdivide);
|
||||
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide);
|
||||
|
||||
/* Layers Enums -------------------------------------- */
|
||||
|
||||
|
@ -447,6 +448,11 @@ void GPENCIL_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
|
|||
void GPENCIL_OT_reproject(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_recalc_geometry(struct wmOperatorType *ot);
|
||||
|
||||
/* stroke editcurve */
|
||||
|
||||
void GPENCIL_OT_stroke_enter_editcurve_mode(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_stroke_editcurve_set_handle_type(struct wmOperatorType *ot);
|
||||
|
||||
/* stroke sculpting -- */
|
||||
|
||||
void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
|
||||
|
@ -692,6 +698,55 @@ struct GP_EditableStrokes_Iter {
|
|||
} \
|
||||
(void)0
|
||||
|
||||
/**
|
||||
* Iterate over all editable editcurves in the current context,
|
||||
* stopping on each usable layer + stroke + curve pair (i.e. gpl, gps and gpc)
|
||||
* to perform some operations on the curve.
|
||||
*
|
||||
* \param gpl: The identifier to use for the layer of the stroke being processed.
|
||||
* Choose a suitable value to avoid name clashes.
|
||||
* \param gps: The identifier to use for current stroke being processed.
|
||||
* Choose a suitable value to avoid name clashes.
|
||||
* \param gpc: The identifier to use for current editcurve being processed.
|
||||
* Choose a suitable value to avoid name clashes.
|
||||
*/
|
||||
#define GP_EDITABLE_CURVES_BEGIN(gpstroke_iter, C, gpl, gps, gpc) \
|
||||
{ \
|
||||
struct GP_EditableStrokes_Iter gpstroke_iter = {{{0}}}; \
|
||||
Depsgraph *depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C); \
|
||||
Object *obact_ = CTX_data_active_object(C); \
|
||||
bGPdata *gpd_ = CTX_data_gpencil_data(C); \
|
||||
const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
|
||||
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { \
|
||||
bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \
|
||||
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
|
||||
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
|
||||
BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
|
||||
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
|
||||
/* loop over strokes */ \
|
||||
bGPDstroke *gpsn_; \
|
||||
for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gpsn_) { \
|
||||
gpsn_ = gps->next; \
|
||||
/* skip strokes that are invalid for current view */ \
|
||||
if (ED_gpencil_stroke_can_use(C, gps) == false) \
|
||||
continue; \
|
||||
if (gps->editcurve == NULL) \
|
||||
continue; \
|
||||
bGPDcurve *gpc = gps->editcurve; \
|
||||
/* ... Do Stuff With Strokes ... */
|
||||
|
||||
#define GP_EDITABLE_CURVES_END(gpstroke_iter) \
|
||||
} \
|
||||
} \
|
||||
if (!is_multiedit_) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
CTX_DATA_END; \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
/**
|
||||
* Iterate over all editable strokes using evaluated data in the current context,
|
||||
* stopping on each usable layer + stroke pair (i.e. gpl and gps)
|
||||
|
|
|
@ -184,7 +184,7 @@ static void gpencil_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgp
|
|||
|
||||
/* Add temp strokes. */
|
||||
if (gpf) {
|
||||
bGPDstroke *gps_eval = BKE_gpencil_stroke_duplicate(new_stroke, true);
|
||||
bGPDstroke *gps_eval = BKE_gpencil_stroke_duplicate(new_stroke, true, true);
|
||||
gps_eval->flag |= GP_STROKE_TAG;
|
||||
BLI_addtail(&gpf->strokes, gps_eval);
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
|
|||
}
|
||||
|
||||
/* create new stroke */
|
||||
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true);
|
||||
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
|
||||
|
||||
if (valid) {
|
||||
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
|
||||
|
@ -353,7 +353,7 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
|
|||
}
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(new_stroke);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
|
||||
/* add to strokes */
|
||||
BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
|
||||
}
|
||||
|
@ -608,11 +608,11 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
|
|||
}
|
||||
|
||||
/* make copy of source stroke, then adjust pointer to points too */
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
|
||||
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
|
||||
gps_dst->flag &= ~GP_STROKE_TAG;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps_dst);
|
||||
BKE_gpencil_stroke_geometry_update(tgpi->gpd, gps_dst);
|
||||
|
||||
BLI_addtail(&gpf_dst->strokes, gps_dst);
|
||||
}
|
||||
|
@ -1050,7 +1050,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
/* create new stroke */
|
||||
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true);
|
||||
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
|
||||
|
||||
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
|
||||
if (gps_from->totpoints > gps_to->totpoints) {
|
||||
|
@ -1075,7 +1075,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
|
|||
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(new_stroke);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
|
||||
|
||||
/* add to strokes */
|
||||
BLI_addtail(&interFrame->strokes, new_stroke);
|
||||
|
|
|
@ -172,6 +172,9 @@ static void gpencil_get_elements_len(bContext *C, int *totstrokes, int *totpoint
|
|||
|
||||
static void gpencil_dissolve_points(bContext *C)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
bGPdata *gpd = ob->data;
|
||||
|
||||
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
if (gpf == NULL) {
|
||||
|
@ -179,7 +182,7 @@ static void gpencil_dissolve_points(bContext *C)
|
|||
}
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
|
||||
gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
|
||||
gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
@ -519,7 +522,7 @@ static int gpencil_stroke_merge_exec(bContext *C, wmOperator *op)
|
|||
gpencil_dissolve_points(C);
|
||||
}
|
||||
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
/* free memory */
|
||||
MEM_SAFE_FREE(original_array);
|
||||
|
|
|
@ -69,6 +69,13 @@ static bool gpencil_stroke_editmode_poll(bContext *C)
|
|||
return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE));
|
||||
}
|
||||
|
||||
/* Poll callback for stroke curve editing mode */
|
||||
static bool gpencil_stroke_editmode_curve_poll(bContext *C)
|
||||
{
|
||||
bGPdata *gpd = CTX_data_gpencil_data(C);
|
||||
return (GPENCIL_EDIT_MODE(gpd) && GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd));
|
||||
}
|
||||
|
||||
/* Poll callback for stroke painting mode */
|
||||
static bool gpencil_stroke_paintmode_poll(bContext *C)
|
||||
{
|
||||
|
@ -315,6 +322,15 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
|
|||
keymap->poll = gpencil_stroke_editmode_poll;
|
||||
}
|
||||
|
||||
/* Stroke Curve Editing Keymap - Only when editmode is enabled and in curve edit mode */
|
||||
static void ed_keymap_gpencil_curve_editing(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Curve Edit Mode", 0, 0);
|
||||
|
||||
/* set poll callback - so that this keymap only gets enabled when curve editmode is enabled */
|
||||
keymap->poll = gpencil_stroke_editmode_curve_poll;
|
||||
}
|
||||
|
||||
/* keys for draw with a drawing brush (no fill) */
|
||||
static void ed_keymap_gpencil_painting_draw(wmKeyConfig *keyconf)
|
||||
{
|
||||
|
@ -471,6 +487,7 @@ static void ed_keymap_gpencil_weightpainting_draw(wmKeyConfig *keyconf)
|
|||
void ED_keymap_gpencil(wmKeyConfig *keyconf)
|
||||
{
|
||||
ed_keymap_gpencil_general(keyconf);
|
||||
ed_keymap_gpencil_curve_editing(keyconf);
|
||||
ed_keymap_gpencil_editing(keyconf);
|
||||
ed_keymap_gpencil_painting(keyconf);
|
||||
ed_keymap_gpencil_painting_draw(keyconf);
|
||||
|
@ -568,6 +585,11 @@ void ED_operatortypes_gpencil(void)
|
|||
WM_operatortype_append(GPENCIL_OT_sculpt_paint);
|
||||
WM_operatortype_append(GPENCIL_OT_weight_paint);
|
||||
|
||||
/* Edit stroke editcurve */
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_stroke_enter_editcurve_mode);
|
||||
WM_operatortype_append(GPENCIL_OT_stroke_editcurve_set_handle_type);
|
||||
|
||||
/* Editing (Buttons) ------------ */
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_annotation_add);
|
||||
|
|
|
@ -1195,7 +1195,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
|||
|
||||
/* subdivide and smooth the stroke */
|
||||
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) {
|
||||
gpencil_subdivide_stroke(gps, subdivide);
|
||||
gpencil_subdivide_stroke(gpd, gps, subdivide);
|
||||
}
|
||||
|
||||
/* Smooth stroke after subdiv - only if there's something to do for each iteration,
|
||||
|
@ -1226,7 +1226,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
|||
/* Simplify adaptive */
|
||||
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
|
||||
(brush->gpencil_settings->simplify_f > 0.0f)) {
|
||||
BKE_gpencil_stroke_simplify_adaptive(gps, brush->gpencil_settings->simplify_f);
|
||||
BKE_gpencil_stroke_simplify_adaptive(gpd, gps, brush->gpencil_settings->simplify_f);
|
||||
}
|
||||
|
||||
/* reproject to plane (only in 3d space) */
|
||||
|
@ -1279,11 +1279,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
|||
/* post process stroke */
|
||||
if ((p->brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
|
||||
p->brush->gpencil_settings->flag & GP_BRUSH_TRIM_STROKE) {
|
||||
BKE_gpencil_stroke_trim(gps);
|
||||
BKE_gpencil_stroke_trim(gpd, gps);
|
||||
}
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
gpencil_stroke_added_enable(p);
|
||||
}
|
||||
|
@ -1652,7 +1652,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
|
|||
gpencil_stroke_soft_refine(gps);
|
||||
}
|
||||
|
||||
gpencil_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
|
||||
gpencil_stroke_delete_tagged_points(p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
|
||||
}
|
||||
gpencil_update_cache(p->gpd);
|
||||
}
|
||||
|
|
|
@ -1082,7 +1082,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
|
|||
}
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
/* Update evaluated data. */
|
||||
ED_gpencil_sbuffer_update_eval(tgpi->gpd, tgpi->ob_eval);
|
||||
|
@ -1323,7 +1323,7 @@ static void gpencil_primitive_interaction_end(bContext *C,
|
|||
copy_v2_v2(gps->aspect_ratio, brush_settings->aspect_ratio);
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(tgpi->gpd, gps);
|
||||
}
|
||||
|
||||
/* transfer stroke from temporary buffer to the actual frame */
|
||||
|
|
|
@ -303,7 +303,7 @@ static void gpencil_update_geometry(bGPdata *gpd)
|
|||
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
if (gps->flag & GP_STROKE_TAG) {
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
gps->flag &= ~GP_STROKE_TAG;
|
||||
}
|
||||
}
|
||||
|
@ -1021,7 +1021,7 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
|
|||
bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
|
||||
|
||||
/* Make a new stroke */
|
||||
new_stroke = BKE_gpencil_stroke_duplicate(gps, true);
|
||||
new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true);
|
||||
|
||||
new_stroke->next = new_stroke->prev = NULL;
|
||||
BLI_addtail(&gpf->strokes, new_stroke);
|
||||
|
@ -1574,6 +1574,7 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
|
|||
bool changed = false;
|
||||
bool redo_geom = false;
|
||||
Object *ob = gso->object;
|
||||
bGPdata *gpd = ob->data;
|
||||
char tool = gso->brush->gpencil_sculpt_tool;
|
||||
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
|
@ -1672,7 +1673,7 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
|
|||
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
|
||||
/* Update active frame now, only if material has fill. */
|
||||
if (gp_style->flag & GP_MATERIAL_FILL_SHOW) {
|
||||
BKE_gpencil_stroke_geometry_update(gps_active);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps_active);
|
||||
}
|
||||
else {
|
||||
gpencil_recalc_geometry_tag(gps_active);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -352,13 +352,14 @@ void ED_gpencil_trace_data_to_strokes(Main *bmain,
|
|||
* long stroke. Here the length is checked and removed if the length is too big. */
|
||||
float length = BKE_gpencil_stroke_length(gps, true);
|
||||
if (length <= MAX_LENGTH) {
|
||||
bGPdata *gpd = ob->data;
|
||||
if (sample > 0.0f) {
|
||||
/* Resample stroke. Don't need to call to BKE_gpencil_stroke_geometry_update() because
|
||||
* the sample function already call that. */
|
||||
BKE_gpencil_stroke_sample(gps, sample, false);
|
||||
BKE_gpencil_stroke_sample(gpd, gps, sample, false);
|
||||
}
|
||||
else {
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_gpencil_curve.h"
|
||||
#include "BKE_gpencil_geom.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
|
@ -1144,7 +1145,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
|
|||
bGPDstroke *gps_active = gps;
|
||||
/* if duplicate, deselect all points. */
|
||||
if (keep_original) {
|
||||
gps_active = BKE_gpencil_stroke_duplicate(gps, true);
|
||||
gps_active = BKE_gpencil_stroke_duplicate(gps, true, true);
|
||||
gps_active->flag &= ~GP_STROKE_SELECT;
|
||||
for (i = 0, pt = gps_active->points; i < gps_active->totpoints; i++, pt++) {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
|
@ -1320,10 +1321,11 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
|
|||
|
||||
/**
|
||||
* Subdivide a stroke once, by adding a point half way between each pair of existing points
|
||||
* \param gpd: Datablock
|
||||
* \param gps: Stroke data
|
||||
* \param subdivide: Number of times to subdivide
|
||||
*/
|
||||
void gpencil_subdivide_stroke(bGPDstroke *gps, const int subdivide)
|
||||
void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide)
|
||||
{
|
||||
bGPDspoint *temp_points;
|
||||
int totnewpoints, oldtotpoints;
|
||||
|
@ -1413,7 +1415,7 @@ void gpencil_subdivide_stroke(bGPDstroke *gps, const int subdivide)
|
|||
MEM_SAFE_FREE(temp_points);
|
||||
}
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
/* Reset parent matrix for all layers. */
|
||||
|
@ -2243,8 +2245,12 @@ static void gpencil_copy_points(
|
|||
}
|
||||
}
|
||||
|
||||
static void gpencil_insert_point(
|
||||
bGPDstroke *gps, bGPDspoint *a_pt, bGPDspoint *b_pt, const float co_a[3], const float co_b[3])
|
||||
static void gpencil_insert_point(bGPdata *gpd,
|
||||
bGPDstroke *gps,
|
||||
bGPDspoint *a_pt,
|
||||
bGPDspoint *b_pt,
|
||||
const float co_a[3],
|
||||
float co_b[3])
|
||||
{
|
||||
bGPDspoint *temp_points;
|
||||
int totnewpoints, oldtotpoints;
|
||||
|
@ -2303,8 +2309,8 @@ static void gpencil_insert_point(
|
|||
|
||||
i2++;
|
||||
}
|
||||
/* Calculate geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
MEM_SAFE_FREE(temp_points);
|
||||
}
|
||||
|
@ -2328,7 +2334,8 @@ static float gpencil_calc_factor(const float p2d_a1[2],
|
|||
}
|
||||
|
||||
/* extend selection to stroke intersections */
|
||||
int ED_gpencil_select_stroke_segment(bGPDlayer *gpl,
|
||||
int ED_gpencil_select_stroke_segment(bGPdata *gpd,
|
||||
bGPDlayer *gpl,
|
||||
bGPDstroke *gps,
|
||||
bGPDspoint *pt,
|
||||
bool select,
|
||||
|
@ -2483,7 +2490,7 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl,
|
|||
|
||||
/* insert new point in the collision points */
|
||||
if (insert) {
|
||||
gpencil_insert_point(gps, hit_pointa, hit_pointb, r_hita, r_hitb);
|
||||
gpencil_insert_point(gpd, gps, hit_pointa, hit_pointb, r_hita, r_hitb);
|
||||
}
|
||||
|
||||
/* free memory */
|
||||
|
@ -2611,6 +2618,82 @@ void ED_gpencil_select_toggle_all(bContext *C, int action)
|
|||
}
|
||||
}
|
||||
|
||||
void ED_gpencil_select_curve_toggle_all(bContext *C, int action)
|
||||
{
|
||||
/* if toggle, check if we need to select or deselect */
|
||||
if (action == SEL_TOGGLE) {
|
||||
action = SEL_SELECT;
|
||||
GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
|
||||
{
|
||||
if (gpc->flag & GP_CURVE_SELECT) {
|
||||
action = SEL_DESELECT;
|
||||
}
|
||||
}
|
||||
GP_EDITABLE_CURVES_END(gps_iter);
|
||||
}
|
||||
|
||||
if (action == SEL_DESELECT) {
|
||||
GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc)
|
||||
{
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
|
||||
BEZT_DESEL_ALL(bezt);
|
||||
}
|
||||
gpc->flag &= ~GP_CURVE_SELECT;
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
GP_EDITABLE_CURVES_END(gps_iter);
|
||||
}
|
||||
else {
|
||||
GP_EDITABLE_STROKES_BEGIN(gps_iter, C, gpl, gps){
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
bGPdata *gpd = ob->data;
|
||||
bool selected = false;
|
||||
|
||||
/* Make sure stroke has an editcurve */
|
||||
if (gps->editcurve == NULL) {
|
||||
BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
switch (action) {
|
||||
case SEL_SELECT:
|
||||
gpc_pt->flag |= GP_CURVE_POINT_SELECT;
|
||||
BEZT_SEL_ALL(bezt);
|
||||
break;
|
||||
case SEL_INVERT:
|
||||
gpc_pt->flag ^= GP_CURVE_POINT_SELECT;
|
||||
BEZT_SEL_INVERT(bezt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
|
||||
selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
gpc->flag |= GP_CURVE_SELECT;
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
}
|
||||
else {
|
||||
gpc->flag &= ~GP_CURVE_SELECT;
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
}
|
||||
GP_EDITABLE_STROKES_END(gps_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the #tGPspoint buffer (while drawing stroke)
|
||||
* size is enough to save all points of the stroke.
|
||||
|
|
|
@ -273,7 +273,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
|
|||
changed = true;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
|
|||
gps->uv_rotation = opdata->array_rot[i] - uv_rotation;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
|
|||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
gps->uv_scale = opdata->array_scale[i] + scale;
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ static int gpencil_reset_transform_fill_exec(bContext *C, wmOperator *op)
|
|||
gps->uv_scale = 1.0f;
|
||||
}
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -819,8 +819,9 @@ static void gpencil_save_selected_point(tGP_BrushVertexpaintData *gso,
|
|||
gso->pbuffer_used++;
|
||||
}
|
||||
|
||||
/* Select points in this stroke and add to an array to be used later. */
|
||||
static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
||||
/* Select points in this stroke and add to an array to be used later.
|
||||
* Returns true if any point was hit and got saved */
|
||||
static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
||||
bGPDstroke *gps,
|
||||
const char tool,
|
||||
const float diff_mat[4][4])
|
||||
|
@ -841,9 +842,11 @@ static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
|||
int index;
|
||||
bool include_last = false;
|
||||
|
||||
bool saved = false;
|
||||
|
||||
/* Check if the stroke collide with brush. */
|
||||
if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gps->totpoints == 1) {
|
||||
|
@ -862,6 +865,7 @@ static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
|||
/* apply operation to this point */
|
||||
if (pt_active != NULL) {
|
||||
gpencil_save_selected_point(gso, gps_active, 0, pc1);
|
||||
saved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -913,6 +917,7 @@ static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
|||
}
|
||||
hit = true;
|
||||
gpencil_save_selected_point(gso, gps_active, index, pc1);
|
||||
saved = true;
|
||||
}
|
||||
|
||||
/* Only do the second point if this is the last segment,
|
||||
|
@ -931,6 +936,7 @@ static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
|||
hit = true;
|
||||
gpencil_save_selected_point(gso, gps_active, index, pc2);
|
||||
include_last = false;
|
||||
saved = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -949,8 +955,8 @@ static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
|||
if (pt_active != NULL) {
|
||||
hit = true;
|
||||
gpencil_save_selected_point(gso, gps_active, index, pc1);
|
||||
|
||||
include_last = false;
|
||||
saved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -970,10 +976,13 @@ static void gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
|
|||
for (int repeat = 0; repeat < 50; repeat++) {
|
||||
gpencil_save_selected_point(gso, gps_active, -1, NULL);
|
||||
}
|
||||
saved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
/* Apply vertex paint brushes to strokes in the given frame. */
|
||||
|
@ -1008,7 +1017,13 @@ static bool gpencil_vertexpaint_brush_do_frame(bContext *C,
|
|||
}
|
||||
|
||||
/* Check points below the brush. */
|
||||
gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat);
|
||||
bool hit = gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat);
|
||||
|
||||
/* If stroke was hit and has an editcurve the curve needs an update. */
|
||||
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
|
||||
if (gps_active->editcurve != NULL && hit) {
|
||||
gps_active->editcurve->flag |= GP_CURVE_NEEDS_STROKE_UPDATE;
|
||||
}
|
||||
}
|
||||
|
||||
/* For Average tool, need calculate the average resulting color from all colors
|
||||
|
|
|
@ -314,7 +314,8 @@ void ED_gpencil_update_color_uv(struct Main *bmain, struct Material *mat);
|
|||
* 2 - Hit in point B
|
||||
* 3 - Hit in point A and B
|
||||
*/
|
||||
int ED_gpencil_select_stroke_segment(struct bGPDlayer *gpl,
|
||||
int ED_gpencil_select_stroke_segment(struct bGPdata *gpd,
|
||||
struct bGPDlayer *gpl,
|
||||
struct bGPDstroke *gps,
|
||||
struct bGPDspoint *pt,
|
||||
bool select,
|
||||
|
@ -324,6 +325,7 @@ int ED_gpencil_select_stroke_segment(struct bGPDlayer *gpl,
|
|||
float r_hitb[3]);
|
||||
|
||||
void ED_gpencil_select_toggle_all(struct bContext *C, int action);
|
||||
void ED_gpencil_select_curve_toggle_all(struct bContext *C, int action);
|
||||
|
||||
/* Ensure stroke sbuffer size is enough */
|
||||
struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
|
||||
|
|
|
@ -1738,6 +1738,10 @@ static void ed_default_handlers(
|
|||
wmKeyMap *keymap_general = WM_keymap_ensure(wm->defaultconf, "Grease Pencil", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap_general);
|
||||
|
||||
wmKeyMap *keymap_curve_edit = WM_keymap_ensure(
|
||||
wm->defaultconf, "Grease Pencil Stroke Curve Edit Mode", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap_curve_edit);
|
||||
|
||||
wmKeyMap *keymap_edit = WM_keymap_ensure(
|
||||
wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap_edit);
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_gpencil_curve.h"
|
||||
#include "BKE_gpencil_geom.h"
|
||||
|
||||
#include "ED_gpencil.h"
|
||||
|
@ -63,33 +65,351 @@ static void createTransGPencil_center_get(bGPDstroke *gps, float r_center[3])
|
|||
}
|
||||
}
|
||||
|
||||
void createTransGPencil(bContext *C, TransInfo *t)
|
||||
static short get_bezt_sel_triple_flag(BezTriple *bezt, const bool handles_visible)
|
||||
{
|
||||
if (t->data_container_len == 0) {
|
||||
#define SEL_F1 (1 << 0)
|
||||
#define SEL_F2 (1 << 1)
|
||||
#define SEL_F3 (1 << 2)
|
||||
#define SEL_ALL ((1 << 0) | (1 << 1) | (1 << 2))
|
||||
|
||||
short flag = 0;
|
||||
|
||||
if (handles_visible) {
|
||||
flag = ((bezt->f1 & SELECT) ? SEL_F1 : 0) | ((bezt->f2 & SELECT) ? SEL_F2 : 0) |
|
||||
((bezt->f3 & SELECT) ? SEL_F3 : 0);
|
||||
}
|
||||
else {
|
||||
if (bezt->f2 & SELECT) {
|
||||
flag = SEL_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Special case for auto & aligned handles */
|
||||
if (flag != SEL_ALL && flag & SEL_F2) {
|
||||
if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) {
|
||||
flag = SEL_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SEL_F1
|
||||
#undef SEL_F2
|
||||
#undef SEL_F3
|
||||
return flag;
|
||||
}
|
||||
|
||||
static void createTransGPencil_curves(bContext *C,
|
||||
TransInfo *t,
|
||||
Depsgraph *depsgraph,
|
||||
ToolSettings *ts,
|
||||
Object *obact,
|
||||
bGPdata *gpd,
|
||||
const int cfra_scene,
|
||||
const bool is_multiedit,
|
||||
const bool use_multiframe_falloff,
|
||||
const bool is_prop_edit,
|
||||
const bool is_prop_edit_connected,
|
||||
const bool is_scale_thickness)
|
||||
{
|
||||
#define SEL_F1 (1 << 0)
|
||||
#define SEL_F2 (1 << 1)
|
||||
#define SEL_F3 (1 << 2)
|
||||
|
||||
View3D *v3d = t->view;
|
||||
const bool handle_only_selected_visible = (v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
|
||||
const bool handle_all_visible = (v3d->overlay.handle_display == CURVE_HANDLE_ALL);
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
tc->data_len = 0;
|
||||
|
||||
/* Number of selected curve points */
|
||||
uint32_t tot_curve_points = 0, tot_sel_curve_points = 0, tot_points = 0, tot_sel_points = 0;
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
/* Only editable and visible layers are considered. */
|
||||
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
|
||||
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
|
||||
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
|
||||
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
/* skip strokes that are invalid for current view */
|
||||
if (ED_gpencil_stroke_can_use(C, gps) == false) {
|
||||
continue;
|
||||
}
|
||||
/* Check if the color is editable. */
|
||||
if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
|
||||
continue;
|
||||
}
|
||||
/* Check if stroke has an editcurve */
|
||||
if (gps->editcurve == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
if (bezt->hide) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool handles_visible = (handle_all_visible ||
|
||||
(handle_only_selected_visible &&
|
||||
(gpc_pt->flag & GP_CURVE_POINT_SELECT)));
|
||||
|
||||
const short sel_flag = get_bezt_sel_triple_flag(bezt, handles_visible);
|
||||
if (sel_flag & (SEL_F1 | SEL_F2 | SEL_F3)) {
|
||||
if (sel_flag & SEL_F1) {
|
||||
tot_sel_points++;
|
||||
}
|
||||
if (sel_flag & SEL_F2) {
|
||||
tot_sel_points++;
|
||||
}
|
||||
if (sel_flag & SEL_F3) {
|
||||
tot_sel_points++;
|
||||
}
|
||||
tot_sel_curve_points++;
|
||||
}
|
||||
|
||||
if (is_prop_edit) {
|
||||
tot_points += 3;
|
||||
tot_curve_points++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If not multiedit out of loop. */
|
||||
if (!is_multiedit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((is_prop_edit && !is_prop_edit_connected) ? tot_curve_points : tot_sel_points) == 0) {
|
||||
tc->data_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
ToolSettings *ts = CTX_data_tool_settings(C);
|
||||
int data_len_pt = 0;
|
||||
|
||||
bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
|
||||
bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
|
||||
if (is_prop_edit) {
|
||||
tc->data_len = tot_points;
|
||||
data_len_pt = tot_curve_points;
|
||||
}
|
||||
else {
|
||||
tc->data_len = tot_sel_points;
|
||||
data_len_pt = tot_sel_curve_points;
|
||||
}
|
||||
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
if (tc->data_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
transform_around_single_fallback_ex(t, data_len_pt);
|
||||
|
||||
tc->data = MEM_callocN(tc->data_len * sizeof(TransData), __func__);
|
||||
TransData *td = tc->data;
|
||||
|
||||
const bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
|
||||
transform_mode_use_local_origins(t));
|
||||
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
/* Only editable and visible layers are considered. */
|
||||
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
|
||||
const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
|
||||
float diff_mat[4][4], mtx[3][3];
|
||||
float smtx[3][3];
|
||||
|
||||
/* Init multiframe falloff options. */
|
||||
int f_init = 0;
|
||||
int f_end = 0;
|
||||
|
||||
if (use_multiframe_falloff) {
|
||||
BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
|
||||
}
|
||||
|
||||
if ((gpf->framenum != cfra) && (!is_multiedit)) {
|
||||
gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
|
||||
/* in some weird situations (framelock enabled) return NULL */
|
||||
if (gpf == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (!is_multiedit) {
|
||||
init_gpf = gpf;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate difference matrix. */
|
||||
BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
|
||||
copy_m3_m4(mtx, diff_mat);
|
||||
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
|
||||
|
||||
for (gpf = init_gpf; gpf; gpf = gpf->next) {
|
||||
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
|
||||
/* If multi-frame and falloff, recalculate and save value. */
|
||||
float falloff = 1.0f; /* by default no falloff */
|
||||
if ((is_multiedit) && (use_multiframe_falloff)) {
|
||||
/* Falloff depends on distance to active frame
|
||||
* (relative to the overall frame range). */
|
||||
falloff = BKE_gpencil_multiframe_falloff_calc(
|
||||
gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
/* skip strokes that are invalid for current view */
|
||||
if (ED_gpencil_stroke_can_use(C, gps) == false) {
|
||||
continue;
|
||||
}
|
||||
/* Check if the color is editable. */
|
||||
if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
|
||||
continue;
|
||||
}
|
||||
/* Check if stroke has an editcurve */
|
||||
if (gps->editcurve == NULL) {
|
||||
continue;
|
||||
}
|
||||
TransData *head, *tail;
|
||||
head = tail = td;
|
||||
|
||||
gps->runtime.multi_frame_falloff = falloff;
|
||||
bool need_handle_recalc = false;
|
||||
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
if (bezt->hide) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TransDataCurveHandleFlags *hdata = NULL;
|
||||
bool bezt_use = false;
|
||||
const bool handles_visible = (handle_all_visible ||
|
||||
(handle_only_selected_visible &&
|
||||
(gpc_pt->flag & GP_CURVE_POINT_SELECT)));
|
||||
const short sel_flag = get_bezt_sel_triple_flag(bezt, handles_visible);
|
||||
/* Iterate over bezier triple */
|
||||
for (int j = 0; j < 3; j++) {
|
||||
bool is_ctrl_point = (j == 1);
|
||||
bool sel = sel_flag & (1 << j);
|
||||
|
||||
if (is_prop_edit || sel) {
|
||||
copy_v3_v3(td->iloc, bezt->vec[j]);
|
||||
td->loc = bezt->vec[j];
|
||||
bool rotate_around_ctrl = !handles_visible ||
|
||||
(t->around == V3D_AROUND_LOCAL_ORIGINS) ||
|
||||
(bezt->f2 & SELECT);
|
||||
copy_v3_v3(td->center, bezt->vec[rotate_around_ctrl ? 1 : j]);
|
||||
|
||||
if (!handles_visible || is_ctrl_point) {
|
||||
if (bezt->f2 & SELECT) {
|
||||
td->flag = TD_SELECTED;
|
||||
}
|
||||
else {
|
||||
td->flag = 0;
|
||||
}
|
||||
}
|
||||
else if (handles_visible) {
|
||||
if (BEZT_ISSEL_IDX(bezt, j)) {
|
||||
td->flag = TD_SELECTED;
|
||||
}
|
||||
else {
|
||||
td->flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
td->ext = NULL;
|
||||
if (is_ctrl_point) {
|
||||
if (t->mode != TFM_MIRROR) {
|
||||
if (t->mode != TFM_GPENCIL_OPACITY) {
|
||||
if (is_scale_thickness) {
|
||||
td->val = &(gpc_pt->pressure);
|
||||
td->ival = gpc_pt->pressure;
|
||||
}
|
||||
}
|
||||
else {
|
||||
td->val = &(gpc_pt->strength);
|
||||
td->ival = gpc_pt->strength;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
td->val = NULL;
|
||||
}
|
||||
|
||||
if (hdata == NULL) {
|
||||
if (is_ctrl_point && ((sel_flag & SEL_F1 & SEL_F3) == 0)) {
|
||||
hdata = initTransDataCurveHandles(td, bezt);
|
||||
}
|
||||
else if (!is_ctrl_point) {
|
||||
hdata = initTransDataCurveHandles(td, bezt);
|
||||
}
|
||||
}
|
||||
|
||||
td->extra = gps;
|
||||
td->ob = obact;
|
||||
|
||||
copy_m3_m3(td->smtx, smtx);
|
||||
copy_m3_m3(td->mtx, mtx);
|
||||
copy_m3_m3(td->axismtx, mtx);
|
||||
|
||||
td++;
|
||||
tail++;
|
||||
}
|
||||
|
||||
bezt_use |= sel;
|
||||
}
|
||||
|
||||
/* Update the handle types so transformation is possible */
|
||||
if (bezt_use && !ELEM(t->mode, TFM_GPENCIL_OPACITY, TFM_GPENCIL_SHRINKFATTEN)) {
|
||||
BKE_nurb_bezt_handle_test(
|
||||
bezt, SELECT, handles_visible, use_around_origins_for_handles_test);
|
||||
need_handle_recalc = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_prop_edit && (head != tail)) {
|
||||
calc_distanceCurveVerts(head, tail - 1, is_cyclic);
|
||||
}
|
||||
|
||||
if (need_handle_recalc) {
|
||||
BKE_gpencil_editcurve_recalculate_handles(gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If not multiedit out of loop. */
|
||||
if (!is_multiedit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef SEL_F1
|
||||
#undef SEL_F2
|
||||
#undef SEL_F3
|
||||
}
|
||||
|
||||
static void createTransGPencil_strokes(bContext *C,
|
||||
TransInfo *t,
|
||||
Depsgraph *depsgraph,
|
||||
ToolSettings *ts,
|
||||
Object *obact,
|
||||
bGPdata *gpd,
|
||||
const int cfra_scene,
|
||||
const bool is_multiedit,
|
||||
const bool use_multiframe_falloff,
|
||||
const bool is_prop_edit,
|
||||
const bool is_prop_edit_connected,
|
||||
const bool is_scale_thickness)
|
||||
{
|
||||
TransData *td = NULL;
|
||||
float mtx[3][3], smtx[3][3];
|
||||
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
const int cfra_scene = CFRA;
|
||||
|
||||
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
|
||||
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
|
||||
const bool is_scale_thickness = ((t->mode == TFM_GPENCIL_SHRINKFATTEN) ||
|
||||
(ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS));
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
/* == Grease Pencil Strokes to Transform Data ==
|
||||
* Grease Pencil stroke points can be a mixture of 2D (screen-space),
|
||||
* or 3D coordinates. However, they're always saved as 3D points.
|
||||
|
@ -98,15 +418,6 @@ void createTransGPencil(bContext *C, TransInfo *t)
|
|||
*/
|
||||
tc->data_len = 0;
|
||||
|
||||
if (gpd == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* initialize falloff curve */
|
||||
if (is_multiedit) {
|
||||
BKE_curvemapping_init(ts->gp_sculpt.cur_falloff);
|
||||
}
|
||||
|
||||
/* First Pass: Count the number of data-points required for the strokes,
|
||||
* (and additional info about the configuration - e.g. 2D/3D?).
|
||||
*/
|
||||
|
@ -368,6 +679,71 @@ void createTransGPencil(bContext *C, TransInfo *t)
|
|||
}
|
||||
}
|
||||
|
||||
void createTransGPencil(bContext *C, TransInfo *t)
|
||||
{
|
||||
if (t->data_container_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
bGPdata *gpd = obact->data;
|
||||
BLI_assert(gpd != NULL);
|
||||
|
||||
const int cfra_scene = CFRA;
|
||||
|
||||
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
|
||||
const bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) !=
|
||||
0;
|
||||
|
||||
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
|
||||
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
|
||||
const bool is_scale_thickness = ((t->mode == TFM_GPENCIL_SHRINKFATTEN) ||
|
||||
(ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS));
|
||||
|
||||
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
|
||||
|
||||
/* initialize falloff curve */
|
||||
if (is_multiedit) {
|
||||
BKE_curvemapping_init(ts->gp_sculpt.cur_falloff);
|
||||
}
|
||||
|
||||
if (gpd == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_curve_edit) {
|
||||
createTransGPencil_curves(C,
|
||||
t,
|
||||
depsgraph,
|
||||
ts,
|
||||
obact,
|
||||
gpd,
|
||||
cfra_scene,
|
||||
is_multiedit,
|
||||
use_multiframe_falloff,
|
||||
is_prop_edit,
|
||||
is_prop_edit_connected,
|
||||
is_scale_thickness);
|
||||
}
|
||||
else {
|
||||
createTransGPencil_strokes(C,
|
||||
t,
|
||||
depsgraph,
|
||||
ts,
|
||||
obact,
|
||||
gpd,
|
||||
cfra_scene,
|
||||
is_multiedit,
|
||||
use_multiframe_falloff,
|
||||
is_prop_edit,
|
||||
is_prop_edit_connected,
|
||||
is_scale_thickness);
|
||||
}
|
||||
}
|
||||
|
||||
/* force recalculation of triangles during transformation */
|
||||
void recalcData_gpencil_strokes(TransInfo *t)
|
||||
{
|
||||
|
@ -375,13 +751,19 @@ void recalcData_gpencil_strokes(TransInfo *t)
|
|||
GHash *strokes = BLI_ghash_ptr_new(__func__);
|
||||
|
||||
TransData *td = tc->data;
|
||||
bGPdata *gpd = td->ob->data;
|
||||
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
|
||||
for (int i = 0; i < tc->data_len; i++, td++) {
|
||||
bGPDstroke *gps = td->extra;
|
||||
|
||||
if ((gps != NULL) && (!BLI_ghash_haskey(strokes, gps))) {
|
||||
BLI_ghash_insert(strokes, gps, gps);
|
||||
if (is_curve_edit && gps->editcurve != NULL) {
|
||||
BKE_gpencil_editcurve_recalculate_handles(gps);
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
}
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
BLI_ghash_free(strokes, NULL, NULL);
|
||||
|
|
|
@ -799,7 +799,7 @@ void postTrans(bContext *C, TransInfo *t)
|
|||
if (t->data_len_all != 0) {
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
/* free data malloced per trans-data */
|
||||
if (ELEM(t->obedit_type, OB_CURVE, OB_SURF) || (t->spacetype == SPACE_GRAPH)) {
|
||||
if (ELEM(t->obedit_type, OB_CURVE, OB_SURF, OB_GPENCIL) || (t->spacetype == SPACE_GRAPH)) {
|
||||
TransData *td = tc->data;
|
||||
for (int a = 0; a < tc->data_len; a++, td++) {
|
||||
if (td->flag & TD_BEZTRIPLE) {
|
||||
|
|
|
@ -653,6 +653,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
|
|||
Object *ob = OBACT(view_layer);
|
||||
bGPdata *gpd = CTX_data_gpencil_data(C);
|
||||
const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
|
||||
const bool is_curve_edit = GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
|
||||
int a, totsel = 0;
|
||||
|
||||
const int pivot_point = scene->toolsettings->transform_pivot_point;
|
||||
|
@ -711,16 +712,39 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* we're only interested in selected points here... */
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
if (is_curve_edit) {
|
||||
if (gps->editcurve == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Change selection status of all points, then make the stroke match */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
if (pt->flag & GP_SPOINT_SELECT) {
|
||||
calc_tw_center_with_matrix(tbounds, &pt->x, use_mat_local, diff_mat);
|
||||
totsel++;
|
||||
bGPDcurve *gpc = gps->editcurve;
|
||||
if (gpc->flag & GP_CURVE_SELECT) {
|
||||
for (uint32_t i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
if (gpc_pt->flag & GP_CURVE_POINT_SELECT) {
|
||||
for (uint32_t j = 0; j < 3; j++) {
|
||||
if (BEZT_ISSEL_IDX(bezt, j)) {
|
||||
calc_tw_center_with_matrix(tbounds, bezt->vec[j], use_mat_local, diff_mat);
|
||||
totsel++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* we're only interested in selected points here... */
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
/* Change selection status of all points, then make the stroke match */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
if (pt->flag & GP_SPOINT_SELECT) {
|
||||
calc_tw_center_with_matrix(tbounds, &pt->x, use_mat_local, diff_mat);
|
||||
totsel++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
@ -68,8 +70,16 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
|
|||
BLI_snprintf(str, sizeof(str), TIP_("Opacity: %3f"), ratio);
|
||||
}
|
||||
|
||||
bool recalc = false;
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
bGPdata *gpd = td->ob->data;
|
||||
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
|
||||
/* Only recalculate data when in curve edit mode. */
|
||||
if (is_curve_edit) {
|
||||
recalc = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
|
@ -84,6 +94,10 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
|
|||
}
|
||||
}
|
||||
|
||||
if (recalc) {
|
||||
recalcData(t);
|
||||
}
|
||||
|
||||
ED_area_status_text(t->area, str);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "BKE_context.h"
|
||||
#include "BKE_unit.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
@ -68,8 +70,16 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
|
|||
BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio);
|
||||
}
|
||||
|
||||
bool recalc = false;
|
||||
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
|
||||
TransData *td = tc->data;
|
||||
bGPdata *gpd = td->ob->data;
|
||||
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
|
||||
/* Only recalculate data when in curve edit mode. */
|
||||
if (is_curve_edit) {
|
||||
recalc = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < tc->data_len; i++, td++) {
|
||||
if (td->flag & TD_SKIP) {
|
||||
continue;
|
||||
|
@ -86,6 +96,10 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
|
|||
}
|
||||
}
|
||||
|
||||
if (recalc) {
|
||||
recalcData(t);
|
||||
}
|
||||
|
||||
ED_area_status_text(t->area, str);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,10 +125,11 @@ static void deformStroke(GpencilModifierData *md,
|
|||
if (!mmd->object) {
|
||||
return;
|
||||
}
|
||||
bGPdata *gpd = ob->data;
|
||||
|
||||
gpencil_deform_verts(mmd, ob, gps);
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
static void bakeModifier(Main *UNUSED(bmain),
|
||||
|
|
|
@ -255,7 +255,7 @@ static void generate_geometry(GpencilModifierData *md,
|
|||
/* Duplicate original strokes to create this instance. */
|
||||
LISTBASE_FOREACH_BACKWARD (tmpStrokes *, iter, &stroke_cache) {
|
||||
/* Duplicate stroke */
|
||||
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(iter->gps, true);
|
||||
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(iter->gps, true, true);
|
||||
|
||||
/* Move points */
|
||||
for (int i = 0; i < iter->gps->totpoints; i++) {
|
||||
|
|
|
@ -115,7 +115,8 @@ static void gpf_clear_all_strokes(bGPDframe *gpf)
|
|||
*
|
||||
* Note: This won't be called if all points are present/removed
|
||||
*/
|
||||
static void reduce_stroke_points(bGPDstroke *gps,
|
||||
static void reduce_stroke_points(bGPdata *gpd,
|
||||
bGPDstroke *gps,
|
||||
const int num_points,
|
||||
const eBuildGpencil_Transition transition)
|
||||
{
|
||||
|
@ -180,7 +181,7 @@ static void reduce_stroke_points(bGPDstroke *gps,
|
|||
gps->totpoints = num_points;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
@ -197,7 +198,10 @@ typedef struct tStrokeBuildDetails {
|
|||
} tStrokeBuildDetails;
|
||||
|
||||
/* Sequential - Show strokes one after the other */
|
||||
static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
|
||||
static void build_sequential(BuildGpencilModifierData *mmd,
|
||||
bGPdata *gpd,
|
||||
bGPDframe *gpf,
|
||||
float fac)
|
||||
{
|
||||
const size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
|
||||
bGPDstroke *gps;
|
||||
|
@ -236,25 +240,25 @@ static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
|
|||
size_t last_visible = 0;
|
||||
|
||||
switch (mmd->transition) {
|
||||
/* Show in forward order
|
||||
* - As fac increases, the number of visible points increases
|
||||
*/
|
||||
/* Show in forward order
|
||||
* - As fac increases, the number of visible points increases
|
||||
*/
|
||||
case GP_BUILD_TRANSITION_GROW:
|
||||
first_visible = 0; /* always visible */
|
||||
last_visible = (size_t)roundf(totpoints * fac);
|
||||
break;
|
||||
|
||||
/* Hide in reverse order
|
||||
* - As fac increases, the number of points visible at the end decreases
|
||||
*/
|
||||
/* Hide in reverse order
|
||||
* - As fac increases, the number of points visible at the end decreases
|
||||
*/
|
||||
case GP_BUILD_TRANSITION_SHRINK:
|
||||
first_visible = 0; /* always visible (until last point removed) */
|
||||
last_visible = (size_t)(totpoints * (1.0f - fac));
|
||||
break;
|
||||
|
||||
/* Hide in forward order
|
||||
* - As fac increases, the early points start getting hidden
|
||||
*/
|
||||
/* Hide in forward order
|
||||
* - As fac increases, the early points start getting hidden
|
||||
*/
|
||||
case GP_BUILD_TRANSITION_FADE:
|
||||
first_visible = (size_t)(totpoints * fac);
|
||||
last_visible = totpoints; /* i.e. visible until the end, unless first overlaps this */
|
||||
|
@ -278,12 +282,12 @@ static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
|
|||
else if (first_visible > cell->start_idx) {
|
||||
/* Starts partway through this stroke */
|
||||
int num_points = cell->end_idx - first_visible;
|
||||
reduce_stroke_points(cell->gps, num_points, mmd->transition);
|
||||
reduce_stroke_points(gpd, cell->gps, num_points, mmd->transition);
|
||||
}
|
||||
else {
|
||||
/* Ends partway through this stroke */
|
||||
int num_points = last_visible - cell->start_idx;
|
||||
reduce_stroke_points(cell->gps, num_points, mmd->transition);
|
||||
reduce_stroke_points(gpd, cell->gps, num_points, mmd->transition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +299,10 @@ static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
|
|||
/* --------------------------------------------- */
|
||||
|
||||
/* Concurrent - Show multiple strokes at once */
|
||||
static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac)
|
||||
static void build_concurrent(BuildGpencilModifierData *mmd,
|
||||
bGPdata *gpd,
|
||||
bGPDframe *gpf,
|
||||
float fac)
|
||||
{
|
||||
bGPDstroke *gps, *gps_next;
|
||||
int max_points = 0;
|
||||
|
@ -390,16 +397,14 @@ static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
|
|||
}
|
||||
else if (num_points < gps->totpoints) {
|
||||
/* Remove some points */
|
||||
reduce_stroke_points(gps, num_points, mmd->transition);
|
||||
reduce_stroke_points(gpd, gps, num_points, mmd->transition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
static void generate_geometry(GpencilModifierData *md,
|
||||
Depsgraph *depsgraph,
|
||||
bGPDlayer *gpl,
|
||||
bGPDframe *gpf)
|
||||
static void generate_geometry(
|
||||
GpencilModifierData *md, Depsgraph *depsgraph, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf)
|
||||
{
|
||||
BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
|
||||
const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
|
||||
|
@ -504,11 +509,11 @@ static void generate_geometry(GpencilModifierData *md,
|
|||
/* Time management mode */
|
||||
switch (mmd->mode) {
|
||||
case GP_BUILD_MODE_SEQUENTIAL:
|
||||
build_sequential(mmd, gpf, fac);
|
||||
build_sequential(mmd, gpd, gpf, fac);
|
||||
break;
|
||||
|
||||
case GP_BUILD_MODE_CONCURRENT:
|
||||
build_concurrent(mmd, gpf, fac);
|
||||
build_concurrent(mmd, gpd, gpf, fac);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -530,7 +535,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
|
|||
if (gpf == NULL) {
|
||||
continue;
|
||||
}
|
||||
generate_geometry(md, depsgraph, gpl, gpf);
|
||||
generate_geometry(md, depsgraph, gpd, gpl, gpf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -228,6 +228,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
mmd->flag & GP_HOOK_INVERT_MATERIAL)) {
|
||||
return;
|
||||
}
|
||||
bGPdata *gpd = ob->data;
|
||||
|
||||
/* init struct */
|
||||
tData.curfalloff = mmd->curfalloff;
|
||||
|
@ -273,7 +274,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
gpencil_hook_co_apply(&tData, weight, pt);
|
||||
}
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
/* FIXME: Ideally we be doing this on a copy of the main depsgraph
|
||||
|
|
|
@ -85,6 +85,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
bGPDframe *UNUSED(gpf),
|
||||
bGPDstroke *gps)
|
||||
{
|
||||
bGPdata *gpd = ob->data;
|
||||
LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
|
||||
const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
|
||||
|
||||
|
@ -121,7 +122,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
(struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight);
|
||||
}
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
/* FIXME: Ideally we be doing this on a copy of the main depsgraph
|
||||
|
|
|
@ -151,7 +151,7 @@ static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gp
|
|||
mmd->flag & GP_MIRROR_INVERT_PASS,
|
||||
mmd->flag & GP_MIRROR_INVERT_LAYERPASS,
|
||||
mmd->flag & GP_MIRROR_INVERT_MATERIAL)) {
|
||||
gps_new = BKE_gpencil_stroke_duplicate(gps, true);
|
||||
gps_new = BKE_gpencil_stroke_duplicate(gps, true, true);
|
||||
update_position(ob, mmd, gps_new, xi);
|
||||
BLI_addtail(&gpf->strokes, gps_new);
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ static void duplicateStroke(Object *ob,
|
|||
float fading_thickness,
|
||||
float fading_opacity)
|
||||
{
|
||||
bGPdata *gpd = ob->data;
|
||||
int i;
|
||||
bGPDstroke *new_gps = NULL;
|
||||
float stroke_normal[3];
|
||||
|
@ -172,7 +173,7 @@ static void duplicateStroke(Object *ob,
|
|||
* to be processed, since we duplicate its data. */
|
||||
for (i = count - 1; i >= 0; i--) {
|
||||
if (i != 0) {
|
||||
new_gps = BKE_gpencil_stroke_duplicate(gps, true);
|
||||
new_gps = BKE_gpencil_stroke_duplicate(gps, true, true);
|
||||
BLI_addtail(results, new_gps);
|
||||
}
|
||||
else {
|
||||
|
@ -199,7 +200,7 @@ static void duplicateStroke(Object *ob,
|
|||
}
|
||||
/* Calc geometry data. */
|
||||
if (new_gps != NULL) {
|
||||
BKE_gpencil_stroke_geometry_update(new_gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, new_gps);
|
||||
}
|
||||
MEM_freeN(t1_array);
|
||||
MEM_freeN(t2_array);
|
||||
|
|
|
@ -100,6 +100,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
mmd->flag & GP_OFFSET_INVERT_MATERIAL)) {
|
||||
return;
|
||||
}
|
||||
bGPdata *gpd = ob->data;
|
||||
|
||||
for (int i = 0; i < gps->totpoints; i++) {
|
||||
bGPDspoint *pt = &gps->points[i];
|
||||
|
@ -125,7 +126,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
mul_m4_v3(mat, &pt->x);
|
||||
}
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
static void bakeModifier(struct Main *UNUSED(bmain),
|
||||
|
|
|
@ -92,26 +92,26 @@ static void deformStroke(GpencilModifierData *md,
|
|||
mmd->flag & GP_SIMPLIFY_INVERT_MATERIAL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bGPdata *gpd = ob->data;
|
||||
/* Select simplification mode. */
|
||||
switch (mmd->mode) {
|
||||
case GP_SIMPLIFY_FIXED: {
|
||||
for (int i = 0; i < mmd->step; i++) {
|
||||
BKE_gpencil_stroke_simplify_fixed(gps);
|
||||
BKE_gpencil_stroke_simplify_fixed(gpd, gps);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GP_SIMPLIFY_ADAPTIVE: {
|
||||
/* simplify stroke using Ramer-Douglas-Peucker algorithm */
|
||||
BKE_gpencil_stroke_simplify_adaptive(gps, mmd->factor);
|
||||
BKE_gpencil_stroke_simplify_adaptive(gpd, gps, mmd->factor);
|
||||
break;
|
||||
}
|
||||
case GP_SIMPLIFY_SAMPLE: {
|
||||
BKE_gpencil_stroke_sample(gps, mmd->length, false);
|
||||
BKE_gpencil_stroke_sample(gpd, gps, mmd->length, false);
|
||||
break;
|
||||
}
|
||||
case GP_SIMPLIFY_MERGE: {
|
||||
BKE_gpencil_stroke_merge_distance(gpf, gps, mmd->distance, true);
|
||||
BKE_gpencil_stroke_merge_distance(gpd, gpf, gps, mmd->distance, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -80,6 +80,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
bGPDstroke *gps)
|
||||
{
|
||||
SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
|
||||
bGPdata *gpd = ob->data;
|
||||
|
||||
/* It makes sense when adding points to a straight line */
|
||||
/* e.g. for creating thickness variation in later modifiers. */
|
||||
|
@ -100,7 +101,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
return;
|
||||
}
|
||||
|
||||
BKE_gpencil_stroke_subdivide(gps, mmd->level, mmd->type);
|
||||
BKE_gpencil_stroke_subdivide(gpd, gps, mmd->level, mmd->type);
|
||||
|
||||
/* If the stroke is cyclic, must generate the closing geometry. */
|
||||
if (gps->flag & GP_STROKE_CYCLIC) {
|
||||
|
|
|
@ -82,6 +82,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
{
|
||||
TextureGpencilModifierData *mmd = (TextureGpencilModifierData *)md;
|
||||
const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
|
||||
bGPdata *gpd = ob->data;
|
||||
|
||||
if (!is_stroke_affected_by_modifier(ob,
|
||||
mmd->layername,
|
||||
|
@ -102,7 +103,7 @@ static void deformStroke(GpencilModifierData *md,
|
|||
gps->uv_translation[0] += mmd->fill_offset[0];
|
||||
gps->uv_translation[1] += mmd->fill_offset[1];
|
||||
gps->uv_scale *= mmd->fill_scale;
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
|
||||
if (ELEM(mmd->mode, STROKE, STROKE_AND_FILL)) {
|
||||
|
|
|
@ -519,6 +519,10 @@ typedef enum eBezTriple_KeyframeType {
|
|||
(bezt)->f2 & SELECT : \
|
||||
BEZT_ISSEL_ANY(bezt))
|
||||
|
||||
#define BEZT_ISSEL_IDX(bezt, i) \
|
||||
((i == 0 && (bezt)->f1 & SELECT) || (i == 1 && (bezt)->f2 & SELECT) || \
|
||||
(i == 2 && (bezt)->f3 & SELECT))
|
||||
|
||||
#define BEZT_SEL_ALL(bezt) \
|
||||
{ \
|
||||
(bezt)->f1 |= SELECT; \
|
||||
|
@ -533,6 +537,49 @@ typedef enum eBezTriple_KeyframeType {
|
|||
(bezt)->f3 &= ~SELECT; \
|
||||
} \
|
||||
((void)0)
|
||||
#define BEZT_SEL_INVERT(bezt) \
|
||||
{ \
|
||||
(bezt)->f1 ^= SELECT; \
|
||||
(bezt)->f2 ^= SELECT; \
|
||||
(bezt)->f3 ^= SELECT; \
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
#define BEZT_SEL_IDX(bezt, i) \
|
||||
{ \
|
||||
switch (i) { \
|
||||
case 0: \
|
||||
(bezt)->f1 |= SELECT; \
|
||||
break; \
|
||||
case 1: \
|
||||
(bezt)->f2 |= SELECT; \
|
||||
break; \
|
||||
case 2: \
|
||||
(bezt)->f3 |= SELECT; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
#define BEZT_DESEL_IDX(bezt, i) \
|
||||
{ \
|
||||
switch (i) { \
|
||||
case 0: \
|
||||
(bezt)->f1 &= ~SELECT; \
|
||||
break; \
|
||||
case 1: \
|
||||
(bezt)->f2 &= ~SELECT; \
|
||||
break; \
|
||||
case 2: \
|
||||
(bezt)->f3 &= ~SELECT; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
((void)0)
|
||||
|
||||
#define BEZT_IS_AUTOH(bezt) \
|
||||
(ELEM((bezt)->h1, HD_AUTO, HD_AUTO_ANIM) && ELEM((bezt)->h2, HD_AUTO, HD_AUTO_ANIM))
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
struct AnimData;
|
||||
struct MDeformVert;
|
||||
struct Curve;
|
||||
|
||||
#define GP_DEFAULT_PIX_FACTOR 1.0f
|
||||
#define GP_DEFAULT_GRID_LINES 4
|
||||
|
@ -36,6 +37,10 @@ struct MDeformVert;
|
|||
|
||||
#define GP_MATERIAL_BUFFER_LEN 256
|
||||
|
||||
#define GP_DEFAULT_CURVE_RESOLUTION 32
|
||||
#define GP_DEFAULT_CURVE_ERROR 0.1f
|
||||
#define GP_DEFAULT_CURVE_EDIT_CORNER_ANGLE M_PI_2
|
||||
|
||||
/* ***************************************** */
|
||||
/* GP Stroke Points */
|
||||
|
||||
|
@ -165,6 +170,61 @@ typedef enum eGPDpalette_Flag {
|
|||
PL_PALETTE_ACTIVE = (1 << 0),
|
||||
} eGPDpalette_Flag;
|
||||
|
||||
/* ***************************************** */
|
||||
/* GP Curve Point */
|
||||
|
||||
typedef struct bGPDcurve_point {
|
||||
/** Bezier Triple for the handles and control points. */
|
||||
BezTriple bezt;
|
||||
/** Pressure of input device (from 0 to 1) at this point. */
|
||||
float pressure;
|
||||
/** Color strength (used for alpha factor). */
|
||||
float strength;
|
||||
/** Index of corresponding point in gps->points. */
|
||||
int point_index;
|
||||
|
||||
/** Additional options. */
|
||||
int flag;
|
||||
|
||||
/** Factor of uv along the stroke. */
|
||||
float uv_fac;
|
||||
/** Uv rotation for dot mode. */
|
||||
float uv_rot;
|
||||
/** Uv for fill mode. */
|
||||
float uv_fill[2];
|
||||
|
||||
/** Vertex Color RGBA (A=mix factor). */
|
||||
float vert_color[4];
|
||||
char _pad[4];
|
||||
} bGPDcurve_point;
|
||||
|
||||
/* bGPDcurve_point->flag */
|
||||
typedef enum eGPDcurve_point_Flag {
|
||||
GP_CURVE_POINT_SELECT = (1 << 0),
|
||||
} eGPDcurve_point_Flag;
|
||||
|
||||
/* ***************************************** */
|
||||
/* GP Curve */
|
||||
|
||||
/* Curve for Bezier Editing. */
|
||||
typedef struct bGPDcurve {
|
||||
/** Array of BezTriple. */
|
||||
bGPDcurve_point *curve_points;
|
||||
/** Total number of curve points. */
|
||||
int tot_curve_points;
|
||||
/** General flag. */
|
||||
short flag;
|
||||
char _pad[2];
|
||||
} bGPDcurve;
|
||||
|
||||
/* bGPDcurve_Flag->flag */
|
||||
typedef enum bGPDcurve_Flag {
|
||||
/* Flag to indicated that the stroke data has been changed and the curve needs to be refitted */
|
||||
GP_CURVE_NEEDS_STROKE_UPDATE = (1 << 0),
|
||||
/* Curve is selected */
|
||||
GP_CURVE_SELECT = (1 << 1),
|
||||
} bGPDcurve_Flag;
|
||||
|
||||
/* ***************************************** */
|
||||
/* GP Strokes */
|
||||
|
||||
|
@ -180,7 +240,8 @@ typedef struct bGPDstroke_Runtime {
|
|||
int stroke_start;
|
||||
/** Triangle offset in the ibo where this fill starts. */
|
||||
int fill_start;
|
||||
int _pad[1];
|
||||
/** Curve Handles offset in the ibo where this handle starts. */
|
||||
int curve_start;
|
||||
|
||||
/** Original stroke (used to dereference evaluated data) */
|
||||
struct bGPDstroke *gps_orig;
|
||||
|
@ -245,6 +306,9 @@ typedef struct bGPDstroke {
|
|||
/** Vertex Color for Fill (one for all stroke, A=mix factor). */
|
||||
float vert_color_fill[4];
|
||||
|
||||
/** Curve used to edit the stroke using Bezier handlers. */
|
||||
struct bGPDcurve *editcurve;
|
||||
|
||||
bGPDstroke_Runtime runtime;
|
||||
} bGPDstroke;
|
||||
|
||||
|
@ -263,6 +327,9 @@ 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),
|
||||
/* Flag to indicated that the editcurve has been changed and the stroke needs to be updated with
|
||||
* the curve data */
|
||||
GP_STROKE_NEEDS_CURVE_UPDATE = (1 << 9),
|
||||
/* 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) */
|
||||
|
@ -562,7 +629,12 @@ typedef struct bGPdata {
|
|||
ListBase layers;
|
||||
/** Settings for this data-block. */
|
||||
int flag;
|
||||
char _pad1[4];
|
||||
/** Default resolution for generated curves using curve editing method. */
|
||||
int curve_edit_resolution;
|
||||
/** Curve Editing error threshold. */
|
||||
float curve_edit_threshold;
|
||||
/** Curve Editing corner angle (less or equal is treated as corner). */
|
||||
float curve_edit_corner_angle;
|
||||
|
||||
/* Palettes */
|
||||
/** List of bGPDpalette's - Deprecated (2.78 - 2.79 only). */
|
||||
|
@ -680,6 +752,11 @@ typedef enum eGPdata_Flag {
|
|||
|
||||
/* Autolock not active layers */
|
||||
GP_DATA_AUTOLOCK_LAYERS = (1 << 20),
|
||||
|
||||
/* Enable Bezier Editing Curve (a submode of Edit mode). */
|
||||
GP_DATA_CURVE_EDIT_MODE = (1 << 21),
|
||||
/* Use adaptive curve resolution */
|
||||
GP_DATA_CURVE_ADAPTIVE_RESOLUTION = (1 << 22),
|
||||
} eGPdata_Flag;
|
||||
|
||||
/* gpd->onion_flag */
|
||||
|
@ -725,6 +802,9 @@ typedef enum eGP_DrawMode {
|
|||
GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)) && \
|
||||
((gpd)->flag & GP_DATA_STROKE_MULTIEDIT))
|
||||
|
||||
#define GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd) \
|
||||
((gpd) && ((gpd)->flag & (GP_DATA_STROKE_EDITMODE)) && ((gpd)->flag & GP_DATA_CURVE_EDIT_MODE))
|
||||
|
||||
/* Macros to check grease pencil modes */
|
||||
#define GPENCIL_ANY_MODE(gpd) \
|
||||
((gpd) && ((gpd)->flag & \
|
||||
|
|
|
@ -1090,7 +1090,7 @@ typedef struct GP_Sculpt_Settings {
|
|||
int lock_axis;
|
||||
/** Threshold for intersections */
|
||||
float isect_threshold;
|
||||
char _pad_[4];
|
||||
char _pad[4];
|
||||
/** Multiframe edit falloff effect by frame. */
|
||||
struct CurveMapping *cur_falloff;
|
||||
/** Curve used for primitive tools. */
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "BLI_math.h"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
@ -160,6 +161,7 @@ static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = {
|
|||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include "BLI_ghash.h"
|
||||
# include "BLI_listbase.h"
|
||||
# include "BLI_string_utils.h"
|
||||
|
||||
# include "WM_api.h"
|
||||
|
@ -167,6 +169,7 @@ static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = {
|
|||
# include "BKE_action.h"
|
||||
# include "BKE_animsys.h"
|
||||
# include "BKE_gpencil.h"
|
||||
# include "BKE_gpencil_curve.h"
|
||||
# include "BKE_gpencil_geom.h"
|
||||
# include "BKE_icons.h"
|
||||
|
||||
|
@ -179,6 +182,71 @@ static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
|
|||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
static void rna_GPencil_curve_edit_mode_toggle(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
bGPdata *gpd = (bGPdata *)ptr->owner_id;
|
||||
|
||||
/* Curve edit mode is turned on. */
|
||||
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
|
||||
/* If the current select mode is segment and the Bezier mode is on, change
|
||||
* to Point because segment is not supported. */
|
||||
if (ts->gpencil_selectmode_edit == GP_SELECTMODE_SEGMENT) {
|
||||
ts->gpencil_selectmode_edit = GP_SELECTMODE_POINT;
|
||||
}
|
||||
|
||||
BKE_gpencil_strokes_selected_update_editcurve(gpd);
|
||||
}
|
||||
/* Curve edit mode is turned off. */
|
||||
else {
|
||||
BKE_gpencil_strokes_selected_sync_selection_editcurve(gpd);
|
||||
}
|
||||
|
||||
/* Standard update. */
|
||||
rna_GPencil_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_GPencil_stroke_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ptr->owner_id;
|
||||
|
||||
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
if (gpl->actframe != NULL) {
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
if (gps->editcurve != NULL) {
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rna_GPencil_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_GPencil_stroke_curve_resolution_update(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ptr->owner_id;
|
||||
|
||||
if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) {
|
||||
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
|
||||
if (gpl->actframe != NULL) {
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
|
||||
if (gps->editcurve != NULL) {
|
||||
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rna_GPencil_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_GPencil_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
|
||||
{
|
||||
DEG_id_tag_update(ptr->owner_id, ID_RECALC_TRANSFORM);
|
||||
|
@ -191,11 +259,12 @@ static void rna_GPencil_dependency_update(Main *bmain, Scene *UNUSED(scene), Poi
|
|||
|
||||
static void rna_GPencil_uv_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ptr->owner_id;
|
||||
/* Force to recalc the UVs. */
|
||||
bGPDstroke *gps = (bGPDstroke *)ptr->data;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(gps);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, gps);
|
||||
|
||||
DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
|
||||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
|
||||
|
@ -669,7 +738,7 @@ static void rna_GPencil_stroke_point_add(
|
|||
stroke->totpoints += count;
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(stroke);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, stroke);
|
||||
|
||||
DEG_id_tag_update(&gpd->id,
|
||||
ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
|
||||
|
@ -730,7 +799,7 @@ static void rna_GPencil_stroke_point_pop(ID *id,
|
|||
}
|
||||
|
||||
/* Calc geometry data. */
|
||||
BKE_gpencil_stroke_geometry_update(stroke);
|
||||
BKE_gpencil_stroke_geometry_update(gpd, stroke);
|
||||
|
||||
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
|
||||
|
||||
|
@ -808,6 +877,32 @@ static void rna_GPencil_stroke_select_set(PointerRNA *ptr, const bool value)
|
|||
}
|
||||
}
|
||||
|
||||
static void rna_GPencil_curve_select_set(PointerRNA *ptr, const bool value)
|
||||
{
|
||||
bGPDcurve *gpc = ptr->data;
|
||||
|
||||
/* Set new value. */
|
||||
if (value) {
|
||||
gpc->flag |= GP_CURVE_SELECT;
|
||||
}
|
||||
else {
|
||||
gpc->flag &= ~GP_CURVE_SELECT;
|
||||
}
|
||||
/* Ensure that the curves's points are selected in the same way. */
|
||||
for (int i = 0; i < gpc->tot_curve_points; i++) {
|
||||
bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
|
||||
BezTriple *bezt = &gpc_pt->bezt;
|
||||
if (value) {
|
||||
gpc_pt->flag |= GP_CURVE_POINT_SELECT;
|
||||
BEZT_SEL_ALL(bezt);
|
||||
}
|
||||
else {
|
||||
gpc_pt->flag &= ~GP_CURVE_POINT_SELECT;
|
||||
BEZT_DESEL_ALL(bezt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer,
|
||||
ReportList *reports,
|
||||
int frame_number,
|
||||
|
@ -969,6 +1064,100 @@ static char *rna_GreasePencilGrid_path(PointerRNA *UNUSED(ptr))
|
|||
return BLI_strdup("grid");
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_handle1_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
copy_v3_v3(values, cpt->bezt.vec[0]);
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_handle1_set(PointerRNA *ptr, const float *values)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
copy_v3_v3(cpt->bezt.vec[0], values);
|
||||
}
|
||||
|
||||
static bool rna_GpencilCurvePoint_BezTriple_handle1_select_get(PointerRNA *ptr)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
return cpt->bezt.f1;
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_handle1_select_set(PointerRNA *ptr, const bool value)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
cpt->bezt.f1 = value;
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_handle2_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
copy_v3_v3(values, cpt->bezt.vec[2]);
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_handle2_set(PointerRNA *ptr, const float *values)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
copy_v3_v3(cpt->bezt.vec[2], values);
|
||||
}
|
||||
|
||||
static bool rna_GpencilCurvePoint_BezTriple_handle2_select_get(PointerRNA *ptr)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
return cpt->bezt.f3;
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_handle2_select_set(PointerRNA *ptr, const bool value)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
cpt->bezt.f3 = value;
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_ctrlpoint_get(PointerRNA *ptr, float *values)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
copy_v3_v3(values, cpt->bezt.vec[1]);
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_ctrlpoint_set(PointerRNA *ptr, const float *values)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
copy_v3_v3(cpt->bezt.vec[1], values);
|
||||
}
|
||||
|
||||
static bool rna_GpencilCurvePoint_BezTriple_ctrlpoint_select_get(PointerRNA *ptr)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
return cpt->bezt.f2;
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_ctrlpoint_select_set(PointerRNA *ptr, const bool value)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
cpt->bezt.f2 = value;
|
||||
}
|
||||
|
||||
static bool rna_GpencilCurvePoint_BezTriple_hide_get(PointerRNA *ptr)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
return (bool)cpt->bezt.hide;
|
||||
}
|
||||
|
||||
static void rna_GpencilCurvePoint_BezTriple_hide_set(PointerRNA *ptr, const bool value)
|
||||
{
|
||||
bGPDcurve_point *cpt = (bGPDcurve_point *)ptr->data;
|
||||
cpt->bezt.hide = value;
|
||||
}
|
||||
|
||||
static bool rna_stroke_has_edit_curve_get(PointerRNA *ptr)
|
||||
{
|
||||
bGPDstroke *gps = (bGPDstroke *)ptr->data;
|
||||
if (gps->editcurve != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
|
||||
|
@ -1106,6 +1295,149 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna)
|
|||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
}
|
||||
|
||||
static void rna_def_gpencil_curve_point(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "GPencilEditCurvePoint", NULL);
|
||||
RNA_def_struct_sdna(srna, "bGPDcurve_point");
|
||||
RNA_def_struct_ui_text(srna, "Bezier Curve Point", "Bezier curve point with two handles");
|
||||
|
||||
/* Boolean values */
|
||||
prop = RNA_def_property(srna, "select_left_handle", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_GpencilCurvePoint_BezTriple_handle1_select_get",
|
||||
"rna_GpencilCurvePoint_BezTriple_handle1_select_set");
|
||||
RNA_def_property_ui_text(prop, "Handle 1 selected", "Handle 1 selection status");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "select_right_handle", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_GpencilCurvePoint_BezTriple_handle2_select_get",
|
||||
"rna_GpencilCurvePoint_BezTriple_handle2_select_set");
|
||||
RNA_def_property_ui_text(prop, "Handle 2 selected", "Handle 2 selection status");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "select_control_point", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_GpencilCurvePoint_BezTriple_ctrlpoint_select_get",
|
||||
"rna_GpencilCurvePoint_BezTriple_ctrlpoint_select_set");
|
||||
RNA_def_property_ui_text(prop, "Control Point selected", "Control point selection status");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_GpencilCurvePoint_BezTriple_hide_get",
|
||||
"rna_GpencilCurvePoint_BezTriple_hide_set");
|
||||
RNA_def_property_ui_text(prop, "Hide", "Visibility status");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
/* Vector values */
|
||||
prop = RNA_def_property(srna, "handle_left", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_GpencilCurvePoint_BezTriple_handle1_get",
|
||||
"rna_GpencilCurvePoint_BezTriple_handle1_set",
|
||||
NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Handle 1", "Coordinates of the first handle");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
|
||||
prop = RNA_def_property(srna, "co", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_GpencilCurvePoint_BezTriple_ctrlpoint_get",
|
||||
"rna_GpencilCurvePoint_BezTriple_ctrlpoint_set",
|
||||
NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Control Point", "Coordinates of the control point");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
|
||||
prop = RNA_def_property(srna, "handle_right", PROP_FLOAT, PROP_TRANSLATION);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_GpencilCurvePoint_BezTriple_handle2_get",
|
||||
"rna_GpencilCurvePoint_BezTriple_handle2_set",
|
||||
NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Handle 2", "Coordinates of the second handle");
|
||||
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
|
||||
/* Pressure */
|
||||
prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "pressure");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, RNA_TRANSLATION_PREC_DEFAULT);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Pressure", "Pressure of the grease pencil stroke point");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
|
||||
/* Strength */
|
||||
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "strength");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Strength", "Color intensity (alpha factor) of the grease pencil stroke point");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
|
||||
/* read-only index */
|
||||
prop = RNA_def_property(srna, "point_index", PROP_INT, PROP_UNSIGNED);
|
||||
RNA_def_property_int_sdna(prop, NULL, "point_index");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Point Index", "Index of the corresponding grease pencil stroke point");
|
||||
|
||||
prop = RNA_def_property(srna, "uv_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "uv_fac");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "UV Factor", "Internal UV factor");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
|
||||
prop = RNA_def_property(srna, "uv_rotation", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "uv_rot");
|
||||
RNA_def_property_range(prop, -M_PI_2, M_PI_2);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "UV Rotation", "Internal UV factor for dot mode");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
|
||||
prop = RNA_def_property(srna, "vertex_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "vert_color");
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_ui_text(prop, "Vertex Color", "Vertex color of the grease pencil stroke point");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_update");
|
||||
}
|
||||
|
||||
/* Editing Curve data. */
|
||||
static void rna_def_gpencil_curve(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "GPencilEditCurve", NULL);
|
||||
RNA_def_struct_sdna(srna, "bGPDcurve");
|
||||
RNA_def_struct_ui_text(srna, "Edit Curve", "Edition Curve");
|
||||
|
||||
prop = RNA_def_property(srna, "curve_points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "curve_points", "tot_curve_points");
|
||||
RNA_def_property_struct_type(prop, "GPencilEditCurvePoint");
|
||||
RNA_def_property_ui_text(prop, "Curve Points", "Curve data points");
|
||||
|
||||
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_CURVE_SELECT);
|
||||
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_curve_select_set");
|
||||
RNA_def_property_ui_text(prop, "Select", "Curve is selected for viewport editing");
|
||||
RNA_def_property_update(prop, 0, "rna_GPencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_gpencil_mvert_group(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -1180,6 +1512,12 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
|
|||
RNA_def_property_struct_type(prop, "GPencilTriangle");
|
||||
RNA_def_property_ui_text(prop, "Triangles", "Triangulation data for HQ fill");
|
||||
|
||||
/* Edit Curve. */
|
||||
prop = RNA_def_property(srna, "edit_curve", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "editcurve");
|
||||
RNA_def_property_struct_type(prop, "GPencilEditCurve");
|
||||
RNA_def_property_ui_text(prop, "Edit Curve", "Temporary data for Edit Curve");
|
||||
|
||||
/* Material Index */
|
||||
prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "mat_nr");
|
||||
|
@ -1205,6 +1543,12 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Cyclic", "Enable cyclic drawing, closing the stroke");
|
||||
RNA_def_property_update(prop, 0, "rna_GPencil_update");
|
||||
|
||||
/* The stroke has Curve Edit data. */
|
||||
prop = RNA_def_property(srna, "has_edit_curve", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop, "rna_stroke_has_edit_curve_get", NULL);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Has Curve Data", "Stroke has Curve data to edit shape");
|
||||
|
||||
/* Caps mode */
|
||||
prop = RNA_def_property(srna, "start_cap_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "caps[0]");
|
||||
|
@ -2017,6 +2361,47 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
|
|||
"Scale conversion factor for pixel size (use larger values for thicker lines)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "edit_curve_resolution", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "curve_edit_resolution");
|
||||
RNA_def_property_range(prop, 1, 256);
|
||||
RNA_def_property_ui_range(prop, 1, 64, 1, 1);
|
||||
RNA_def_property_int_default(prop, GP_DEFAULT_CURVE_RESOLUTION);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Curve Resolution",
|
||||
"Number of segments generated between control points when editing strokes in curve mode");
|
||||
RNA_def_property_update(
|
||||
prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_resolution_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_adaptive_curve_resolution", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_CURVE_ADAPTIVE_RESOLUTION);
|
||||
RNA_def_property_boolean_default(prop, true);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Adaptive Resolution",
|
||||
"Set the resolution of each editcurve segment dynamically depending on "
|
||||
"the length of the segment. The resolution is the number of points "
|
||||
"generated per unit distance");
|
||||
RNA_def_property_update(
|
||||
prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_curve_resolution_update");
|
||||
|
||||
/* Curve editing error threshold. */
|
||||
prop = RNA_def_property(srna, "curve_edit_threshold", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "curve_edit_threshold");
|
||||
RNA_def_property_range(prop, FLT_MIN, 10.0);
|
||||
RNA_def_property_float_default(prop, GP_DEFAULT_CURVE_ERROR);
|
||||
RNA_def_property_ui_text(prop, "Threshold", "Curve conversion error threshold");
|
||||
RNA_def_property_ui_range(prop, FLT_MIN, 10.0, 2, 5);
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
/* Curve editing corner angle. */
|
||||
prop = RNA_def_property(srna, "curve_edit_corner_angle", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "curve_edit_corner_angle");
|
||||
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
|
||||
RNA_def_property_float_default(prop, DEG2RADF(90.0f));
|
||||
RNA_def_property_ui_text(prop, "Corner Angle", "Angle threshold to be treated as corners");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
prop = RNA_def_property(srna, "use_multiedit", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_MULTIEDIT);
|
||||
RNA_def_property_ui_text(prop,
|
||||
|
@ -2025,6 +2410,11 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
|
|||
"(keyframes must be selected to be included)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_curve_edit", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_CURVE_EDIT_MODE);
|
||||
RNA_def_property_ui_text(prop, "Curve Editing", "Edit strokes using curve handles");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_curve_edit_mode_toggle");
|
||||
|
||||
prop = RNA_def_property(srna, "use_autolock_layers", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_AUTOLOCK_LAYERS);
|
||||
RNA_def_property_ui_text(
|
||||
|
@ -2176,6 +2566,8 @@ void RNA_def_gpencil(BlenderRNA *brna)
|
|||
rna_def_gpencil_stroke(brna);
|
||||
rna_def_gpencil_stroke_point(brna);
|
||||
rna_def_gpencil_triangle(brna);
|
||||
rna_def_gpencil_curve(brna);
|
||||
rna_def_gpencil_curve_point(brna);
|
||||
|
||||
rna_def_gpencil_mvert_group(brna);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue