From 29f3af95272590d26f610ae828b2eeee89c82a00 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Mon, 9 Mar 2020 16:27:24 +0100 Subject: GPencil: Refactor of Draw Engine, Vertex Paint and all internal functions This commit is a full refactor of the grease pencil modules including Draw Engine, Modifiers, VFX, depsgraph update, improvements in operators and conversion of Sculpt and Weight paint tools to real brushes. Also, a huge code cleanup has been done at all levels. Thanks to @fclem for his work and yo @pepeland and @mendio for the testing and help in the development. Differential Revision: https://developer.blender.org/D6293 --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/BKE_brush.h | 13 +- source/blender/blenkernel/BKE_context.h | 3 +- source/blender/blenkernel/BKE_gpencil.h | 159 ++- source/blender/blenkernel/BKE_gpencil_modifier.h | 39 +- source/blender/blenkernel/BKE_paint.h | 17 +- source/blender/blenkernel/intern/brush.c | 1077 +++++++++++++------- source/blender/blenkernel/intern/context.c | 27 +- source/blender/blenkernel/intern/gpencil.c | 1061 +++++++++++++++---- .../blender/blenkernel/intern/gpencil_modifier.c | 358 +++---- source/blender/blenkernel/intern/lib_query.c | 9 + source/blender/blenkernel/intern/material.c | 5 +- source/blender/blenkernel/intern/object.c | 15 +- source/blender/blenkernel/intern/object_update.c | 11 +- source/blender/blenkernel/intern/paint.c | 270 +++++ source/blender/blenkernel/intern/paint_toolslots.c | 9 + source/blender/blenkernel/intern/scene.c | 90 +- 17 files changed, 2219 insertions(+), 946 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 9e4453d21fe..233c385c247 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ * \note Use #STRINGIFY() rather than defining with quotes. */ #define BLENDER_VERSION 283 -#define BLENDER_SUBVERSION 6 +#define BLENDER_SUBVERSION 7 /** Several breakages with 280, e.g. collections vs layers. */ #define BLENDER_MINVERSION 280 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 6644a3f0231..a97263a6523 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -46,13 +46,22 @@ void BKE_brush_system_exit(void); /* datablock functions */ struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode); -struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name); +struct Brush *BKE_brush_add_gpencil(struct Main *bmain, + struct ToolSettings *ts, + const char *name, + eObjectMode mode); +bool BKE_brush_delete(struct Main *bmain, struct Brush *brush); void BKE_brush_init_gpencil_settings(struct Brush *brush); struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode); struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush); void BKE_brush_sculpt_reset(struct Brush *brush); -void BKE_brush_gpencil_presets(struct Main *bmain, struct ToolSettings *ts); + +void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts); +void BKE_brush_gpencil_vertex_presets(struct Main *bmain, struct ToolSettings *ts); +void BKE_brush_gpencil_sculpt_presets(struct Main *bmain, struct ToolSettings *ts); +void BKE_brush_gpencil_weight_presets(struct Main *bmain, struct ToolSettings *ts); +void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type); /* image icon function */ struct ImBuf *get_brush_icon(struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 88a27b67963..9e2a124491c 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -115,8 +115,9 @@ typedef enum eContextObjectMode { CTX_MODE_EDIT_GPENCIL, CTX_MODE_SCULPT_GPENCIL, CTX_MODE_WEIGHT_GPENCIL, + CTX_MODE_VERTEX_GPENCIL, } eContextObjectMode; -#define CTX_MODE_NUM (CTX_MODE_WEIGHT_GPENCIL + 1) +#define CTX_MODE_NUM (CTX_MODE_VERTEX_GPENCIL + 1) /* Context */ diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 1a186d2d682..9d382775df7 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -32,19 +32,22 @@ struct BoundBox; struct Brush; struct CurveMapping; struct Depsgraph; +struct GHash; struct ListBase; struct Main; struct Material; struct Object; struct Scene; +struct SpaceImage; struct ToolSettings; struct bDeformGroup; struct bGPDframe; struct bGPDlayer; +struct bGPDlayer_Mask; struct bGPDspoint; struct bGPDstroke; struct bGPdata; - +struct MaterialGPencilStyle; struct MDeformVert; #define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)) @@ -54,18 +57,33 @@ struct MDeformVert; #define GPENCIL_SIMPLIFY_FILL(scene, playing) \ ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL))) -#define GPENCIL_SIMPLIFY_MODIF(scene, playing) \ - ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ - (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER))) +#define GPENCIL_SIMPLIFY_MODIF(scene) \ + ((GPENCIL_SIMPLIFY(scene) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER))) #define GPENCIL_SIMPLIFY_FX(scene, playing) \ ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX))) -#define GPENCIL_SIMPLIFY_BLEND(scene, playing) \ - ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ - (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND))) -#define GPENCIL_SIMPLIFY_TINT(scene, playing) \ - ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ - (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_TINT))) +#define GPENCIL_SIMPLIFY_TINT(scene) \ + ((GPENCIL_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_TINT)) +#define GPENCIL_SIMPLIFY_AA(scene) \ + ((GPENCIL_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_AA)) + +/* Vertex Color macros. */ +#define GPENCIL_USE_VERTEX_COLOR(toolsettings) \ + ((toolsettings->gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR)) +#define GPENCIL_USE_VERTEX_COLOR_STROKE(toolsettings, brush) \ + ((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \ + ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \ + (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH)))) +#define GPENCIL_USE_VERTEX_COLOR_FILL(toolsettings, brush) \ + ((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \ + ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \ + (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH)))) +#define GPENCIL_TINT_VERTEX_COLOR_STROKE(brush) \ + ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \ + (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH)) +#define GPENCIL_TINT_VERTEX_COLOR_FILL(brush) \ + ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \ + (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH)) /* ------------ Grease-Pencil API ------------------ */ @@ -75,8 +93,9 @@ void BKE_gpencil_free_stroke(struct bGPDstroke *gps); bool BKE_gpencil_free_strokes(struct bGPDframe *gpf); void BKE_gpencil_free_frames(struct bGPDlayer *gpl); void BKE_gpencil_free_layers(struct ListBase *list); -bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *gpf_eval); void BKE_gpencil_free(struct bGPdata *gpd, bool free_all); +void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval); +void BKE_gpencil_free_layer_masks(struct bGPDlayer *gpl); void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd); void BKE_gpencil_batch_cache_free(struct bGPdata *gpd); @@ -91,10 +110,11 @@ 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); +struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points); void BKE_gpencil_copy_data(struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag); struct bGPdata *BKE_gpencil_copy(struct Main *bmain, const struct bGPdata *gpd); + struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy); @@ -109,6 +129,11 @@ bool BKE_gpencil_material_index_used(struct bGPdata *gpd, int index); void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len); +bool BKE_gpencil_merge_materials_table_get(struct Object *ob, + const float hue_threshold, + const float sat_threshold, + const float val_threshold, + struct GHash *r_mat_table); /* statistics functions */ void BKE_gpencil_stats_update(struct bGPdata *gpd); @@ -124,12 +149,11 @@ void BKE_gpencil_stroke_add_points(struct bGPDstroke *gps, const int totpoints, const float mat[4][4]); -struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, - int mat_idx, - int totpoints, - short thickness); +struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness); +struct bGPDstroke *BKE_gpencil_stroke_add( + struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head); -struct bGPDstroke *BKE_gpencil_add_stroke_existing_style(struct bGPDframe *gpf, +struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf, struct bGPDstroke *existing, int mat_idx, int totpoints, @@ -139,7 +163,7 @@ struct bGPDstroke *BKE_gpencil_add_stroke_existing_style(struct bGPDframe *gpf, #define GPENCIL_ALPHA_OPACITY_THRESH 0.001f #define GPENCIL_STRENGTH_MIN 0.003f -bool gpencil_layer_is_editable(const struct bGPDlayer *gpl); +bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl); /* How gpencil_layer_getframe() should behave when there * is no existing GP-Frame on the frame requested. @@ -154,17 +178,25 @@ typedef enum eGP_GetFrame_Mode { GP_GETFRAME_ADD_COPY = 2, } eGP_GetFrame_Mode; -struct bGPDframe *BKE_gpencil_layer_getframe(struct bGPDlayer *gpl, - int cframe, - eGP_GetFrame_Mode addnew); -struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe); -bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf); +struct bGPDframe *BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, + int cframe, + eGP_GetFrame_Mode addnew); +struct bGPDframe *BKE_gpencil_layer_frame_find(struct bGPDlayer *gpl, int cframe); +bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf); -struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd); -void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active); +struct bGPDlayer *BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name); +struct bGPDlayer *BKE_gpencil_layer_active_get(struct bGPdata *gpd); +void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active); void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl); void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock); +struct bGPDlayer_Mask *BKE_gpencil_layer_mask_add(struct bGPDlayer *gpl, const char *name); +void BKE_gpencil_layer_mask_remove(struct bGPDlayer *gpl, struct bGPDlayer_Mask *mask); +void BKE_gpencil_layer_mask_remove_ref(struct bGPdata *gpd, const char *name); +struct bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name); +void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl); +void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd); + /* Brush */ struct Material *BKE_gpencil_brush_material_get(struct Brush *brush); void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material); @@ -183,9 +215,9 @@ struct Material *BKE_gpencil_object_material_new(struct Main *bmain, const char *name, int *r_index); -int BKE_gpencil_object_material_get_index(struct Object *ob, struct Material *ma); +int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma); -struct Material *BKE_gpencil_object_material_get_from_brush(struct Object *ob, +struct Material *BKE_gpencil_object_material_from_brush_get(struct Object *ob, struct Brush *brush); int BKE_gpencil_object_material_get_index_from_brush(struct Object *ob, struct Brush *brush); @@ -206,22 +238,23 @@ bool BKE_gpencil_stroke_select_check(const struct bGPDstroke *gps); struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob); void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]); +void BKE_gpencil_stroke_boundingbox_calc(struct bGPDstroke *gps); /* vertex groups */ void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps); void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup); void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst); -/* GPencil geometry evaluation */ -void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd); +/* Set active frame by layer. */ +void BKE_gpencil_frame_active_set(struct Depsgraph *depsgraph, struct bGPdata *gpd); /* stroke geometry utilities */ void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]); -void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor); -void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps); -void BKE_gpencil_subdivide(struct bGPDstroke *gps, int level, int flag); -bool BKE_gpencil_trim_stroke(struct bGPDstroke *gps); -void BKE_gpencil_merge_distance_stroke(struct bGPDframe *gpf, +void BKE_gpencil_stroke_simplify_adaptive(struct bGPDstroke *gps, float factor); +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, struct bGPDstroke *gps, const float threshold, const bool use_unselected); @@ -237,31 +270,33 @@ void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points, float (*points2d)[2], const float scale, int *r_direction); -void BKE_gpencil_triangulate_stroke_fill(struct bGPdata *gpd, struct bGPDstroke *gps); +void BKE_gpencil_stroke_fill_triangulate(struct bGPDstroke *gps); +void BKE_gpencil_stroke_geometry_update(struct bGPDstroke *gps); +void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps); void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]); -bool BKE_gpencil_sample_stroke(struct bGPDstroke *gps, const float dist, const bool select); -bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf); -bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence); -bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence); -bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence); -bool BKE_gpencil_close_stroke(struct bGPDstroke *gps); +bool BKE_gpencil_stroke_sample(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); -bool BKE_gpencil_stretch_stroke(struct bGPDstroke *gps, const float dist, const float tip_length); -bool BKE_gpencil_trim_stroke_points(struct bGPDstroke *gps, +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_split_stroke(struct bGPDframe *gpf, +bool BKE_gpencil_stroke_split(struct bGPDframe *gpf, struct bGPDstroke *gps, const int before_index, struct bGPDstroke **remaining_gps); -bool BKE_gpencil_shrink_stroke(struct bGPDstroke *gps, const float dist); +bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist); float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d); -void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe); +void BKE_gpencil_frame_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe); float BKE_gpencil_multiframe_falloff_calc( struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff); @@ -273,9 +308,41 @@ void BKE_gpencil_convert_curve(struct Main *bmain, const bool use_collections, const bool only_stroke); +void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene); + +bool BKE_gpencil_from_image(struct SpaceImage *sima, + struct bGPDframe *gpf, + const float size, + const bool mask); + +/* Iterator */ +/* frame & stroke are NULL if it is a layer callback. */ +typedef void (*gpIterCb)(struct bGPDlayer *layer, + struct bGPDframe *frame, + struct bGPDstroke *stroke, + void *thunk); + +void BKE_gpencil_visible_stroke_iter(struct Object *ob, + gpIterCb layer_cb, + gpIterCb stroke_cb, + void *thunk, + bool do_onion, + int cfra); + extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd); extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd); +void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig, + const struct bGPDframe *gpf_eval); +void BKE_gpencil_update_orig_pointers(const struct Object *ob_orig, const struct Object *ob_eval); + +void BKE_gpencil_parent_matrix_get(const struct Depsgraph *depsgraph, + struct Object *obact, + struct bGPDlayer *gpl, + float diff_mat[4][4]); + +void BKE_gpencil_update_layer_parent(const struct Depsgraph *depsgraph, struct Object *ob); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index 3a1e729e4de..b48a6284567 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -141,20 +141,10 @@ typedef struct GpencilModifierTypeInfo { /** * Callback for GP "geometry" modifiers that create extra geometry * in the frame (e.g. Array) - * - * The gpf parameter contains the GP frame/strokes to operate on. This is - * usually a copy of the original (unmodified and saved to files) stroke data. - * Modifiers should only add any generated strokes to this frame (and not one accessed - * via the gpl parameter). - * - * The modifier_index parameter indicates where the modifier is - * in the modifier stack in relation to other modifiers. */ void (*generateStrokes)(struct GpencilModifierData *md, struct Depsgraph *depsgraph, - struct Object *ob, - struct bGPDlayer *gpl, - struct bGPDframe *gpf); + struct Object *ob); /** * Bake-down GP modifier's effects into the GP data-block. @@ -297,24 +287,6 @@ bool BKE_gpencil_has_geometry_modifiers(struct Object *ob); bool BKE_gpencil_has_time_modifiers(struct Object *ob); bool BKE_gpencil_has_transform_modifiers(struct Object *ob); -void BKE_gpencil_stroke_modifiers(struct Depsgraph *depsgraph, - struct Object *ob, - struct bGPDlayer *gpl, - struct bGPDframe *gpf, - struct bGPDstroke *gps, - bool is_render); -void BKE_gpencil_geometry_modifiers(struct Depsgraph *depsgraph, - struct Object *ob, - struct bGPDlayer *gpl, - struct bGPDframe *gpf, - bool is_render); -int BKE_gpencil_time_modifier(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct bGPDlayer *gpl, - int cfra, - bool is_render); - void BKE_gpencil_lattice_init(struct Object *ob); void BKE_gpencil_lattice_clear(struct Object *ob); @@ -322,6 +294,15 @@ void BKE_gpencil_modifiers_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); +void BKE_gpencil_prepare_eval_data(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); + +struct bGPDframe *BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + struct bGPDlayer *gpl); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 5283672bdde..46fb254a387 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -34,6 +34,7 @@ struct Brush; struct CurveMapping; struct Depsgraph; struct EnumPropertyItem; +struct GHash; struct GridPaintMask; struct ImagePool; struct MLoop; @@ -55,6 +56,7 @@ struct SubdivCCG; struct SubdivCCG; struct Tex; struct ToolSettings; +struct tPaletteColorHSV; struct UnifiedPaintSettings; struct View3D; struct ViewLayer; @@ -82,9 +84,13 @@ typedef enum ePaintMode { PAINT_MODE_TEXTURE_2D = 4, PAINT_MODE_SCULPT_UV = 5, PAINT_MODE_GPENCIL = 6, + /* Grease Pencil Vertex Paint */ + PAINT_MODE_VERTEX_GPENCIL = 7, + PAINT_MODE_SCULPT_GPENCIL = 8, + PAINT_MODE_WEIGHT_GPENCIL = 9, /** Keep last. */ - PAINT_MODE_INVALID = 7, + PAINT_MODE_INVALID = 10, } ePaintMode; #define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PAINT_MODE_SCULPT_UV) @@ -143,6 +149,15 @@ bool BKE_palette_is_empty(const struct Palette *palette); void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color); void BKE_palette_clear(struct Palette *palette); +void BKE_palette_sort_hsv(struct tPaletteColorHSV *color_array, const int totcol); +void BKE_palette_sort_svh(struct tPaletteColorHSV *color_array, const int totcol); +void BKE_palette_sort_vhs(struct tPaletteColorHSV *color_array, const int totcol); +void BKE_palette_sort_luminance(struct tPaletteColorHSV *color_array, const int totcol); +bool BKE_palette_from_hash(struct Main *bmain, + struct GHash *color_table, + const char *name, + const bool linear); + /* paint curves */ struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 4a92f439d74..1716439c3fd 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -271,12 +271,10 @@ void BKE_brush_init_gpencil_settings(Brush *brush) brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->flag = 0; brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; brush->gpencil_settings->draw_strength = 1.0f; brush->gpencil_settings->draw_jitter = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; - brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; /* curves */ brush->gpencil_settings->curve_sensitivity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); @@ -285,11 +283,32 @@ void BKE_brush_init_gpencil_settings(Brush *brush) } /* add a new gp-brush */ -Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name) +Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eObjectMode mode) { + Paint *paint = NULL; Brush *brush; - Paint *paint = &ts->gp_paint->paint; - brush = BKE_brush_add(bmain, name, OB_MODE_PAINT_GPENCIL); + switch (mode) { + case OB_MODE_PAINT_GPENCIL: { + paint = &ts->gp_paint->paint; + break; + } + case OB_MODE_SCULPT_GPENCIL: { + paint = &ts->gp_sculptpaint->paint; + break; + } + case OB_MODE_WEIGHT_GPENCIL: { + paint = &ts->gp_weightpaint->paint; + break; + } + case OB_MODE_VERTEX_GPENCIL: { + paint = &ts->gp_vertexpaint->paint; + break; + } + default: + paint = &ts->gp_paint->paint; + } + + brush = BKE_brush_add(bmain, name, mode); BKE_paint_brush_set(paint, brush); id_us_min(&brush->id); @@ -303,6 +322,22 @@ Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name) return brush; } +/* Delete a Brush. */ +bool BKE_brush_delete(Main *bmain, Brush *brush) +{ + if (brush->id.tag & LIB_TAG_INDIRECT) { + return false; + } + else if (BKE_library_ID_is_indirectly_used(bmain, brush) && ID_REAL_USERS(brush) <= 1 && + ID_EXTRA_USERS(brush) == 0) { + return false; + } + + BKE_id_delete(bmain, brush); + + return true; +} + /* grease pencil cumapping->preset */ typedef enum eGPCurveMappingPreset { GPCURVE_PRESET_PENCIL = 0, @@ -363,442 +398,760 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) } } -/* create a set of grease pencil presets. */ -void BKE_brush_gpencil_presets(Main *bmain, ToolSettings *ts) +void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) { #define SMOOTH_STROKE_RADIUS 40 #define SMOOTH_STROKE_FACTOR 0.9f +#define ACTIVE_SMOOTH 0.35f - Paint *paint = &ts->gp_paint->paint; + CurveMapping *custom_curve = NULL; - Brush *brush, *deft; - CurveMapping *custom_curve; + /* Set general defaults at brush level. */ + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; - /* Airbrush brush. */ - brush = BLI_findstring(&bmain->brushes, "Airbrush", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Airbrush"); + brush->rgb[0] = 0.498f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 0.498f; + + brush->secondary_rgb[0] = 1.0f; + brush->secondary_rgb[1] = 1.0f; + brush->secondary_rgb[2] = 1.0f; + + brush->curve_preset = BRUSH_CURVE_SMOOTH; + + if (brush->gpencil_settings == NULL) { + return; } - brush->size = 300.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + /* Set preset type. */ + brush->gpencil_settings->preset_type = type; - brush->gpencil_settings->draw_strength = 0.4f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + /* Set vertex mix factor. */ + brush->gpencil_settings->vertex_mode = GPPAINT_MODE_STROKE; + brush->gpencil_settings->vertex_factor = 1.0f; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.98f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->gradient_f = 0.211f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; + switch (type) { + case GP_BRUSH_PRESET_AIRBRUSH: { + brush->size = 300.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->draw_strength = 0.4f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->gpencil_tool = GPAINT_TOOL_DRAW; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_AIRBRUSH; + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->hardeness = 0.211f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_AIRBRUSH; - /* Create and link Black Dots material to brush. - * This material is required because the brush uses the material to define how the stroke is - * drawn. */ - Material *ma = BLI_findstring(&bmain->materials, "Black Dots", offsetof(ID, name) + 2); - if (ma == NULL) { - ma = BKE_gpencil_material_add(bmain, "Black Dots"); - } - brush->gpencil_settings->material = ma; - /* Pin the matterial to the brush. */ - brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED; + /* Create and link Black Dots material to brush. + * This material is required because the brush uses the material to define how the stroke is + * drawn. */ + Material *ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2); + if (ma == NULL) { + ma = BKE_gpencil_material_add(bmain, "Dots Stroke"); + } + brush->gpencil_settings->material = ma; + /* Pin the matterial to the brush. */ + brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED; - /* Ink Pen brush. */ - brush = BLI_findstring(&bmain->brushes, "Ink Pen", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen"); - } - brush->size = 60.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_INK_PEN: { - brush->gpencil_settings->draw_strength = 1.0f; + brush->size = 60.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.7f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; + brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->simplify_f = 0.002f; + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->hardeness = 1.0f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->simplify_f = 0.002f; - /* Curve. */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); - BKE_curvemapping_initialize(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK); + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + /* Curve. */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INK); - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK; + brush->gpencil_tool = GPAINT_TOOL_DRAW; - /* Ink Pen Rough brush. */ - brush = BLI_findstring(&bmain->brushes, "Ink Pen Rough", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Ink Pen Rough"); - } + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_INK_PEN_ROUGH: { + brush->size = 60.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->hardeness = 1.0f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); + + brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 2; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->simplify_f = 0.000f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 1.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + /* Curve. */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE); + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_MARKER_BOLD: { + brush->size = 150.0f; + brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 0.3f; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->hardeness = 1.0f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + /* Curve. */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER); + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_MARKER_CHISEL: { + brush->size = 80.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = DEG2RAD(20.0f); + brush->gpencil_settings->draw_angle_factor = 1.0f; + brush->gpencil_settings->hardeness = 1.0f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_PEN: { + brush->size = 30.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->hardeness = 1.0f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_PENCIL_SOFT: { + brush->size = 80.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 0.4f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->hardeness = 0.8f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->simplify_f = 0.000f; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_PENCIL: { + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 0.6f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->input_samples = 10; + brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + brush->gpencil_settings->hardeness = 1.0f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->simplify_f = 0.002f; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; + brush->gpencil_tool = GPAINT_TOOL_DRAW; + + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_FILL_AREA: { + brush->size = 20.0f; + + brush->gpencil_settings->fill_leak = 3; + brush->gpencil_settings->fill_threshold = 0.1f; + brush->gpencil_settings->fill_simplylvl = 1; + brush->gpencil_settings->fill_factor = 1; + + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->hardeness = 1.0f; + copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); + brush->gpencil_settings->draw_smoothfac = 0.1f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 1; + + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; + brush->gpencil_tool = GPAINT_TOOL_FILL; + brush->gpencil_settings->vertex_mode = GPPAINT_MODE_FILL; + + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_ERASER_SOFT: { + brush->size = 30.0f; + brush->gpencil_settings->draw_strength = 0.5f; + brush->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; + brush->gpencil_tool = GPAINT_TOOL_ERASE; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; + brush->gpencil_settings->era_strength_f = 100.0f; + brush->gpencil_settings->era_thickness_f = 10.0f; - brush->size = 60.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + break; + } + case GP_BRUSH_PRESET_ERASER_HARD: { + brush->size = 30.0f; + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; + brush->gpencil_settings->era_strength_f = 100.0f; + brush->gpencil_settings->era_thickness_f = 50.0f; - brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; + brush->gpencil_tool = GPAINT_TOOL_ERASE; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.5f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - - brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 2; - brush->gpencil_settings->thick_smoothfac = 0.0f; - brush->gpencil_settings->thick_smoothlvl = 2; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->simplify_f = 0.000f; - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 1.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + break; + } + case GP_BRUSH_PRESET_ERASER_POINT: { + brush->size = 30.0f; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; - /* Curve. */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); - BKE_curvemapping_initialize(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_INKNOISE); + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; + brush->gpencil_tool = GPAINT_TOOL_ERASE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + break; + } + case GP_BRUSH_PRESET_ERASER_STROKE: { + brush->size = 30.0f; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; + brush->gpencil_tool = GPAINT_TOOL_ERASE; - /* Marker Bold brush. */ - brush = BLI_findstring(&bmain->brushes, "Marker Bold", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Marker Bold"); - } - brush->size = 150.0f; - brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; + break; + } + case GP_BRUSH_PRESET_TINT: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_TINT; + brush->gpencil_tool = GPAINT_TOOL_TINT; - brush->gpencil_settings->draw_strength = 0.3f; + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.6f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; + brush->gpencil_settings->draw_strength = 0.8f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_VERTEX_DRAW: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_DRAW; + brush->gpencil_vertex_tool = GPVERTEX_TOOL_DRAW; - /* Curve. */ - custom_curve = brush->gpencil_settings->curve_sensitivity; - BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); - BKE_curvemapping_initialize(custom_curve); - brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_MARKER); + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->gpencil_settings->draw_strength = 0.8f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_VERTEX_BLUR: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR; + brush->gpencil_vertex_tool = GPVERTEX_TOOL_BLUR; - /* Marker Chisel brush. */ - brush = BLI_findstring(&bmain->brushes, "Marker Chisel", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Marker Chisel"); - } - brush->size = 80.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->draw_strength = 0.8f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.5f; - brush->gpencil_settings->draw_angle = DEG2RAD(20.0f); - brush->gpencil_settings->draw_angle_factor = 1.0f; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_VERTEX_AVERAGE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_AVERAGE; + brush->gpencil_vertex_tool = GPVERTEX_TOOL_AVERAGE; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->draw_random_sub = 0; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->flag &= ~GP_BRUSH_GROUP_RANDOM; - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->gpencil_settings->draw_strength = 0.8f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_VERTEX_SMEAR: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_SMEAR; + brush->gpencil_vertex_tool = GPVERTEX_TOOL_SMEAR; - /* Pen brush. */ - brush = BLI_findstring(&bmain->brushes, "Pen", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Pen"); - } - brush->size = 30.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.3f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 1; - brush->gpencil_settings->draw_subdivide = 1; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->simplify_f = 0.002f; - - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->draw_strength = 0.8f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_VERTEX_REPLACE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_REPLACE; + brush->gpencil_vertex_tool = GPVERTEX_TOOL_REPLACE; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - /* Pencil Soft brush. */ - brush = BLI_findstring(&bmain->brushes, "Pencil Soft", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Pencil Soft"); - } + brush->gpencil_settings->draw_strength = 0.8f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->size = 80.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + zero_v3(brush->secondary_rgb); + break; + } + case GP_BRUSH_PRESET_SMOOTH_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_SMOOTH; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_SMOOTH; - brush->gpencil_settings->draw_strength = 0.4f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.64f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->gradient_f = 0.8f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_flag = GP_SCULPT_FLAG_SMOOTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->simplify_f = 0.000f; - - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_random_strength = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + break; + } + case GP_BRUSH_PRESET_STRENGTH_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_STRENGTH; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_STRENGTH; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_flag = GP_SCULPT_FLAG_SMOOTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - /* Pencil brush. */ - brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Pencil"); - } - deft = brush; /* save default brush. */ + break; + } + case GP_BRUSH_PRESET_THICKNESS_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_THICKNESS; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_THICKNESS; - brush->size = 25.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_strength = 0.6f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->draw_strength = 0.5f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - brush->gpencil_settings->input_samples = 10; - brush->gpencil_settings->active_smooth = 0.55f; - brush->gpencil_settings->draw_angle = 0.0f; - brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; + break; + } + case GP_BRUSH_PRESET_GRAB_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_GRAB; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_GRAB; + brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.0f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 0; - brush->gpencil_settings->draw_random_sub = 0.0f; - brush->gpencil_settings->simplify_f = 0.002f; + brush->size = 25.0f; - brush->gpencil_settings->draw_random_press = 0.0f; - brush->gpencil_settings->draw_jitter = 0.0f; - brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; - brush->gpencil_tool = GPAINT_TOOL_DRAW; + break; + } + case GP_BRUSH_PRESET_PUSH_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_PUSH; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_PUSH; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - /* Fill brush. */ - brush = BLI_findstring(&bmain->brushes, "Fill Area", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); - } - brush->size = 20.0f; - brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - brush->gpencil_settings->fill_leak = 3; - brush->gpencil_settings->fill_threshold = 0.1f; - brush->gpencil_settings->fill_simplylvl = 1; - brush->gpencil_settings->fill_factor = 1; + break; + } + case GP_BRUSH_PRESET_TWIST_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_TWIST; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_TWIST; - brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->gradient_f = 1.0f; - brush->gpencil_settings->gradient_s[0] = 1.0f; - brush->gpencil_settings->gradient_s[1] = 1.0f; - brush->gpencil_settings->draw_smoothfac = 0.1f; - brush->gpencil_settings->draw_smoothlvl = 1; - brush->gpencil_settings->thick_smoothfac = 1.0f; - brush->gpencil_settings->thick_smoothlvl = 3; - brush->gpencil_settings->draw_subdivide = 1; + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->draw_strength = 0.3f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; - brush->gpencil_tool = GPAINT_TOOL_FILL; + break; + } + case GP_BRUSH_PRESET_PINCH_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_PINCH; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_PINCH; - brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; - brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + brush->size = 50.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - /* Soft Eraser brush. */ - brush = BLI_findstring(&bmain->brushes, "Eraser Soft", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft"); + brush->gpencil_settings->draw_strength = 0.5f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_RANDOMIZE_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_RANDOMIZE; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_RANDOMIZE; + + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 0.5f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_CLONE_STROKE: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_CLONE; + brush->gpencil_sculpt_tool = GPSCULPT_TOOL_CLONE; + brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; + + brush->size = 25.0f; + + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + case GP_BRUSH_PRESET_DRAW_WEIGHT: { + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_WEIGHT; + brush->gpencil_weight_tool = GPWEIGHT_TOOL_DRAW; + + brush->size = 25.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + + brush->gpencil_settings->draw_strength = 0.8f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION; + + break; + } + default: + break; } - brush->size = 30.0f; - brush->gpencil_settings->draw_strength = 0.5f; - brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); - brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; - brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; - brush->gpencil_tool = GPAINT_TOOL_ERASE; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; - brush->gpencil_settings->era_strength_f = 100.0f; - brush->gpencil_settings->era_thickness_f = 10.0f; +} - /* Hard Eraser brush. */ - brush = BLI_findstring(&bmain->brushes, "Eraser Hard", offsetof(ID, name) + 2); +static Brush *gpencil_brush_ensure(Main *bmain, + ToolSettings *ts, + const char *brush_name, + eObjectMode mode) +{ + Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard"); + brush = BKE_brush_add_gpencil(bmain, ts, brush_name, mode); } - brush->size = 30.0f; - brush->gpencil_settings->draw_strength = 1.0f; - brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; - brush->gpencil_settings->era_strength_f = 100.0f; - brush->gpencil_settings->era_thickness_f = 50.0f; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; - brush->gpencil_tool = GPAINT_TOOL_ERASE; - - /* Point Eraser brush. */ - brush = BLI_findstring(&bmain->brushes, "Eraser Point", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Point"); + if (brush->gpencil_settings == NULL) { + BKE_brush_init_gpencil_settings(brush); } - brush->size = 30.0f; - brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; - brush->gpencil_tool = GPAINT_TOOL_ERASE; + return brush; +} + +/* Create a set of grease pencil Drawing presets. */ +void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts) +{ + + Paint *paint = &ts->gp_paint->paint; + + Brush *brush, *deft_draw; + /* Airbrush brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Airbrush", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_AIRBRUSH); + + /* Ink Pen brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Ink Pen", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN); + + /* Ink Pen Rough brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Ink Pen Rough", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN_ROUGH); + + /* Marker Bold brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Marker Bold", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_BOLD); + + /* Marker Chisel brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Marker Chisel", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_CHISEL); + + /* Pen brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Pen", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PEN); + + /* Pencil Soft brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Pencil Soft", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL_SOFT); + + /* Pencil brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Pencil", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL); + deft_draw = brush; /* save default brush. */ + + /* Fill brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Fill Area", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_FILL_AREA); + + /* Soft Eraser brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Eraser Soft", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_SOFT); + + /* Hard Eraser brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Eraser Hard", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_HARD); + + /* Point Eraser brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Eraser Point", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_POINT); /* Stroke Eraser brush. */ - brush = BLI_findstring(&bmain->brushes, "Eraser Stroke", offsetof(ID, name) + 2); - if (brush == NULL) { - brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke"); - } - brush->size = 30.0f; - brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; - brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; + brush = gpencil_brush_ensure(bmain, ts, "Eraser Stroke", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_STROKE); + + /* Tint brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Tint", OB_MODE_PAINT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TINT); + + /* Set default Draw brush. */ + BKE_paint_brush_set(paint, deft_draw); +} + +/* Create a set of grease pencil Vertex Paint presets. */ +void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts) +{ + Paint *vertexpaint = &ts->gp_vertexpaint->paint; + + Brush *brush, *deft_vertex; + /* Vertex Draw brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Vertex Draw", OB_MODE_VERTEX_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_DRAW); + deft_vertex = brush; /* save default brush. */ + + /* Vertex Blur brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Vertex Blur", OB_MODE_VERTEX_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_BLUR); + + /* Vertex Average brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Vertex Average", OB_MODE_VERTEX_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_AVERAGE); + + /* Vertex Smear brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Vertex Smear", OB_MODE_VERTEX_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_SMEAR); + + /* Vertex Replace brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Vertex Replace", OB_MODE_VERTEX_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_REPLACE); + + /* Set default Vertex brush. */ + BKE_paint_brush_set(vertexpaint, deft_vertex); +} + +/* Create a set of grease pencil Sculpt Paint presets. */ +void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts) +{ + Paint *sculptpaint = &ts->gp_sculptpaint->paint; + Brush *brush, *deft_sculpt; + + /* Smooth brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Smooth Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_SMOOTH_STROKE); + deft_sculpt = brush; + + /* Strength brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Strength Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_STRENGTH_STROKE); + + /* Thickness brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Thickness Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_THICKNESS_STROKE); + + /* Grab brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Grab Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_GRAB_STROKE); + + /* Push brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Push Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PUSH_STROKE); + + /* Twist brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Twist Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TWIST_STROKE); + + /* Pinch brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Pinch Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PINCH_STROKE); + + /* Randomize brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Randomize Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_RANDOMIZE_STROKE); + + /* Clone brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Clone Stroke", OB_MODE_SCULPT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_CLONE_STROKE); + + /* Set default brush. */ + BKE_paint_brush_set(sculptpaint, deft_sculpt); +} + +/* Create a set of grease pencil Weight Paint presets. */ +void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts) +{ + Paint *weightpaint = &ts->gp_weightpaint->paint; - brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; - brush->gpencil_tool = GPAINT_TOOL_ERASE; + Brush *brush, *deft_weight; + /* Vertex Draw brush. */ + brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL); + BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT); + deft_weight = brush; /* save default brush. */ - /* set default brush. */ - BKE_paint_brush_set(paint, deft); + /* Set default brush. */ + BKE_paint_brush_set(weightpaint, deft_weight); } struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode) diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 48985932d87..b2c551a1752 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -1124,6 +1124,9 @@ enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit, else if (object_mode & OB_MODE_WEIGHT_GPENCIL) { return CTX_MODE_WEIGHT_GPENCIL; } + else if (object_mode & OB_MODE_VERTEX_GPENCIL) { + return CTX_MODE_VERTEX_GPENCIL; + } } } @@ -1140,25 +1143,11 @@ enum eContextObjectMode CTX_data_mode_enum(const bContext *C) /* would prefer if we can use the enum version below over this one - Campbell */ /* must be aligned with above enum */ static const char *data_mode_strings[] = { - "mesh_edit", - "curve_edit", - "surface_edit", - "text_edit", - "armature_edit", - "mball_edit", - "lattice_edit", - "posemode", - "sculpt_mode", - "weightpaint", - "vertexpaint", - "imagepaint", - "particlemode", - "objectmode", - "greasepencil_paint", - "greasepencil_edit", - "greasepencil_sculpt", - "greasepencil_weight", - NULL, + "mesh_edit", "curve_edit", "surface_edit", "text_edit", + "armature_edit", "mball_edit", "lattice_edit", "posemode", + "sculpt_mode", "weightpaint", "vertexpaint", "imagepaint", + "particlemode", "objectmode", "greasepencil_paint", "greasepencil_edit", + "greasepencil_sculpt", "greasepencil_weight", "greasepencil_vertex", NULL, }; BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode") diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 747ffb92ad5..0b33eaccb6f 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -39,12 +39,16 @@ #include "BLT_translation.h" +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + #include "DNA_anim_types.h" #include "DNA_meshdata_types.h" #include "DNA_material_types.h" #include "DNA_gpencil_types.h" #include "DNA_userdef_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "DNA_object_types.h" #include "BKE_action.h" @@ -55,14 +59,17 @@ #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_icons.h" +#include "BKE_image.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BLI_math_color.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" static CLG_LogRef LOG = {"bke.gpencil"}; @@ -139,12 +146,10 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps) /* Free strokes belonging to a gp-frame */ bool BKE_gpencil_free_strokes(bGPDframe *gpf) { - bGPDstroke *gps_next; bool changed = (BLI_listbase_is_empty(&gpf->strokes) == false); /* free strokes */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) { - gps_next = gps->next; + LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { BKE_gpencil_free_stroke(gps); } BLI_listbase_clear(&gpf->strokes); @@ -152,24 +157,6 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf) return changed; } -/* Free strokes and colors belonging to a gp-frame */ -bool BKE_gpencil_free_frame_runtime_data(bGPDframe *gpf_eval) -{ - bGPDstroke *gps_next; - if (!gpf_eval) { - return false; - } - - /* free strokes */ - for (bGPDstroke *gps = gpf_eval->strokes.first; gps; gps = gps_next) { - gps_next = gps->next; - BKE_gpencil_free_stroke(gps); - } - BLI_listbase_clear(&gpf_eval->strokes); - - return true; -} - /* Free all of a gp-layer's frames */ void BKE_gpencil_free_frames(bGPDlayer *gpl) { @@ -191,6 +178,15 @@ void BKE_gpencil_free_frames(bGPDlayer *gpl) gpl->actframe = NULL; } +void BKE_gpencil_free_layer_masks(bGPDlayer *gpl) +{ + /* Free masks.*/ + bGPDlayer_Mask *mask_next = NULL; + for (bGPDlayer_Mask *mask = gpl->mask_layers.first; mask; mask = mask_next) { + mask_next = mask->next; + BLI_freelinkN(&gpl->mask_layers, mask); + } +} /* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ void BKE_gpencil_free_layers(ListBase *list) { @@ -207,6 +203,10 @@ void BKE_gpencil_free_layers(ListBase *list) /* free layers and their data */ BKE_gpencil_free_frames(gpl); + + /* Free masks.*/ + BKE_gpencil_free_layer_masks(gpl); + BLI_freelinkN(list, gpl); } } @@ -230,6 +230,13 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all) } } +void BKE_gpencil_eval_delete(bGPdata *gpd_eval) +{ + BKE_gpencil_free(gpd_eval, true); + BKE_libblock_free_data(&gpd_eval->id, false); + MEM_freeN(gpd_eval); +} + /* ************************************************** */ /* Container Creation */ @@ -307,7 +314,7 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) new_frame = BKE_gpencil_frame_duplicate(gpl->actframe); /* Find frame to insert it before */ - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (gpf->framenum > cframe) { /* Add it here */ BLI_insertlinkbefore(&gpl->frames, gpf, new_frame); @@ -356,7 +363,7 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti /* allocate memory for frame and add to end of list */ gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer"); - gpl_active = BKE_gpencil_layer_getactive(gpd); + gpl_active = BKE_gpencil_layer_active_get(gpd); /* add to datablock */ if (gpl_active == NULL) { @@ -386,6 +393,8 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti gpl->opacity = 1.0f; /* default channel color */ ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f); + /* Default vertex mix. */ + gpl->vertex_paint_opacity = 1.0f; } /* auto-name */ @@ -397,9 +406,11 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti offsetof(bGPDlayer, info), sizeof(gpl->info)); + /* Enable always affected by scene lights. */ + gpl->flag |= GP_LAYER_USE_LIGHTS; /* make this one the active one */ if (setactive) { - BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_active_set(gpd, gpl); } /* return layer */ @@ -419,7 +430,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) /* general flags */ gpd->flag |= GP_DATA_VIEWALIGN; - gpd->flag |= GP_DATA_STROKE_FORCE_RECALC; /* always enable object onion skin switch */ gpd->flag |= GP_DATA_SHOW_ONIONSKINS; /* GP object specific settings */ @@ -427,6 +437,8 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; + gpd->zdepth_offset = 0.150f; + /* grid settings */ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); /* Color */ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); /* Scale */ @@ -474,43 +486,59 @@ void BKE_gpencil_stroke_add_points(bGPDstroke *gps, } } -/* Create a new stroke, with pre-allocated data buffers */ -bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness) +/* Create a new stroke, with pre-allocated data buffers. */ +bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness) { /* allocate memory for a new stroke */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); gps->thickness = thickness; - gps->gradient_f = 1.0f; - gps->gradient_s[0] = 1.0f; - gps->gradient_s[1] = 1.0f; + gps->fill_opacity_fac = 1.0f; + gps->hardeness = 1.0f; + copy_v2_fl(gps->aspect_ratio, 1.0f); + + gps->uv_scale = 1.0f; gps->inittime = 0; - /* enable recalculation flag by default */ - gps->flag = GP_STROKE_RECALC_GEOMETRY | GP_STROKE_3DSPACE; + gps->flag = GP_STROKE_3DSPACE; gps->totpoints = totpoints; gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); /* initialize triangle memory to dummy data */ gps->triangles = NULL; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; gps->tot_triangles = 0; gps->mat_nr = mat_idx; - /* add to frame */ - BLI_addtail(&gpf->strokes, gps); + return gps; +} + +/* Create a new stroke and add to frame. */ +bGPDstroke *BKE_gpencil_stroke_add( + bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head) +{ + bGPDstroke *gps = BKE_gpencil_stroke_new(mat_idx, totpoints, thickness); + + /* Add to frame. */ + if ((gps != NULL) && (gpf != NULL)) { + if (!insert_at_head) { + BLI_addtail(&gpf->strokes, gps); + } + else { + BLI_addhead(&gpf->strokes, gps); + } + } return gps; } /* Add a stroke and copy the temporary drawing color value from one of the existing stroke */ -bGPDstroke *BKE_gpencil_add_stroke_existing_style( +bGPDstroke *BKE_gpencil_stroke_add_existing_style( bGPDframe *gpf, bGPDstroke *existing, int mat_idx, int totpoints, short thickness) { - bGPDstroke *gps = BKE_gpencil_add_stroke(gpf, mat_idx, totpoints, thickness); + bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, mat_idx, totpoints, thickness, false); /* Copy run-time color data so that strokes added in the modifier has the style. * There are depsgraph reference pointers inside, * change the copy function if interfere with future drawing implementation. */ @@ -533,30 +561,26 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d } /* make a copy of a given gpencil stroke */ -bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src) +bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src, const bool dup_points) { bGPDstroke *gps_dst = NULL; gps_dst = MEM_dupallocN(gps_src); gps_dst->prev = gps_dst->next = NULL; + gps_dst->triangles = MEM_dupallocN(gps_src->triangles); - gps_dst->points = MEM_dupallocN(gps_src->points); + if (dup_points) { + gps_dst->points = MEM_dupallocN(gps_src->points); - if (gps_src->dvert != NULL) { - gps_dst->dvert = MEM_dupallocN(gps_src->dvert); - BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); - } - else { - gps_dst->dvert = NULL; + if (gps_src->dvert != NULL) { + gps_dst->dvert = MEM_dupallocN(gps_src->dvert); + BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); + } + else { + gps_dst->dvert = NULL; + } } - /* Don't clear triangles, so that modifier evaluation can just use - * this without extra work first. Most places that need to force - * this data to get recalculated will destroy the data anyway though. - */ - gps_dst->triangles = MEM_dupallocN(gps_dst->triangles); - /* gps_dst->flag |= GP_STROKE_RECALC_GEOMETRY; */ - /* return new stroke */ return gps_dst; } @@ -580,7 +604,7 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) BLI_listbase_clear(&gpf_dst->strokes); for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { /* make copy of source stroke */ - gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true); BLI_addtail(&gpf_dst->strokes, gps_dst); } @@ -601,7 +625,7 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds BLI_listbase_clear(&gpf_dst->strokes); for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { /* make copy of source stroke */ - gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true); BLI_addtail(&gpf_dst->strokes, gps_dst); } } @@ -622,6 +646,14 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) gpl_dst = MEM_dupallocN(gpl_src); gpl_dst->prev = gpl_dst->next = NULL; + /* Copy masks. */ + BLI_listbase_clear(&gpl_dst->mask_layers); + LISTBASE_FOREACH (bGPDlayer_Mask *, mask_src, &gpl_src->mask_layers) { + bGPDlayer_Mask *mask_dst = MEM_dupallocN(mask_src); + mask_dst->prev = mask_dst->next = NULL; + BLI_addtail(&gpl_dst->mask_layers, mask_dst); + } + /* copy frames */ BLI_listbase_clear(&gpl_dst->frames); for (gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) { @@ -658,7 +690,7 @@ void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int U /* copy layers */ BLI_listbase_clear(&gpd_dst->layers); - for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) { /* make a copy of source layer and its data */ /* TODO here too could add unused flags... */ @@ -766,8 +798,8 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) /* if frame has no strokes after this, delete it */ if (BLI_listbase_is_empty(&gpf->strokes)) { - BKE_gpencil_layer_delframe(gpl, gpf); - BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV); + BKE_gpencil_layer_frame_delete(gpl, gpf); + BKE_gpencil_layer_frame_get(gpl, cfra, GP_GETFRAME_USE_PREV); } } @@ -775,7 +807,7 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) /* GP Layer API */ /* Check if the given layer is able to be edited or not */ -bool gpencil_layer_is_editable(const bGPDlayer *gpl) +bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl) { /* Sanity check */ if (gpl == NULL) { @@ -797,7 +829,7 @@ bool gpencil_layer_is_editable(const bGPDlayer *gpl) } /* Look up the gp-frame on the requested frame number, but don't add a new one */ -bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe) +bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe) { bGPDframe *gpf; @@ -817,7 +849,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe) * - this sets the layer's actframe var (if allowed to) * - extension beyond range (if first gp-frame is after all frame in interest and cannot add) */ -bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew) +bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew) { bGPDframe *gpf = NULL; bool found = false; @@ -966,7 +998,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M } /* delete the given frame from a layer */ -bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) +bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf) { bool changed = false; @@ -989,18 +1021,103 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) return changed; } -/* get the active gp-layer for editing */ -bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd) +bGPDlayer *BKE_gpencil_layer_named_get(bGPdata *gpd, const char *name) +{ + if (name[0] == '\0') { + return NULL; + } + return BLI_findstring(&gpd->layers, name, offsetof(bGPDlayer, info)); +} + +bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(bGPDlayer *gpl, const char *name) +{ + if (name[0] == '\0') { + return NULL; + } + return BLI_findstring(&gpl->mask_layers, name, offsetof(bGPDlayer_Mask, name)); +} + +bGPDlayer_Mask *BKE_gpencil_layer_mask_add(bGPDlayer *gpl, const char *name) +{ + + bGPDlayer_Mask *mask = MEM_callocN(sizeof(bGPDlayer_Mask), "bGPDlayer_Mask"); + BLI_addtail(&gpl->mask_layers, mask); + BLI_strncpy(mask->name, name, sizeof(mask->name)); + gpl->act_mask++; + + return mask; +} + +void BKE_gpencil_layer_mask_remove(bGPDlayer *gpl, bGPDlayer_Mask *mask) +{ + BLI_freelinkN(&gpl->mask_layers, mask); + gpl->act_mask--; + CLAMP_MIN(gpl->act_mask, 0); +} + +void BKE_gpencil_layer_mask_remove_ref(bGPdata *gpd, const char *name) +{ + bGPDlayer_Mask *mask_next; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + for (bGPDlayer_Mask *mask = gpl->mask_layers.first; mask; mask = mask_next) { + mask_next = mask->next; + if (STREQ(mask->name, name)) { + BKE_gpencil_layer_mask_remove(gpl, mask); + } + } + } +} + +static int gpencil_cb_sort_masks(const void *arg1, const void *arg2) +{ + /* sort is inverted as layer list. */ + const struct bGPDlayer_Mask *mask1 = arg1; + const struct bGPDlayer_Mask *mask2 = arg2; + int val = 0; + + if (mask1->sort_index < mask2->sort_index) { + val = 1; + } + else if (mask1->sort_index > mask2->sort_index) { + val = -1; + } + + return val; +} + +void BKE_gpencil_layer_mask_sort(bGPdata *gpd, bGPDlayer *gpl) +{ + /* Update sort index. */ + LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) { + bGPDlayer *gpl_mask = BKE_gpencil_layer_named_get(gpd, mask->name); + if (gpl_mask != NULL) { + mask->sort_index = BLI_findindex(&gpd->layers, gpl_mask); + } + else { + mask->sort_index = 0; + } + } + BLI_listbase_sort(&gpl->mask_layers, gpencil_cb_sort_masks); +} + +void BKE_gpencil_layer_mask_sort_all(bGPdata *gpd) { - bGPDlayer *gpl; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + BKE_gpencil_layer_mask_sort(gpd, gpl); + } +} +/* get the active gp-layer for editing */ +bGPDlayer *BKE_gpencil_layer_active_get(bGPdata *gpd) +{ /* error checking */ if (ELEM(NULL, gpd, gpd->layers.first)) { return NULL; } /* loop over layers until found (assume only one active) */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->flag & GP_LAYER_ACTIVE) { return gpl; } @@ -1011,17 +1128,15 @@ bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd) } /* set the active gp-layer */ -void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) +void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active) { - bGPDlayer *gpl; - /* error checking */ if (ELEM(NULL, gpd, gpd->layers.first, active)) { return; } /* loop over layers deactivating all */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpl->flag &= ~GP_LAYER_ACTIVE; if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) { gpl->flag |= GP_LAYER_LOCKED; @@ -1040,13 +1155,11 @@ void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock) { BLI_assert(gpd != NULL); - bGPDlayer *gpl; - if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) { - bGPDlayer *layer_active = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *layer_active = BKE_gpencil_layer_active_get(gpd); /* Lock all other layers */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* unlock active layer */ if (gpl == layer_active) { gpl->flag &= ~GP_LAYER_LOCKED; @@ -1061,7 +1174,7 @@ void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock) * a problem in the UI because the user expects all layers will be unlocked */ if (unlock) { - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpl->flag &= ~GP_LAYER_LOCKED; } } @@ -1079,6 +1192,12 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl) /* free layer */ BKE_gpencil_free_frames(gpl); + /* Free Masks. */ + BKE_gpencil_free_layer_masks(gpl); + + /* Remove any reference to that layer in masking lists. */ + BKE_gpencil_layer_mask_remove_ref(gpd, gpl->info); + /* free icon providing preview of icon color */ BKE_icon_delete(gpl->runtime.icon_id); @@ -1119,7 +1238,7 @@ Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob, Material *ma = BKE_gpencil_brush_material_get(brush); /* check if the material is already on object material slots and add it if missing */ - if (ma && BKE_gpencil_object_material_get_index(ob, ma) < 0) { + if (ma && BKE_gpencil_object_material_index_get(ob, ma) < 0) { BKE_object_material_slot_add(bmain, ob); BKE_object_material_assign(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF); } @@ -1138,7 +1257,7 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi if (!material) { return -1; } - int index = BKE_gpencil_object_material_get_index(ob, material); + int index = BKE_gpencil_object_material_index_get(ob, material); if (index < 0) { BKE_object_material_slot_add(bmain, ob); BKE_object_material_assign(bmain, ob, material, ob->totcol, BKE_MAT_ASSIGN_USERPREF); @@ -1167,7 +1286,7 @@ Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *n } /* Returns the material for a brush with respect to its pinned state. */ -Material *BKE_gpencil_object_material_get_from_brush(Object *ob, Brush *brush) +Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush) { if ((brush) && (brush->gpencil_settings) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) { @@ -1183,7 +1302,7 @@ Material *BKE_gpencil_object_material_get_from_brush(Object *ob, Brush *brush) int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush) { if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) { - return BKE_gpencil_object_material_get_index(ob, brush->gpencil_settings->material); + return BKE_gpencil_object_material_index_get(ob, brush->gpencil_settings->material); } else { return ob->actcol - 1; @@ -1294,11 +1413,11 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3]) return changed; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { bGPDframe *gpf = gpl->actframe; if (gpf != NULL) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); } } @@ -1330,6 +1449,13 @@ void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3]) mul_v3_v3fl(r_centroid, tot, 0.5f); } +/* Compute stroke bounding box. */ +void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps) +{ + INIT_MINMAX(gps->boundbox_min, gps->boundbox_max); + BKE_gpencil_stroke_minmax(gps, false, gps->boundbox_min, gps->boundbox_max); +} + /* create bounding box values */ static void boundbox_gpencil(Object *ob) { @@ -1381,7 +1507,7 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) } const float scalef = mat4_to_scale(mat); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* FIXME: For now, we just skip parented layers. * Otherwise, we have to update each frame to find * the current parent position/effects. @@ -1390,8 +1516,8 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) continue; } - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { bGPDspoint *pt; int i; @@ -1400,9 +1526,8 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) pt->pressure *= scalef; } - /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + /* Distortion may mean we need to re-triangulate. */ + BKE_gpencil_stroke_geometry_update(gps); } } } @@ -1421,9 +1546,9 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) /* Remove points data */ if (gpd) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->dvert != NULL) { for (int i = 0; i < gps->totpoints; i++) { dvert = &gps->dvert[i]; @@ -1537,6 +1662,7 @@ static int stroke_march_next_point(const bGPDstroke *gps, float *result, float *pressure, float *strength, + float *vert_color, float *ratio_result, int *index_from, int *index_to) @@ -1576,6 +1702,7 @@ static int stroke_march_next_point(const bGPDstroke *gps, copy_v3_v3(result, &pt->x); *pressure = gps->points[next_point_index].pressure; *strength = gps->points[next_point_index].strength; + memcpy(vert_color, gps->points[next_point_index].vert_color, sizeof(float) * 4); *index_from = next_point_index - 1; *index_to = next_point_index; @@ -1590,6 +1717,10 @@ static int stroke_march_next_point(const bGPDstroke *gps, gps->points[next_point_index].pressure, gps->points[next_point_index - 1].pressure, ratio); *strength = interpf( gps->points[next_point_index].strength, gps->points[next_point_index - 1].strength, ratio); + interp_v4_v4v4(vert_color, + gps->points[next_point_index - 1].vert_color, + gps->points[next_point_index].vert_color, + ratio); *index_from = next_point_index - 1; *index_to = next_point_index; @@ -1673,7 +1804,7 @@ static int stroke_march_count(const bGPDstroke *gps, const float dist) * \param gps: Stroke to sample * \param dist: Distance of one segment */ -bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool select) +bool BKE_gpencil_stroke_sample(bGPDstroke *gps, const float dist, const bool select) { bGPDspoint *pt = gps->points; bGPDspoint *pt1 = NULL; @@ -1701,6 +1832,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel int next_point_index = 1; i = 0; float pressure, strength, ratio_result; + float vert_color[4]; int index_from, index_to; float last_coord[3]; @@ -1711,6 +1843,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel copy_v3_v3(&pt2->x, last_coord); new_pt[i].pressure = pt[0].pressure; new_pt[i].strength = pt[0].strength; + memcpy(new_pt[i].vert_color, pt[0].vert_color, sizeof(float) * 4); if (select) { new_pt[i].flag |= GP_SPOINT_SELECT; } @@ -1728,6 +1861,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel last_coord, &pressure, &strength, + vert_color, &ratio_result, &index_from, &index_to)) > -1) { @@ -1735,6 +1869,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel copy_v3_v3(&pt2->x, last_coord); new_pt[i].pressure = pressure; new_pt[i].strength = strength; + memcpy(new_pt[i].vert_color, vert_color, sizeof(float) * 4); if (select) { new_pt[i].flag |= GP_SPOINT_SELECT; } @@ -1766,8 +1901,8 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel gps->totpoints = i; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); return true; } @@ -1778,7 +1913,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel * \param dist: Distance of one segment * \param tip_length: Ignore tip jittering, set zero to use default value. */ -bool BKE_gpencil_stretch_stroke(bGPDstroke *gps, const float dist, const float tip_length) +bool BKE_gpencil_stroke_stretch(bGPDstroke *gps, const float dist, const float tip_length) { bGPDspoint *pt = gps->points, *last_pt, *second_last, *next_pt; int i; @@ -1829,7 +1964,7 @@ bool BKE_gpencil_stretch_stroke(bGPDstroke *gps, const float dist, const float t * \param index_from: the index of the first point to be used in the trimmed result * \param index_to: the index of the last point to be used in the trimmed result */ -bool BKE_gpencil_trim_stroke_points(bGPDstroke *gps, const int index_from, const int index_to) +bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to) { bGPDspoint *pt = gps->points, *new_pt; MDeformVert *dv, *new_dv; @@ -1879,7 +2014,7 @@ bool BKE_gpencil_trim_stroke_points(bGPDstroke *gps, const int index_from, const return true; } -bool BKE_gpencil_split_stroke(bGPDframe *gpf, +bool BKE_gpencil_stroke_split(bGPDframe *gpf, bGPDstroke *gps, const int before_index, bGPDstroke **remaining_gps) @@ -1897,7 +2032,7 @@ bool BKE_gpencil_split_stroke(bGPDframe *gpf, /* Handle remaining segments first. */ - new_gps = BKE_gpencil_add_stroke_existing_style( + new_gps = BKE_gpencil_stroke_add_existing_style( gpf, gps, gps->mat_nr, new_count, gps->thickness); new_pt = new_gps->points; /* Allocated from above. */ @@ -1907,13 +2042,14 @@ bool BKE_gpencil_split_stroke(bGPDframe *gpf, } if (gps->dvert) { - new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, "gp_stroke_dverts_remaining"); + new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, + "gp_stroke_dverts_remaining(MDeformVert)"); for (int i = 0; i < new_count; i++) { dv = &gps->dvert[i + before_index]; new_dv[i].flag = dv->flag; new_dv[i].totweight = dv->totweight; new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight, - "gp_stroke_dverts_dw_remaining"); + "gp_stroke_dverts_dw_remaining(MDeformWeight)"); for (int j = 0; j < dv->totweight; j++) { new_dv[i].dw[j].weight = dv->dw[j].weight; new_dv[i].dw[j].def_nr = dv->dw[j].def_nr; @@ -1927,8 +2063,8 @@ bool BKE_gpencil_split_stroke(bGPDframe *gpf, /* Trim the original stroke into a shorter one. * Keep the end point. */ - BKE_gpencil_trim_stroke_points(gps, 0, old_count); - + BKE_gpencil_stroke_trim_points(gps, 0, old_count); + BKE_gpencil_stroke_geometry_update(gps); return true; } @@ -1937,7 +2073,7 @@ bool BKE_gpencil_split_stroke(bGPDframe *gpf, * \param gps: Stroke to shrink * \param dist: delta length */ -bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist) +bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist) { bGPDspoint *pt = gps->points, *second_last; int i; @@ -1981,7 +2117,7 @@ bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist) index_start = index_end = 0; /* no length left to cut */ } - BKE_gpencil_trim_stroke_points(gps, index_start, index_end); + BKE_gpencil_stroke_trim_points(gps, index_start, index_end); if (gps->totpoints == 0) { return false; @@ -2009,7 +2145,7 @@ bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist) * \param i: Point index * \param inf: Amount of smoothing to apply */ -bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf) +bool BKE_gpencil_stroke_smooth(bGPDstroke *gps, int i, float inf) { bGPDspoint *pt = &gps->points[i]; float sco[3] = {0.0f}; @@ -2068,7 +2204,7 @@ bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf) /** * Apply smooth for strength to stroke point */ -bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence) { bGPDspoint *ptb = &gps->points[point_index]; @@ -2128,7 +2264,7 @@ bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float /** * Apply smooth for thickness to stroke point (use pressure) */ -bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence) { bGPDspoint *ptb = &gps->points[point_index]; @@ -2188,7 +2324,7 @@ bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float /** * Apply smooth for UV rotation to stroke point (use pressure). */ -bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence) { bGPDspoint *ptb = &gps->points[point_index]; @@ -2233,12 +2369,12 @@ bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influe * \param r_initframe: Number of first selected frame * \param r_endframe: Number of last selected frame */ -void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe) +void BKE_gpencil_frame_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe) { *r_initframe = gpl->actframe->framenum; *r_endframe = gpl->actframe->framenum; - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (gpf->flag & GP_FRAME_SELECT) { if (gpf->framenum < *r_initframe) { *r_initframe = gpf->framenum; @@ -2291,9 +2427,9 @@ float BKE_gpencil_multiframe_falloff_calc( /* reassign strokes using a material */ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* reassign strokes */ if ((gps->mat_nr > index) || (gps->mat_nr > totcol - 1)) { gps->mat_nr--; @@ -2307,9 +2443,9 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index) /* remove strokes using a material */ bool BKE_gpencil_material_index_used(bGPdata *gpd, int index) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->mat_nr == index) { return true; } @@ -2333,9 +2469,9 @@ void BKE_gpencil_material_remap(struct bGPdata *gpd, } \ ((void)0) - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* reassign strokes */ MAT_NR_REMAP(gps->mat_nr); } @@ -2345,6 +2481,102 @@ void BKE_gpencil_material_remap(struct bGPdata *gpd, #undef MAT_NR_REMAP } +/* Load a table with material conversion index for merged materials. */ +bool BKE_gpencil_merge_materials_table_get(Object *ob, + const float hue_threshold, + const float sat_threshold, + const float val_threshold, + GHash *r_mat_table) +{ + bool changed = false; + + Material *ma_primary = NULL; + Material *ma_secondary = NULL; + MaterialGPencilStyle *gp_style_primary = NULL; + MaterialGPencilStyle *gp_style_secondary = NULL; + + short *totcol = BKE_object_material_len_p(ob); + if (totcol == 0) { + return changed; + } + + for (int idx_primary = 0; idx_primary < *totcol; idx_primary++) { + /* Read primary material to compare. */ + ma_primary = BKE_gpencil_material(ob, idx_primary + 1); + if (ma_primary == NULL) { + continue; + } + + for (int idx_secondary = idx_primary + 1; idx_secondary < *totcol; idx_secondary++) { + /* Read secondary material to compare with primary material. */ + ma_secondary = BKE_gpencil_material(ob, idx_secondary + 1); + if ((ma_secondary == NULL) || + (BLI_ghash_haskey(r_mat_table, POINTER_FROM_INT(idx_secondary)))) { + continue; + } + gp_style_primary = ma_primary->gp_style; + gp_style_secondary = ma_secondary->gp_style; + + if ((gp_style_primary == NULL) || (gp_style_secondary == NULL) || + (gp_style_secondary->flag & GP_MATERIAL_LOCKED)) { + continue; + } + + /* Check materials have the same mode. */ + if (gp_style_primary->mode != gp_style_secondary->mode) { + continue; + } + + /* Check materials have same stroke and fill attributes. */ + if ((gp_style_primary->flag & GP_MATERIAL_STROKE_SHOW) != + (gp_style_secondary->flag & GP_MATERIAL_STROKE_SHOW)) { + continue; + } + + if ((gp_style_primary->flag & GP_MATERIAL_FILL_SHOW) != + (gp_style_secondary->flag & GP_MATERIAL_FILL_SHOW)) { + continue; + } + + /* Check materials have the same type. */ + if ((gp_style_primary->stroke_style != gp_style_secondary->stroke_style) || + (gp_style_primary->fill_style != gp_style_secondary->fill_style)) { + continue; + } + + float s_hsv_a[3], s_hsv_b[3], f_hsv_a[3], f_hsv_b[3], col[3]; + copy_v3_v3(col, gp_style_primary->stroke_rgba); + rgb_to_hsv_compat_v(col, s_hsv_a); + copy_v3_v3(col, gp_style_secondary->stroke_rgba); + rgb_to_hsv_compat_v(col, s_hsv_b); + + copy_v3_v3(col, gp_style_primary->fill_rgba); + rgb_to_hsv_compat_v(col, f_hsv_a); + copy_v3_v3(col, gp_style_secondary->fill_rgba); + rgb_to_hsv_compat_v(col, f_hsv_b); + + /* Check stroke and fill color (only Hue and Saturation). */ + if ((!compare_ff(s_hsv_a[0], s_hsv_b[0], hue_threshold)) || + (!compare_ff(s_hsv_a[1], s_hsv_b[1], sat_threshold)) || + (!compare_ff(f_hsv_a[0], f_hsv_b[0], hue_threshold)) || + (!compare_ff(f_hsv_a[1], f_hsv_b[1], sat_threshold)) || + (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold)) || + (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold)) || + (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold)) || + (!compare_ff(s_hsv_a[2], s_hsv_b[2], val_threshold))) { + continue; + } + + /* Save conversion indexes. */ + BLI_ghash_insert( + r_mat_table, POINTER_FROM_INT(idx_secondary), POINTER_FROM_INT(idx_primary)); + changed = true; + } + } + + return changed; +} + /* statistics functions */ void BKE_gpencil_stats_update(bGPdata *gpd) { @@ -2353,11 +2585,11 @@ void BKE_gpencil_stats_update(bGPdata *gpd) gpd->totstroke = 0; gpd->totpoint = 0; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpd->totlayer++; - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { gpd->totframe++; - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { gpd->totstroke++; gpd->totpoint += gps->totpoints; } @@ -2366,7 +2598,7 @@ void BKE_gpencil_stats_update(bGPdata *gpd) } /* get material index (0-based like mat_nr not actcol) */ -int BKE_gpencil_object_material_get_index(Object *ob, Material *ma) +int BKE_gpencil_object_material_index_get(Object *ob, Material *ma) { short *totcol = BKE_object_material_len_p(ob); Material *read_ma = NULL; @@ -2524,61 +2756,48 @@ void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points, *r_direction = (int)locy[2]; } -/* calc bounding box in 2d using flat projection data */ -static void gpencil_calc_2d_bounding_box(const float (*points2d)[2], - int totpoints, - float minv[2], - float maxv[2]) -{ - minv[0] = points2d[0][0]; - minv[1] = points2d[0][1]; - maxv[0] = points2d[0][0]; - maxv[1] = points2d[0][1]; - - for (int i = 1; i < totpoints; i++) { - /* min */ - if (points2d[i][0] < minv[0]) { - minv[0] = points2d[i][0]; - } - if (points2d[i][1] < minv[1]) { - minv[1] = points2d[i][1]; - } - /* max */ - if (points2d[i][0] > maxv[0]) { - maxv[0] = points2d[i][0]; - } - if (points2d[i][1] > maxv[1]) { - maxv[1] = points2d[i][1]; - } - } - /* use a perfect square */ - if (maxv[0] > maxv[1]) { - maxv[1] = maxv[0]; - } - else { - maxv[0] = maxv[1]; - } -} - /* calc texture coordinates using flat projected points */ static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2], - int totpoints, + bGPDstroke *gps, const float minv[2], float maxv[2], float (*r_uv)[2]) { + const float s = sin(gps->uv_rotation); + const float c = cos(gps->uv_rotation); + + /* Calc center for rotation. */ + float center[2] = {0.5f, 0.5f}; float d[2]; d[0] = maxv[0] - minv[0]; d[1] = maxv[1] - minv[1]; - for (int i = 0; i < totpoints; i++) { + for (int i = 0; i < gps->totpoints; i++) { r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0]; r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1]; + + /* Apply translation. */ + add_v2_v2(r_uv[i], gps->uv_translation); + + /* Apply Rotation. */ + r_uv[i][0] -= center[0]; + r_uv[i][1] -= center[1]; + + float x = r_uv[i][0] * c - r_uv[i][1] * s; + float y = r_uv[i][0] * s + r_uv[i][1] * c; + + r_uv[i][0] = x + center[0]; + r_uv[i][1] = y + center[1]; + + /* Apply scale. */ + if (gps->uv_scale != 0.0f) { + mul_v2_fl(r_uv[i], 1.0f / gps->uv_scale); + } } } /* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was * modified) */ -void BKE_gpencil_triangulate_stroke_fill(bGPdata *gpd, bGPDstroke *gps) +void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) { BLI_assert(gps->totpoints >= 3); @@ -2600,36 +2819,25 @@ void BKE_gpencil_triangulate_stroke_fill(bGPdata *gpd, bGPDstroke *gps) float minv[2]; float maxv[2]; /* first needs bounding box data */ - if (gpd->flag & GP_DATA_UV_ADAPTIVE) { - gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv); - } - else { - ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); - ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); - } + ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); + ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); /* calc uv data */ - gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv); + gpencil_calc_stroke_fill_uv(points2d, gps, minv, maxv, uv); - /* Number of triangles */ - gps->tot_triangles = gps->totpoints - 2; - /* save triangulation data in stroke cache */ + /* Save triangulation data. */ if (gps->tot_triangles > 0) { - if (gps->triangles == NULL) { - gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, - "GP Stroke triangulation"); - } - else { - gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles); - } + MEM_SAFE_FREE(gps->triangles); + gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, + "GP Stroke triangulation"); for (int i = 0; i < gps->tot_triangles; i++) { - bGPDtriangle *stroke_triangle = &gps->triangles[i]; memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); - /* copy texture coordinates */ - copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]); - copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]); - copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]); + } + + /* Copy UVs to bGPDspoint. */ + for (int i = 0; i < gps->totpoints; i++) { + copy_v2_v2(gps->points[i].uv_fill, uv[i]); } } else { @@ -2641,17 +2849,50 @@ void BKE_gpencil_triangulate_stroke_fill(bGPdata *gpd, bGPDstroke *gps) gps->triangles = NULL; } - /* disable recalculation flag */ - if (gps->flag & GP_STROKE_RECALC_GEOMETRY) { - gps->flag &= ~GP_STROKE_RECALC_GEOMETRY; - } - /* clear memory */ MEM_SAFE_FREE(tmp_triangles); MEM_SAFE_FREE(points2d); MEM_SAFE_FREE(uv); } +/* texture coordinate utilities */ +void BKE_gpencil_stroke_uv_update(bGPDstroke *gps) +{ + if (gps == NULL || gps->totpoints == 0) { + return; + } + + bGPDspoint *pt = gps->points; + float totlen = 0.0f; + pt[0].uv_fac = totlen; + for (int i = 1; i < gps->totpoints; i++) { + totlen += len_v3v3(&pt[i - 1].x, &pt[i].x); + pt[i].uv_fac = totlen; + } +} + +/* Recalc the internal geometry caches for fill and uvs. */ +void BKE_gpencil_stroke_geometry_update(bGPDstroke *gps) +{ + if (gps == NULL) { + return; + } + + if (gps->totpoints > 2) { + BKE_gpencil_stroke_fill_triangulate(gps); + } + else { + gps->tot_triangles = 0; + MEM_SAFE_FREE(gps->triangles); + } + + /* calc uv data along the stroke */ + BKE_gpencil_stroke_uv_update(gps); + + /* Calc stroke bounding box. */ + BKE_gpencil_stroke_boundingbox_calc(gps); +} + float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d) { if (!gps->points || gps->totpoints < 2) { @@ -2678,7 +2919,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_trim_stroke(bGPDstroke *gps) +bool BKE_gpencil_stroke_trim(bGPDstroke *gps) { if (gps->totpoints < 4) { return false; @@ -2759,13 +3000,14 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps) } } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; gps->totpoints = newtot; MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); } + + BKE_gpencil_stroke_geometry_update(gps); + return intersect; } @@ -2773,7 +3015,7 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps) * Close stroke * \param gps: Stroke to close */ -bool BKE_gpencil_close_stroke(bGPDstroke *gps) +bool BKE_gpencil_stroke_close(bGPDstroke *gps) { bGPDspoint *pt1 = NULL; bGPDspoint *pt2 = NULL; @@ -2831,6 +3073,7 @@ bool BKE_gpencil_close_stroke(bGPDstroke *gps) pt->pressure = interpf(pt2->pressure, pt1->pressure, step); pt->strength = interpf(pt2->strength, pt1->strength, step); pt->flag = 0; + interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step); /* Set weights. */ if (gps->dvert != NULL) { @@ -2933,8 +3176,7 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta gps->totpoints = tot; /* triangles cache needs to be recalculated */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + BKE_gpencil_stroke_geometry_update(gps); } } @@ -2947,7 +3189,7 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta * \param threshold: Distance between points * \param use_unselected: Set to true to analyze all stroke and not only selected points */ -void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf, +void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf, bGPDstroke *gps, const float threshold, const bool use_unselected) @@ -3014,6 +3256,9 @@ void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf, if (tagged) { BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG); } + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* Helper: Check materials with same color. */ @@ -3033,7 +3278,8 @@ static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Mate float hsv2[4]; rgb_to_hsv_v(gp_style->fill_rgba, hsv2); hsv2[3] = gp_style->fill_rgba[3]; - if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_SOLID) && (compare_v4v4(hsv1, hsv2, 0.01f))) { + if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) && + (compare_v4v4(hsv1, hsv2, 0.01f))) { *r_mat = ma; return i - 1; } @@ -3058,24 +3304,24 @@ static Material *gpencil_add_from_curve_material(Main *bmain, /* Stroke color. */ if (gpencil_lines) { ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f); - gp_style->flag |= GP_STYLE_STROKE_SHOW; + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } else { linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color); - gp_style->flag &= ~GP_STYLE_STROKE_SHOW; + gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; } /* Fill color. */ linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color); /* Fill is false if the original curve hasn't material assigned, so enable it. */ if (fill) { - gp_style->flag |= GP_STYLE_FILL_SHOW; + gp_style->flag |= GP_MATERIAL_FILL_SHOW; } /* Check at least one is enabled. */ - if (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0) && - ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) { - gp_style->flag |= GP_STYLE_STROKE_SHOW; + if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) && + ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) { + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } return mat_gp; @@ -3140,13 +3386,14 @@ static void gpencil_convert_spline(Main *bmain, /* Create Stroke. */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); gps->thickness = 1.0f; - gps->gradient_f = 1.0f; - ARRAY_SET_ITEMS(gps->gradient_s, 1.0f, 1.0f); + gps->fill_opacity_fac = 1.0f; + gps->hardeness = 1.0f; + gps->uv_scale = 1.0f; + + ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f); ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND); gps->inittime = 0.0f; - /* Enable recalculation flag by default. */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; gps->flag &= ~GP_STROKE_SELECT; gps->flag |= GP_STROKE_3DSPACE; @@ -3165,10 +3412,6 @@ static void gpencil_convert_spline(Main *bmain, } totpoints = (resolu * segments) - (segments - 1); - /* Initialize triangle memory to dummy data. */ - gps->tot_triangles = 0; - gps->triangles = NULL; - /* Materials * Notice: The color of the material is the color of viewport and not the final shader color. */ @@ -3212,7 +3455,6 @@ static void gpencil_convert_spline(Main *bmain, copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba); gp_style_gp->fill_style = gp_style_cur->fill_style; gp_style_gp->mix_factor = gp_style_cur->mix_factor; - gp_style_gp->gradient_angle = gp_style_cur->gradient_angle; } /* If object has more than 1 material, use second material for stroke color. */ @@ -3228,16 +3470,16 @@ static void gpencil_convert_spline(Main *bmain, if (ob_cu->totcol > 0) { mat_curve = BKE_object_material_get(ob_cu, 1); if (mat_curve) { - linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); + copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); mat_gp->gp_style->stroke_rgba[3] = mat_curve->a; /* Set fill and stroke depending of curve type (3D or 2D). */ if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) { - mat_gp->gp_style->flag |= GP_STYLE_STROKE_SHOW; - mat_gp->gp_style->flag &= ~GP_STYLE_FILL_SHOW; + mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; } else { - mat_gp->gp_style->flag &= ~GP_STYLE_STROKE_SHOW; - mat_gp->gp_style->flag |= GP_STYLE_FILL_SHOW; + mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW; } } } @@ -3349,8 +3591,11 @@ static void gpencil_convert_spline(Main *bmain, } /* Cyclic curve, close stroke. */ if ((cyclic) && (!do_stroke)) { - BKE_gpencil_close_stroke(gps); + BKE_gpencil_stroke_close(gps); } + + /* Recalc fill geometry. */ + BKE_gpencil_stroke_geometry_update(gps); } /* Convert a curve object to grease pencil stroke. @@ -3388,7 +3633,7 @@ void BKE_gpencil_convert_curve(Main *bmain, if (use_collections) { Collection *collection = gpencil_get_parent_collection(scene, ob_cu); if (collection != NULL) { - gpl = BLI_findstring(&gpd->layers, collection->id.name + 2, offsetof(bGPDlayer, info)); + gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2); if (gpl == NULL) { gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true); } @@ -3396,14 +3641,14 @@ void BKE_gpencil_convert_curve(Main *bmain, } if (gpl == NULL) { - gpl = BKE_gpencil_layer_getactive(gpd); + gpl = BKE_gpencil_layer_active_get(gpd); if (gpl == NULL) { gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); } } /* Check if there is an active frame and add if needed. */ - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); /* Read all splines of the curve and create a stroke for each. */ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) { @@ -3413,3 +3658,379 @@ void BKE_gpencil_convert_curve(Main *bmain, /* Tag for recalculation */ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); } + +/* Create a default palette */ +void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene) +{ + const int totcol = 120; + const char *hexcol[] = { + "FFFFFF", "F2F2F2", "E6E6E6", "D9D9D9", "CCCCCC", "BFBFBF", "B2B2B2", "A6A6A6", "999999", + "8C8C8C", "808080", "737373", "666666", "595959", "4C4C4C", "404040", "333333", "262626", + "1A1A1A", "000000", "F2FC24", "FFEA00", "FEA711", "FE8B68", "FB3B02", "FE3521", "D00000", + "A81F3D", "780422", "2B0000", "F1E2C5", "FEE4B3", "FEDABB", "FEC28E", "D88F57", "BD6340", + "A2402B", "63352D", "6B2833", "34120C", "E7CB8F", "D1B38B", "C1B17F", "D7980B", "FFB100", + "FE8B00", "FF6A00", "B74100", "5F3E1D", "3B2300", "FECADA", "FE65CB", "FE1392", "DD3062", + "C04A6D", "891688", "4D2689", "441521", "2C1139", "241422", "FFFF7D", "FFFF00", "FF7F00", + "FF7D7D", "FF7DFF", "FF00FE", "FF007F", "FF0000", "7F0000", "0A0A00", "F6FDFF", "E9F7FF", + "CFE6FE", "AAC7FE", "77B3FE", "1E74FD", "0046AA", "2F4476", "003052", "0E0E25", "EEF5F0", + "D6E5DE", "ACD8B9", "6CADC6", "42A9AF", "007F7F", "49675C", "2E4E4E", "1D3239", "0F1C21", + "D8FFF4", "B8F4F5", "AECCB5", "76C578", "358757", "409B68", "468768", "1F512B", "2A3C37", + "122E1D", "EFFFC9", "E6F385", "BCF51C", "D4DC18", "82D322", "5C7F00", "59932B", "297F00", + "004320", "1C3322", "00FF7F", "00FF00", "7DFF7D", "7DFFFF", "00FFFF", "7D7DFF", "7F00FF", + "0000FF", "3F007F", "00007F"}; + + ToolSettings *ts = scene->toolsettings; + GpPaint *gp_paint = ts->gp_paint; + Paint *paint = &gp_paint->paint; + + paint->palette = BLI_findstring(&bmain->palettes, "Palette", offsetof(ID, name) + 2); + if (paint->palette == NULL) { + paint->palette = BKE_palette_add(bmain, "Palette"); + ts->gp_vertexpaint->paint.palette = paint->palette; + + /* Create Colors. */ + for (int i = 0; i < totcol; i++) { + PaletteColor *palcol = BKE_palette_color_add(paint->palette); + if (palcol) { + hex_to_rgb((char *)hexcol[i], palcol->rgb, palcol->rgb + 1, palcol->rgb + 2); + } + } + } +} + +bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size, const bool mask) +{ + Image *image = sima->image; + bool done = false; + + if (image == NULL) { + return false; + } + + ImageUser iuser = sima->iuser; + void *lock; + ImBuf *ibuf; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf->rect) { + int img_x = ibuf->x; + int img_y = ibuf->y; + + float color[4]; + bGPDspoint *pt; + for (int row = 0; row < img_y; row++) { + /* Create new stroke */ + bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, 0, img_x, size * 1000, false); + done = true; + for (int col = 0; col < img_x; col++) { + IMB_sampleImageAtLocation(ibuf, col, row, true, color); + pt = &gps->points[col]; + pt->pressure = 1.0f; + pt->x = col * size; + pt->z = row * size; + if (!mask) { + copy_v3_v3(pt->vert_color, color); + pt->vert_color[3] = 1.0f; + pt->strength = color[3]; + } + else { + zero_v3(pt->vert_color); + pt->vert_color[3] = 1.0f; + pt->strength = 1.0f - color[3]; + } + + /* Selet Alpha points. */ + if (pt->strength < 0.03f) { + gps->flag |= GP_STROKE_SELECT; + pt->flag |= GP_SPOINT_SELECT; + } + } + BKE_gpencil_stroke_geometry_update(gps); + } + } + + /* Free memory. */ + BKE_image_release_ibuf(image, ibuf, lock); + + return done; +} + +/* -------------------------------------------------------------------- */ +/** \name Iterators + * + * Iterate over all visible stroke of all visible layers inside a gpObject. + * Also take into account onion skining. + * + * \{ */ + +void BKE_gpencil_visible_stroke_iter( + Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra) +{ + bGPdata *gpd = (bGPdata *)ob->data; + const bool is_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool is_onion = do_onion && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0); + + /* Onion skinning. */ + const bool onion_mode_abs = (gpd->onion_mode == GP_ONION_MODE_ABSOLUTE); + const bool onion_mode_sel = (gpd->onion_mode == GP_ONION_MODE_SELECTED); + const bool onion_loop = (gpd->onion_flag & GP_ONION_LOOP) != 0; + const short onion_keytype = gpd->onion_keytype; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + + bGPDframe *act_gpf = gpl->actframe; + bGPDframe *sta_gpf = act_gpf; + bGPDframe *end_gpf = act_gpf ? act_gpf->next : NULL; + + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + + if (is_multiedit) { + sta_gpf = end_gpf = NULL; + /* Check the whole range and tag the editable frames. */ + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + if (gpf == act_gpf || (gpf->flag & GP_FRAME_SELECT)) { + gpf->runtime.onion_id = 0; + if (sta_gpf == NULL) { + sta_gpf = gpf; + } + end_gpf = gpf->next; + } + else { + gpf->runtime.onion_id = INT_MAX; + } + } + } + else if (is_onion && (gpl->onion_flag & GP_LAYER_ONIONSKIN)) { + if (act_gpf) { + bGPDframe *last_gpf = gpl->frames.last; + + int frame_len = 0; + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + gpf->runtime.frameid = frame_len++; + } + + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + bool is_wrong_keytype = (onion_keytype > -1) && (gpf->key_type != onion_keytype); + bool is_in_range; + int delta = (onion_mode_abs) ? (gpf->framenum - cfra) : + (gpf->runtime.frameid - act_gpf->runtime.frameid); + + if (onion_mode_sel) { + is_in_range = (gpf->flag & GP_FRAME_SELECT) != 0; + } + else { + is_in_range = (-delta <= gpd->gstep) && (delta <= gpd->gstep_next); + + if (onion_loop && !is_in_range) { + /* We wrap the value using the last frame and 0 as reference. */ + /* FIXME: This might not be good for animations not starting at 0. */ + int shift = (onion_mode_abs) ? last_gpf->framenum : last_gpf->runtime.frameid; + delta += (delta < 0) ? (shift + 1) : -(shift + 1); + /* Test again with wrapped value. */ + is_in_range = (-delta <= gpd->gstep) && (delta <= gpd->gstep_next); + } + } + /* Mask frames that have wrong keytype of are not in range. */ + gpf->runtime.onion_id = (is_wrong_keytype || !is_in_range) ? INT_MAX : delta; + } + /* Active frame is always shown. */ + act_gpf->runtime.onion_id = 0; + } + + sta_gpf = gpl->frames.first; + end_gpf = NULL; + } + else { + /* Bypass multiedit/onion skinning. */ + end_gpf = sta_gpf = NULL; + } + + if (sta_gpf == NULL && act_gpf == NULL) { + if (layer_cb) { + layer_cb(gpl, act_gpf, NULL, thunk); + } + continue; + } + + /* Draw multiedit/onion skinning first */ + for (bGPDframe *gpf = sta_gpf; gpf && gpf != end_gpf; gpf = gpf->next) { + if (gpf->runtime.onion_id == INT_MAX || gpf == act_gpf) { + continue; + } + + if (layer_cb) { + layer_cb(gpl, gpf, NULL, thunk); + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + stroke_cb(gpl, gpf, gps, thunk); + } + } + /* Draw Active frame on top. */ + /* Use evaluated frame (with modifiers for active stroke)/ */ + act_gpf = gpl->actframe; + act_gpf->runtime.onion_id = 0; + if (act_gpf) { + if (layer_cb) { + layer_cb(gpl, act_gpf, NULL, thunk); + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &act_gpf->strokes) { + stroke_cb(gpl, act_gpf, gps, thunk); + } + } + } +} + +void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig, + const struct bGPDframe *gpf_eval) +{ + bGPDstroke *gps_eval = gpf_eval->strokes.first; + LISTBASE_FOREACH (bGPDstroke *, gps_orig, &gpf_orig->strokes) { + + /* Assign original stroke pointer. */ + if (gps_eval != NULL) { + gps_eval->runtime.gps_orig = gps_orig; + + /* Assign original point pointer. */ + for (int i = 0; i < gps_orig->totpoints; i++) { + bGPDspoint *pt_eval = &gps_eval->points[i]; + pt_eval->runtime.pt_orig = &gps_orig->points[i]; + pt_eval->runtime.idx_orig = i; + } + /* Increase pointer. */ + gps_eval = gps_eval->next; + } + } +} + +void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_eval) +{ + bGPdata *gpd_eval = (bGPdata *)ob_eval->data; + bGPdata *gpd_orig = (bGPdata *)ob_orig->data; + + /* Assign pointers to the original stroke and points to the evaluated data. This must + * be done before applying any modifier because at this moment the structure is equals, + * so we can assume the layer index is the same in both datablocks. + * This data will be used by operators. */ + + bGPDlayer *gpl_eval = gpd_eval->layers.first; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { + if (gpl_eval != NULL) { + /* Update layer reference pointers. */ + gpl_eval->runtime.gpl_orig = (bGPDlayer *)gpl; + + bGPDframe *gpf_eval = gpl_eval->frames.first; + LISTBASE_FOREACH (bGPDframe *, gpf_orig, &gpl->frames) { + if (gpf_eval != NULL) { + /* Update frame reference pointers. */ + gpf_eval->runtime.gpf_orig = (bGPDframe *)gpf_orig; + BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval); + gpf_eval = gpf_eval->next; + } + } + gpl_eval = gpl_eval->next; + } + } +} + +void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph, + Object *obact, + bGPDlayer *gpl, + float diff_mat[4][4]) +{ + Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact; + Object *obparent = gpl->parent; + Object *obparent_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obparent) : + obparent; + + /* if not layer parented, try with object parented */ + if (obparent_eval == NULL) { + if (ob_eval != NULL) { + if (ob_eval->type == OB_GPENCIL) { + copy_m4_m4(diff_mat, ob_eval->obmat); + return; + } + } + /* not gpencil object */ + unit_m4(diff_mat); + return; + } + else { + if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { + mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + return; + } + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr); + if (pchan) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat); + mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + } + else { + /* if bone not found use object (armature) */ + mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + } + return; + } + else { + unit_m4(diff_mat); /* not defined type */ + } + } +} + +void BKE_gpencil_update_layer_parent(const Depsgraph *depsgraph, Object *ob) +{ + if (ob->type != OB_GPENCIL) { + return; + } + + bGPdata *gpd = (bGPdata *)ob->data; + bGPDspoint *pt; + int i; + float diff_mat[4][4]; + float cur_mat[4][4]; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if ((gpl->parent != NULL) && (gpl->actframe != NULL)) { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, gpl->parent); + + /* calculate new matrix */ + if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { + invert_m4_m4(cur_mat, ob_eval->obmat); + } + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_eval->pose, gpl->parsubstr); + if (pchan) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, ob_eval->obmat, pchan->pose_mat); + invert_m4_m4(cur_mat, tmp_mat); + } + } + /* only redo if any change */ + if (!equals_m4m4(gpl->inverse, cur_mat)) { + + /* first apply current transformation to all strokes */ + BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat); + /* undo local object */ + sub_v3_v3(diff_mat[3], ob->obmat[3]); + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + mul_m4_v3(diff_mat, &pt->x); + } + } + /* set new parent matrix */ + copy_m4_m4(gpl->inverse, cur_mat); + } + } + } +} +/** \} */ diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index ebb927a7d60..1014db27d84 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -96,7 +96,7 @@ 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 */ -void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float epsilon) +void BKE_gpencil_stroke_simplify_adaptive(bGPDstroke *gps, float epsilon) { bGPDspoint *old_points = MEM_dupallocN(gps->points); int totpoints = gps->totpoints; @@ -165,9 +165,6 @@ void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float epsilon) old_dvert = MEM_dupallocN(gps->dvert); } /* resize gps */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; - int j = 0; for (int i = 0; i < totpoints; i++) { bGPDspoint *pt_src = &old_points[i]; @@ -195,13 +192,16 @@ void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float epsilon) gps->totpoints = j; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); MEM_SAFE_FREE(marked); } /* Simplify alternate vertex of stroke except extremes */ -void BKE_gpencil_simplify_fixed(bGPDstroke *gps) +void BKE_gpencil_stroke_simplify_fixed(bGPDstroke *gps) { if (gps->totpoints < 5) { return; @@ -227,8 +227,6 @@ void BKE_gpencil_simplify_fixed(bGPDstroke *gps) if (gps->dvert != NULL) { gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; int j = 0; for (int i = 0; i < gps->totpoints; i++) { @@ -256,6 +254,8 @@ void BKE_gpencil_simplify_fixed(bGPDstroke *gps) } gps->totpoints = j; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); @@ -357,73 +357,8 @@ bool BKE_gpencil_has_transform_modifiers(Object *ob) return false; } -/* apply stroke modifiers */ -void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, - Object *ob, - bGPDlayer *gpl, - bGPDframe *gpf, - bGPDstroke *gps, - bool is_render) -{ - GpencilModifierData *md; - bGPdata *gpd = ob->data; - const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); - - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - - if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) { - continue; - } - - if (mti && mti->deformStroke) { - mti->deformStroke(md, depsgraph, ob, gpl, gpf, gps); - /* subdivide always requires update */ - if (md->type == eGpencilModifierType_Subdiv) { - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - } - /* some modifiers could require a recalc of fill triangulation data */ - else if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) { - if (ELEM(md->type, - eGpencilModifierType_Armature, - eGpencilModifierType_Hook, - eGpencilModifierType_Lattice, - eGpencilModifierType_Offset)) { - - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - } - } - } - } - } -} - -/* apply stroke geometry modifiers */ -void BKE_gpencil_geometry_modifiers( - Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render) -{ - GpencilModifierData *md; - bGPdata *gpd = ob->data; - const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); - - for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - - if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) { - continue; - } - - if (mti->generateStrokes) { - mti->generateStrokes(md, depsgraph, ob, gpl, gpf); - } - } - } -} - /* apply time modifiers */ -int BKE_gpencil_time_modifier( +static int gpencil_time_modifier( Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render) { GpencilModifierData *md; @@ -454,14 +389,14 @@ int BKE_gpencil_time_modifier( } /* *************************************************** */ -void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, bGPdata *gpd) +void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd) { DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd); int ctime = (int)DEG_get_ctime(depsgraph); /* update active frame */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV); + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, ctime, GP_GETFRAME_USE_PREV); } if (DEG_is_active(depsgraph)) { @@ -471,8 +406,8 @@ void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, bGPdata *gpd) * so that editing tools work with copy-on-write * when the current frame changes */ - for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) { - gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV); + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, ctime, GP_GETFRAME_USE_PREV); } } } @@ -687,7 +622,7 @@ GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *na return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name)); } -void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) +void BKE_gpencil_stroke_subdivide(bGPDstroke *gps, int level, int type) { bGPDspoint *temp_points; MDeformVert *temp_dverts = NULL; @@ -710,8 +645,6 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) temp_dverts = MEM_dupallocN(gps->dvert); gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; /* move points from last to first to new place */ i2 = gps->totpoints - 1; @@ -726,6 +659,7 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) pt_final->flag = pt->flag; pt_final->runtime.pt_orig = pt->runtime.pt_orig; pt_final->runtime.idx_orig = pt->runtime.idx_orig; + copy_v4_v4(pt_final->vert_color, pt->vert_color); if (gps->dvert != NULL) { dvert = &temp_dverts[i]; @@ -749,6 +683,7 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt_final->time = interpf(pt->time, next->time, 0.5f); pt_final->runtime.pt_orig = NULL; + interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f); if (gps->dvert != NULL) { dvert = &temp_dverts[i]; @@ -775,8 +710,8 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) MEM_SAFE_FREE(temp_points); MEM_SAFE_FREE(temp_dverts); - /* move points to smooth stroke (not simple flag )*/ - if ((flag & GP_SUBDIV_SIMPLE) == 0) { + /* move points to smooth stroke (not simple type )*/ + if (type != GP_SUBDIV_SIMPLE) { /* duplicate points in a temp area with the new subdivide data */ temp_points = MEM_dupallocN(gps->points); @@ -793,145 +728,186 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) MEM_SAFE_FREE(temp_points); } } + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); +} + +/* Remap frame (Time modifier) */ +static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl) +{ + const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const bool time_remap = BKE_gpencil_has_time_modifiers(ob); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + + int remap_cfra = cfra_eval; + if (time_remap) { + remap_cfra = gpencil_time_modifier(depsgraph, scene, ob, gpl, cfra_eval, is_render); + } + + return remap_cfra; } -/* Copy frame but do not assign new memory */ -static void gpencil_frame_copy_noalloc(Object *ob, bGPDframe *gpf, bGPDframe *gpf_eval) +/* Get the current frame retimed with time modifiers. */ +bGPDframe *BKE_gpencil_frame_retime_get(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + bGPDlayer *gpl) { - gpf_eval->prev = gpf->prev; - gpf_eval->next = gpf->next; - gpf_eval->framenum = gpf->framenum; - gpf_eval->flag = gpf->flag; - gpf_eval->key_type = gpf->key_type; - gpf_eval->runtime = gpf->runtime; - copy_m4_m4(gpf_eval->runtime.parent_obmat, gpf->runtime.parent_obmat); + int remap_cfra = gpencil_remap_time_get(depsgraph, scene, ob, gpl); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, remap_cfra, GP_GETFRAME_USE_PREV); - /* copy strokes */ - BLI_listbase_clear(&gpf_eval->strokes); - for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) { - /* make copy of source stroke */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + return gpf; +} - /* copy color to temp fields to apply temporal changes in the stroke */ - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps_src->mat_nr + 1); - if (gp_style) { - copy_v4_v4(gps_dst->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); - copy_v4_v4(gps_dst->runtime.tmp_fill_rgba, gp_style->fill_rgba); - } +static void gpencil_assign_object_eval(Object *object) +{ + BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE); - /* Save original pointers for using in edit and select operators. */ - gps_dst->runtime.gps_orig = gps_src; - for (int i = 0; i < gps_src->totpoints; i++) { - bGPDspoint *pt_dst = &gps_dst->points[i]; - pt_dst->runtime.pt_orig = &gps_src->points[i]; - pt_dst->runtime.idx_orig = i; - } + bGPdata *gpd_eval = object->runtime.gpd_eval; + + gpd_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT; - BLI_addtail(&gpf_eval->strokes, gps_dst); + if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) { + object->data = gpd_eval; } } -/* Ensure there is a evaluated frame */ -static void gpencil_evaluated_frame_ensure(int idx, - Object *ob, - bGPDframe *gpf, - bGPDframe **gpf_eval) +/* Helper: Copy active frame from original datablock to evaluated datablock for modifiers. */ +static void gpencil_copy_activeframe_to_eval( + Depsgraph *depsgraph, Scene *scene, Object *ob, bGPdata *gpd_orig, bGPdata *gpd_eval) { - /* Create evaluated frames array data or expand. */ - bGPDframe *evaluated_frames = ob->runtime.gpencil_evaluated_frames; - *gpf_eval = &evaluated_frames[idx]; - /* If already exist a evaluated frame create a new one. */ - if (*gpf_eval != NULL) { - /* first clear temp data */ - BKE_gpencil_free_frame_runtime_data(*gpf_eval); + bGPDlayer *gpl_eval = gpd_eval->layers.first; + LISTBASE_FOREACH (bGPDlayer *, gpl_orig, &gpd_orig->layers) { + + if (gpl_eval != NULL) { + int remap_cfra = gpencil_remap_time_get(depsgraph, scene, ob, gpl_orig); + + bGPDframe *gpf_orig = BKE_gpencil_layer_frame_get( + gpl_orig, remap_cfra, GP_GETFRAME_USE_PREV); + + if (gpf_orig != NULL) { + int gpf_index = BLI_findindex(&gpl_orig->frames, gpf_orig); + bGPDframe *gpf_eval = BLI_findlink(&gpl_eval->frames, gpf_index); + + if (gpf_eval != NULL) { + /* Delete old strokes. */ + BKE_gpencil_free_strokes(gpf_eval); + /* Copy again strokes. */ + BKE_gpencil_frame_copy_strokes(gpf_orig, gpf_eval); + + gpf_eval->runtime.gpf_orig = (bGPDframe *)gpf_orig; + BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval); + } + } + + gpl_eval = gpl_eval->next; + } } - /* Copy data (do not assign new memory). */ - gpencil_frame_copy_noalloc(ob, gpf, *gpf_eval); } -/* Calculate gpencil modifiers */ -void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob) +static bGPdata *gpencil_copy_for_eval(bGPdata *gpd) { - /* use original data to set reference pointers to original data */ - Object *ob_orig = DEG_get_original_object(ob); - bGPdata *gpd = (bGPdata *)ob_orig->data; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const bool simplify_modif = GPENCIL_SIMPLIFY_MODIF(scene, false); - const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - const bool time_remap = BKE_gpencil_has_time_modifiers(ob); - int cfra_eval = (int)DEG_get_ctime(depsgraph); + int flags = LIB_ID_COPY_LOCALIZE; + + bGPdata *result; + BKE_id_copy_ex(NULL, &gpd->id, (ID **)&result, flags); + return result; +} - /* Clear any previous evaluated data. */ - if (ob->runtime.gpencil_tot_layers > 0) { - for (int i = 0; i < ob->runtime.gpencil_tot_layers; i++) { - bGPDframe *gpf_eval = &ob->runtime.gpencil_evaluated_frames[i]; - BKE_gpencil_free_frame_runtime_data(gpf_eval); +void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + bGPdata *gpd_eval = (bGPdata *)ob->data; + Object *ob_orig = (Object *)DEG_get_original_id(&ob->id); + bGPdata *gpd_orig = (bGPdata *)ob_orig->data; + + /* Need check if some layer is parented. */ + bool do_parent = false; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { + if (gpl->parent != NULL) { + do_parent = true; + break; } } - /* Create array of evaluated frames equal to number of layers. */ - ob->runtime.gpencil_tot_layers = BLI_listbase_count(&gpd->layers); - CLAMP_MIN(ob->runtime.gpencil_tot_layers, 1); - if (ob->runtime.gpencil_evaluated_frames == NULL) { - ob->runtime.gpencil_evaluated_frames = MEM_callocN( - sizeof(struct bGPDframe) * ob->runtime.gpencil_tot_layers, __func__); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_eval); + const bool do_modifiers = (bool)((!is_multiedit) && (ob->greasepencil_modifiers.first != NULL) && + (!GPENCIL_SIMPLIFY_MODIF(scene))); + if ((!do_modifiers) && (!do_parent)) { + return; + } + DEG_debug_print_eval(depsgraph, __func__, gpd_eval->id.name, gpd_eval); + + /* If only one user, don't need a new copy, just update data of the frame. */ + if (gpd_orig->id.us == 1) { + ob->runtime.gpd_eval = NULL; + gpencil_copy_activeframe_to_eval(depsgraph, scene, ob, ob_orig->data, gpd_eval); + return; } - else { - ob->runtime.gpencil_evaluated_frames = MEM_recallocN(ob->runtime.gpencil_evaluated_frames, - sizeof(struct bGPDframe) * - ob->runtime.gpencil_tot_layers); + + /* Copy full Datablock to evaluated version. */ + ob->runtime.gpd_orig = gpd_orig; + if (ob->runtime.gpd_eval != NULL) { + BKE_gpencil_eval_delete(ob->runtime.gpd_eval); + ob->runtime.gpd_eval = NULL; + ob->data = ob->runtime.gpd_orig; + } + ob->runtime.gpd_eval = gpencil_copy_for_eval(ob->runtime.gpd_orig); + gpencil_assign_object_eval(ob); + BKE_gpencil_update_orig_pointers(ob_orig, (Object *)ob); +} + +/* Calculate gpencil modifiers */ +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_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const bool do_modifiers = (bool)((!is_multiedit) && (ob->greasepencil_modifiers.first != NULL) && + (!GPENCIL_SIMPLIFY_MODIF(scene))); + if (!do_modifiers) { + return; } /* Init general modifiers data. */ - if (ob->greasepencil_modifiers.first) { - BKE_gpencil_lattice_init(ob); - } - - /* ***************************************************************** - * Loop all layers, duplicate data and apply modifiers. - * - * ******************************************************************/ - int idx = 0; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* Remap frame (Time modifier) */ - int remap_cfra = cfra_eval; - if ((time_remap) && (!simplify_modif)) { - remap_cfra = BKE_gpencil_time_modifier(depsgraph, scene, ob, gpl, cfra_eval, is_render); - } - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV); + BKE_gpencil_lattice_init(ob); - if (gpf == NULL) { - idx++; - continue; - } + const bool time_remap = BKE_gpencil_has_time_modifiers(ob); - /* Create a duplicate data set of stroke to modify. */ - bGPDframe *gpf_eval = NULL; - gpencil_evaluated_frame_ensure(idx, ob, gpf, &gpf_eval); + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { - /* Skip all if some disable flag is enabled. */ - if ((ob->greasepencil_modifiers.first == NULL) || (is_multiedit) || (simplify_modif)) { - idx++; - continue; - } + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - /* Apply geometry modifiers (create new geometry). */ - if (BKE_gpencil_has_geometry_modifiers(ob)) { - BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, gpf_eval, is_render); - } + if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) { + continue; + } - /* Loop all strokes and deform them. */ - for (bGPDstroke *gps = gpf_eval->strokes.first; gps; gps = gps->next) { - /* Apply modifiers that only deform geometry */ - BKE_gpencil_stroke_modifiers(depsgraph, ob, gpl, gpf_eval, gps, is_render); - } + /* Apply geometry modifiers (add new geometry). */ + if (mti && mti->generateStrokes) { + mti->generateStrokes(md, depsgraph, ob); + } - idx++; + /* Apply deform modifiers and Time remap (only change geometry). */ + if ((time_remap) || (mti && mti->deformStroke)) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl); + if (gpf == NULL) { + continue; + } + + if (mti->deformStroke) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + mti->deformStroke(md, depsgraph, ob, gpl, gpf, gps); + } + } + } + } + } } /* Clear any lattice data. */ - if (ob->greasepencil_modifiers.first) { - BKE_gpencil_lattice_clear(ob); - } + BKE_gpencil_lattice_clear(ob); } diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index e1868d88351..ee27d0e546d 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -738,6 +738,15 @@ static void library_foreach_ID_link(Main *bmain, if (toolsett->gp_paint) { library_foreach_paint(&data, &toolsett->gp_paint->paint); } + if (toolsett->gp_vertexpaint) { + library_foreach_paint(&data, &toolsett->gp_vertexpaint->paint); + } + if (toolsett->gp_sculptpaint) { + library_foreach_paint(&data, &toolsett->gp_sculptpaint->paint); + } + if (toolsett->gp_weightpaint) { + library_foreach_paint(&data, &toolsett->gp_weightpaint->paint); + } CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP); } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 10f32a6b0bc..22d7c505e60 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -168,15 +168,12 @@ void BKE_gpencil_material_attr_init(Material *ma) /* set basic settings */ gp_style->stroke_rgba[3] = 1.0f; gp_style->fill_rgba[3] = 1.0f; - gp_style->pattern_gridsize = 0.1f; - gp_style->gradient_radius = 0.5f; ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f); - ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f); ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f); gp_style->texture_opacity = 1.0f; gp_style->texture_pixsize = 100.0f; - gp_style->flag |= GP_STYLE_STROKE_SHOW; + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index e4a3174c908..211cb633881 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -729,8 +729,11 @@ void BKE_object_free_derived_caches(Object *ob) BKE_object_to_mesh_clear(ob); BKE_object_free_curve_cache(ob); - /* clear grease pencil data */ - DRW_gpencil_freecache(ob); + /* Clear grease pencil data. */ + if (ob->runtime.gpd_eval != NULL) { + BKE_gpencil_eval_delete(ob->runtime.gpd_eval); + ob->runtime.gpd_eval = NULL; + } } void BKE_object_free_caches(Object *object) @@ -803,6 +806,9 @@ bool BKE_object_is_in_editmode(const Object *ob) case OB_SURF: case OB_CURVE: return ((Curve *)ob->data)->editnurb != NULL; + case OB_GPENCIL: + /* Grease Pencil object has no edit mode data. */ + return GPENCIL_EDIT_MODE((bGPdata *)ob->data); default: return false; } @@ -1034,6 +1040,10 @@ static void object_init(Object *ob, const short ob_type) ob->trackflag = OB_NEGZ; ob->upflag = OB_POSY; } + + if (ob->type == OB_GPENCIL) { + ob->dtx |= OB_USE_GPENCIL_LIGHTS; + } } void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) @@ -3963,7 +3973,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag)) runtime->data_eval = NULL; runtime->mesh_deform_eval = NULL; runtime->curve_cache = NULL; - runtime->gpencil_cache = NULL; } /* diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index c647afdd00a..20b2ab9409f 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -24,6 +24,7 @@ #include "DNA_anim_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -150,6 +151,11 @@ void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob) else { ob->transflag &= ~OB_NEG_SCALE; } + + /* Assign evaluated version. */ + if ((ob->type == OB_GPENCIL) && (ob->runtime.gpd_eval != NULL)) { + ob->data = ob->runtime.gpd_eval; + } } void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob) @@ -213,9 +219,12 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o case OB_LATTICE: BKE_lattice_modifiers_calc(depsgraph, scene, ob); break; - case OB_GPENCIL: + case OB_GPENCIL: { + BKE_gpencil_prepare_eval_data(depsgraph, scene, ob); BKE_gpencil_modifiers_calc(depsgraph, scene, ob); + BKE_gpencil_update_layer_parent(depsgraph, ob); break; + } } /* particles */ diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 35683ca93f4..e6042b6ad4c 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -215,6 +215,15 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, ePaintMode mode) case PAINT_MODE_GPENCIL: paint_ptr = (Paint **)&ts->gp_paint; break; + case PAINT_MODE_VERTEX_GPENCIL: + paint_ptr = (Paint **)&ts->gp_vertexpaint; + break; + case PAINT_MODE_SCULPT_GPENCIL: + paint_ptr = (Paint **)&ts->gp_sculptpaint; + break; + case PAINT_MODE_WEIGHT_GPENCIL: + paint_ptr = (Paint **)&ts->gp_weightpaint; + break; case PAINT_MODE_INVALID: break; } @@ -244,6 +253,12 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode) return &ts->uvsculpt->paint; case PAINT_MODE_GPENCIL: return &ts->gp_paint->paint; + case PAINT_MODE_VERTEX_GPENCIL: + return &ts->gp_vertexpaint->paint; + case PAINT_MODE_SCULPT_GPENCIL: + return &ts->gp_sculptpaint->paint; + case PAINT_MODE_WEIGHT_GPENCIL: + return &ts->gp_weightpaint->paint; case PAINT_MODE_INVALID: return NULL; default: @@ -270,6 +285,12 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) return rna_enum_brush_uv_sculpt_tool_items; case PAINT_MODE_GPENCIL: return rna_enum_brush_gpencil_types_items; + case PAINT_MODE_VERTEX_GPENCIL: + return rna_enum_brush_gpencil_vertex_types_items; + case PAINT_MODE_SCULPT_GPENCIL: + return rna_enum_brush_gpencil_sculpt_types_items; + case PAINT_MODE_WEIGHT_GPENCIL: + return rna_enum_brush_gpencil_weight_types_items; case PAINT_MODE_INVALID: break; } @@ -292,6 +313,12 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode) return "uv_sculpt_tool"; case PAINT_MODE_GPENCIL: return "gpencil_tool"; + case PAINT_MODE_VERTEX_GPENCIL: + return "gpencil_vertex_tool"; + case PAINT_MODE_SCULPT_GPENCIL: + return "gpencil_sculpt_tool"; + case PAINT_MODE_WEIGHT_GPENCIL: + return "gpencil_weight_tool"; default: /* invalid paint mode */ return NULL; @@ -315,6 +342,12 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) return &ts->imapaint.paint; case OB_MODE_PAINT_GPENCIL: return &ts->gp_paint->paint; + case OB_MODE_VERTEX_GPENCIL: + return &ts->gp_vertexpaint->paint; + case OB_MODE_SCULPT_GPENCIL: + return &ts->gp_sculptpaint->paint; + case OB_MODE_WEIGHT_GPENCIL: + return &ts->gp_weightpaint->paint; case OB_MODE_EDIT: return &ts->uvsculpt->paint; default: @@ -429,6 +462,12 @@ ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref) return PAINT_MODE_GPENCIL; case CTX_MODE_PAINT_TEXTURE: return PAINT_MODE_TEXTURE_3D; + case CTX_MODE_VERTEX_GPENCIL: + return PAINT_MODE_VERTEX_GPENCIL; + case CTX_MODE_SCULPT_GPENCIL: + return PAINT_MODE_SCULPT_GPENCIL; + case CTX_MODE_WEIGHT_GPENCIL: + return PAINT_MODE_WEIGHT_GPENCIL; } } else if (tref->space_type == SPACE_IMAGE) { @@ -485,6 +524,18 @@ void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint) paint->runtime.tool_offset = offsetof(Brush, gpencil_tool); paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL; } + else if (paint == &ts->gp_vertexpaint->paint) { + paint->runtime.tool_offset = offsetof(Brush, gpencil_vertex_tool); + paint->runtime.ob_mode = OB_MODE_VERTEX_GPENCIL; + } + else if (paint == &ts->gp_sculptpaint->paint) { + paint->runtime.tool_offset = offsetof(Brush, gpencil_sculpt_tool); + paint->runtime.ob_mode = OB_MODE_SCULPT_GPENCIL; + } + else if (paint == &ts->gp_weightpaint->paint) { + paint->runtime.tool_offset = offsetof(Brush, gpencil_weight_tool); + paint->runtime.ob_mode = OB_MODE_WEIGHT_GPENCIL; + } else { BLI_assert(0); } @@ -506,6 +557,12 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode) return offsetof(Brush, uv_sculpt_tool); case PAINT_MODE_GPENCIL: return offsetof(Brush, gpencil_tool); + case PAINT_MODE_VERTEX_GPENCIL: + return offsetof(Brush, gpencil_vertex_tool); + case PAINT_MODE_SCULPT_GPENCIL: + return offsetof(Brush, gpencil_sculpt_tool); + case PAINT_MODE_WEIGHT_GPENCIL: + return offsetof(Brush, gpencil_weight_tool); case PAINT_MODE_INVALID: break; /* We don't use these yet. */ } @@ -639,6 +696,204 @@ bool BKE_palette_is_empty(const struct Palette *palette) return BLI_listbase_is_empty(&palette->colors); } +/* helper function to sort using qsort */ +static int palettecolor_compare_hsv(const void *a1, const void *a2) +{ + const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + + /* Hue */ + if (ps1->h > ps2->h) { + return 1; + } + else if (ps1->h < ps2->h) { + return -1; + } + + /* Saturation. */ + if (ps1->s > ps2->s) { + return 1; + } + else if (ps1->s < ps2->s) { + return -1; + } + + /* Value. */ + if (1.0f - ps1->v > 1.0f - ps2->v) { + return 1; + } + else if (1.0f - ps1->v < 1.0f - ps2->v) { + return -1; + } + + return 0; +} + +/* helper function to sort using qsort */ +static int palettecolor_compare_svh(const void *a1, const void *a2) +{ + const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + + /* Saturation. */ + if (ps1->s > ps2->s) { + return 1; + } + else if (ps1->s < ps2->s) { + return -1; + } + + /* Value. */ + if (1.0f - ps1->v > 1.0f - ps2->v) { + return 1; + } + else if (1.0f - ps1->v < 1.0f - ps2->v) { + return -1; + } + + /* Hue */ + if (ps1->h > ps2->h) { + return 1; + } + else if (ps1->h < ps2->h) { + return -1; + } + + return 0; +} + +static int palettecolor_compare_vhs(const void *a1, const void *a2) +{ + const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + + /* Value. */ + if (1.0f - ps1->v > 1.0f - ps2->v) { + return 1; + } + else if (1.0f - ps1->v < 1.0f - ps2->v) { + return -1; + } + + /* Hue */ + if (ps1->h > ps2->h) { + return 1; + } + else if (ps1->h < ps2->h) { + return -1; + } + + /* Saturation. */ + if (ps1->s > ps2->s) { + return 1; + } + else if (ps1->s < ps2->s) { + return -1; + } + + return 0; +} + +static int palettecolor_compare_luminance(const void *a1, const void *a2) +{ + const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + + float lumi1 = (ps1->rgb[0] + ps1->rgb[1] + ps1->rgb[2]) / 3.0f; + float lumi2 = (ps2->rgb[0] + ps2->rgb[1] + ps2->rgb[2]) / 3.0f; + + if (lumi1 > lumi2) { + return -1; + } + else if (lumi1 < lumi2) { + return 1; + } + + return 0; +} + +void BKE_palette_sort_hsv(tPaletteColorHSV *color_array, const int totcol) +{ + /* Sort by Hue , Saturation and Value. */ + qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_hsv); +} + +void BKE_palette_sort_svh(tPaletteColorHSV *color_array, const int totcol) +{ + /* Sort by Saturation, Value and Hue. */ + qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_svh); +} + +void BKE_palette_sort_vhs(tPaletteColorHSV *color_array, const int totcol) +{ + /* Sort by Saturation, Value and Hue. */ + qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_vhs); +} + +void BKE_palette_sort_luminance(tPaletteColorHSV *color_array, const int totcol) +{ + /* Sort by Luminance (calculated with the average, enough for sorting). */ + qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_luminance); +} + +bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, const bool linear) +{ + tPaletteColorHSV *color_array = NULL; + tPaletteColorHSV *col_elm = NULL; + bool done = false; + + const int totpal = BLI_ghash_len(color_table); + + if (totpal > 0) { + color_array = MEM_calloc_arrayN(totpal, sizeof(tPaletteColorHSV), __func__); + /* Put all colors in an array. */ + GHashIterator gh_iter; + int t = 0; + GHASH_ITER (gh_iter, color_table) { + const uint col = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter)); + float r, g, b; + float h, s, v; + cpack_to_rgb(col, &r, &g, &b); + rgb_to_hsv(r, g, b, &h, &s, &v); + + col_elm = &color_array[t]; + col_elm->rgb[0] = r; + col_elm->rgb[1] = g; + col_elm->rgb[2] = b; + col_elm->h = h; + col_elm->s = s; + col_elm->v = v; + t++; + } + } + + /* Create the Palette. */ + if (totpal > 0) { + /* Sort by Hue and saturation. */ + BKE_palette_sort_hsv(color_array, totpal); + + Palette *palette = BKE_palette_add(bmain, name); + if (palette) { + for (int i = 0; i < totpal; i++) { + col_elm = &color_array[i]; + PaletteColor *palcol = BKE_palette_color_add(palette); + if (palcol) { + copy_v3_v3(palcol->rgb, col_elm->rgb); + if (linear) { + linearrgb_to_srgb_v3_v3(palcol->rgb, palcol->rgb); + } + } + } + done = true; + } + } + else { + done = false; + } + + if (totpal > 0) { + MEM_SAFE_FREE(color_array); + } + + return done; +} + /* are we in vertex paint or weight paint face select mode? */ bool BKE_paint_select_face_test(Object *ob) { @@ -720,6 +975,9 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) BLI_assert(ELEM(*r_paint, /* Cast is annoying, but prevent NULL-pointer access. */ (Paint *)ts->gp_paint, + (Paint *)ts->gp_vertexpaint, + (Paint *)ts->gp_sculptpaint, + (Paint *)ts->gp_weightpaint, (Paint *)ts->sculpt, (Paint *)ts->vpaint, (Paint *)ts->wpaint, @@ -755,6 +1013,18 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) GpPaint *data = MEM_callocN(sizeof(*data), __func__); paint = &data->paint; } + else if ((GpVertexPaint **)r_paint == &ts->gp_vertexpaint) { + GpVertexPaint *data = MEM_callocN(sizeof(*data), __func__); + paint = &data->paint; + } + else if ((GpSculptPaint **)r_paint == &ts->gp_sculptpaint) { + GpSculptPaint *data = MEM_callocN(sizeof(*data), __func__); + paint = &data->paint; + } + else if ((GpWeightPaint **)r_paint == &ts->gp_weightpaint) { + GpWeightPaint *data = MEM_callocN(sizeof(*data), __func__); + paint = &data->paint; + } else if ((UvSculpt **)r_paint == &ts->uvsculpt) { UvSculpt *data = MEM_callocN(sizeof(*data), __func__); paint = &data->paint; diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c index e9601109fd5..7e58bf1eb8b 100644 --- a/source/blender/blenkernel/intern/paint_toolslots.c +++ b/source/blender/blenkernel/intern/paint_toolslots.c @@ -82,6 +82,15 @@ void BKE_paint_toolslots_init_from_main(struct Main *bmain) if (ts->gp_paint) { paint_toolslots_init(bmain, &ts->gp_paint->paint); } + if (ts->gp_vertexpaint) { + paint_toolslots_init(bmain, &ts->gp_vertexpaint->paint); + } + if (ts->gp_sculptpaint) { + paint_toolslots_init(bmain, &ts->gp_sculptpaint->paint); + } + if (ts->gp_weightpaint) { + paint_toolslots_init(bmain, &ts->gp_weightpaint->paint); + } } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a88f5a4daa4..f7f59687cb7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -201,72 +201,6 @@ static void scene_init_data(ID *id) BKE_color_managed_view_settings_init_render( &scene->r.bake.im_format.view_settings, &scene->r.bake.im_format.display_settings, "Filmic"); - /* GP Sculpt brushes */ - { - GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt; - GP_Sculpt_Data *gp_brush; - float curcolor_add[3], curcolor_sub[3]; - ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f); - ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH]; - gp_brush->size = 25; - gp_brush->strength = 0.3f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE | - GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS]; - gp_brush->size = 25; - gp_brush->strength = 0.5f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_STRENGTH]; - gp_brush->size = 25; - gp_brush->strength = 0.5f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_GRAB]; - gp_brush->size = 50; - gp_brush->strength = 0.3f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_PUSH]; - gp_brush->size = 25; - gp_brush->strength = 0.3f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_TWIST]; - gp_brush->size = 50; - gp_brush->strength = 0.3f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_PINCH]; - gp_brush->size = 50; - gp_brush->strength = 0.5f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - - gp_brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE]; - gp_brush->size = 25; - gp_brush->strength = 0.5f; - gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR; - copy_v3_v3(gp_brush->curcolor_add, curcolor_add); - copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); - } - /* Curve Profile */ scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE); @@ -560,6 +494,18 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) ts->gp_paint = MEM_dupallocN(ts->gp_paint); BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag); } + if (ts->gp_vertexpaint) { + ts->gp_vertexpaint = MEM_dupallocN(ts->gp_vertexpaint); + BKE_paint_copy(&ts->gp_vertexpaint->paint, &ts->gp_vertexpaint->paint, flag); + } + if (ts->gp_sculptpaint) { + ts->gp_sculptpaint = MEM_dupallocN(ts->gp_sculptpaint); + BKE_paint_copy(&ts->gp_sculptpaint->paint, &ts->gp_sculptpaint->paint, flag); + } + if (ts->gp_weightpaint) { + ts->gp_weightpaint = MEM_dupallocN(ts->gp_weightpaint); + BKE_paint_copy(&ts->gp_weightpaint->paint, &ts->gp_weightpaint->paint, flag); + } BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag); ts->imapaint.paintcursor = NULL; @@ -602,6 +548,18 @@ void BKE_toolsettings_free(ToolSettings *toolsettings) BKE_paint_free(&toolsettings->gp_paint->paint); MEM_freeN(toolsettings->gp_paint); } + if (toolsettings->gp_vertexpaint) { + BKE_paint_free(&toolsettings->gp_vertexpaint->paint); + MEM_freeN(toolsettings->gp_vertexpaint); + } + if (toolsettings->gp_sculptpaint) { + BKE_paint_free(&toolsettings->gp_sculptpaint->paint); + MEM_freeN(toolsettings->gp_sculptpaint); + } + if (toolsettings->gp_weightpaint) { + BKE_paint_free(&toolsettings->gp_weightpaint->paint); + MEM_freeN(toolsettings->gp_weightpaint); + } BKE_paint_free(&toolsettings->imapaint.paint); /* free Grease Pencil interpolation curve */ -- cgit v1.2.3