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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorAntonio Vazquez <blendergit@gmail.com>2020-03-09 18:27:24 +0300
committerAntonio Vazquez <blendergit@gmail.com>2020-03-09 18:27:24 +0300
commit29f3af95272590d26f610ae828b2eeee89c82a00 (patch)
treea696a58a2561c48f7ec6166e369e22081e0a64d8 /source
parentdcb93126876879d969a30a7865700abd072066f8 (diff)
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
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h13
-rw-r--r--source/blender/blenkernel/BKE_context.h3
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h159
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h39
-rw-r--r--source/blender/blenkernel/BKE_paint.h17
-rw-r--r--source/blender/blenkernel/intern/brush.c1077
-rw-r--r--source/blender/blenkernel/intern/context.c27
-rw-r--r--source/blender/blenkernel/intern/gpencil.c1061
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c358
-rw-r--r--source/blender/blenkernel/intern/lib_query.c9
-rw-r--r--source/blender/blenkernel/intern/material.c5
-rw-r--r--source/blender/blenkernel/intern/object.c15
-rw-r--r--source/blender/blenkernel/intern/object_update.c11
-rw-r--r--source/blender/blenkernel/intern/paint.c270
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c9
-rw-r--r--source/blender/blenkernel/intern/scene.c90
-rw-r--r--source/blender/blenlib/intern/BLI_memblock.c11
-rw-r--r--source/blender/blenloader/intern/readfile.c223
-rw-r--r--source/blender/blenloader/intern/versioning_270.c97
-rw-r--r--source/blender/blenloader/intern/versioning_280.c447
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c55
-rw-r--r--source/blender/blenloader/intern/writefile.c61
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc9
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc4
-rw-r--r--source/blender/draw/CMakeLists.txt50
-rw-r--r--source/blender/draw/DRW_engine.h1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_antialiasing.c169
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c568
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c1021
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c502
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c2071
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c1725
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h792
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c365
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader.c311
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c1415
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl85
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl82
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl37
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl68
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl46
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl70
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl51
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl65
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl98
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl98
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl32
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl74
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl44
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl64
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl21
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl12
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl157
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl593
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl17
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl14
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl17
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl53
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl19
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl234
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl16
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl126
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl31
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl11
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl9
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl126
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl142
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl66
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl15
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl110
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl264
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl63
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl354
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl76
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c24
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c85
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c391
-rw-r--r--source/blender/draw/engines/overlay/overlay_motion_path.c4
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c158
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h19
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c103
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c6
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl35
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl14
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl103
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl38
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl14
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl6
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c60
-rw-r--r--source/blender/draw/intern/DRW_render.h22
-rw-r--r--source/blender/draw/intern/draw_cache.c27
-rw-r--r--source/blender/draw/intern/draw_cache.h17
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c745
-rw-r--r--source/blender/draw/intern/draw_common.c2
-rw-r--r--source/blender/draw/intern/draw_common.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c34
-rw-r--r--source/blender/draw/intern/draw_manager.h18
-rw-r--r--source/blender/draw/intern/draw_manager_data.c65
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c91
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_smaa_lib.glsl11
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl13
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c10
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/armature/armature_naming.c2
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt6
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c37
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c21
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c304
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c58
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c93
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c104
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c571
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c493
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c170
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h68
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c145
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c126
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c316
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c1374
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c119
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c (renamed from source/blender/editors/gpencil/gpencil_brush.c)735
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c202
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c483
-rw-r--r--source/blender/editors/gpencil/gpencil_uv.c587
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c899
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c1414
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c901
-rw-r--r--source/blender/editors/include/ED_gpencil.h56
-rw-r--r--source/blender/editors/interface/interface.c6
-rw-r--r--source/blender/editors/interface/interface_eyedropper_gpencil_color.c114
-rw-r--r--source/blender/editors/interface/interface_handlers.c41
-rw-r--r--source/blender/editors/interface/interface_icons.c53
-rw-r--r--source/blender/editors/interface/interface_layout.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c48
-rw-r--r--source/blender/editors/object/object_add.c4
-rw-r--r--source/blender/editors/object/object_edit.c3
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c7
-rw-r--r--source/blender/editors/object/object_modes.c5
-rw-r--r--source/blender/editors/object/object_transform.c10
-rw-r--r--source/blender/editors/screen/area.c72
-rw-r--r--source/blender/editors/screen/screen_context.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c322
-rw-r--r--source/blender/editors/space_action/action_edit.c2
-rw-r--r--source/blender/editors/space_action/action_select.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c2
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c13
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c3
-rw-r--r--source/blender/editors/transform/transform_convert.c10
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c14
-rw-r--r--source/blender/editors/transform/transform_generics.c7
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c6
-rw-r--r--source/blender/editors/undo/ed_undo.c3
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c42
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h7
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c304
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c36
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c120
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c30
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c148
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c227
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c134
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c15
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c52
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c11
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c79
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c116
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c314
-rw-r--r--source/blender/gpu/GPU_framebuffer.h2
-rw-r--r--source/blender/gpu/GPU_shader_interface.h1
-rw-r--r--source/blender/gpu/GPU_texture.h1
-rw-r--r--source/blender/gpu/GPU_vertex_format.h2
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c15
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c1
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.c41
-rw-r--r--source/blender/imbuf/IMB_imbuf.h3
-rw-r--r--source/blender/imbuf/intern/imageprocess.c17
-rw-r--r--source/blender/makesdna/DNA_brush_types.h171
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h106
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h165
-rw-r--r--source/blender/makesdna/DNA_material_types.h65
-rw-r--r--source/blender/makesdna/DNA_object_enums.h6
-rw-r--r--source/blender/makesdna/DNA_object_types.h22
-rw-r--r--source/blender/makesdna/DNA_scene_types.h146
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h37
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h9
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h4
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/RNA_enum_types.h5
-rw-r--r--source/blender/makesrna/intern/rna_brush.c266
-rw-r--r--source/blender/makesrna/intern/rna_context.c1
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c416
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c493
-rw-r--r--source/blender/makesrna/intern/rna_material.c146
-rw-r--r--source/blender/makesrna/intern/rna_object.c29
-rw-r--r--source/blender/makesrna/intern/rna_scene.c136
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c313
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c129
-rw-r--r--source/blender/makesrna/intern/rna_space.c41
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c19
-rw-r--r--source/blender/shader_fx/CMakeLists.txt1
-rw-r--r--source/blender/shader_fx/FX_shader_types.h1
-rw-r--r--source/blender/shader_fx/intern/FX_shader_blur.c9
-rw-r--r--source/blender/shader_fx/intern/FX_shader_flip.c2
-rw-r--r--source/blender/shader_fx/intern/FX_shader_glow.c8
-rw-r--r--source/blender/shader_fx/intern/FX_shader_pixel.c2
-rw-r--r--source/blender/shader_fx/intern/FX_shader_rim.c2
-rw-r--r--source/blender/shader_fx/intern/FX_shader_shadow.c2
-rw-r--r--source/blender/shader_fx/intern/FX_shader_util.c1
-rw-r--r--source/blender/shader_fx/intern/FX_shader_wave.c2
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c3
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c58
229 files changed, 19313 insertions, 14010 deletions
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 */
diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c
index f7239f1b9d1..ee9ea15835b 100644
--- a/source/blender/blenlib/intern/BLI_memblock.c
+++ b/source/blender/blenlib/intern/BLI_memblock.c
@@ -81,7 +81,16 @@ BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size)
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback)
{
- BLI_memblock_clear(mblk, free_callback);
+ int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
+
+ if (free_callback) {
+ for (int i = 0; i <= mblk->elem_last; i++) {
+ int chunk_idx = i / elem_per_chunk;
+ int elem_idx = i - elem_per_chunk * chunk_idx;
+ void *val = (char *)(mblk->chunk_list[chunk_idx]) + mblk->elem_size * elem_idx;
+ free_callback(val);
+ }
+ }
for (int i = 0; i < mblk->chunk_len; i++) {
MEM_SAFE_FREE(mblk->chunk_list[i]);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6cf8c968ed4..01ab4c0603a 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3609,23 +3609,23 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
}
#if 0
- if (ntree->previews) {
- bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews");
- bNodeInstanceHashIterator iter;
-
- NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
- bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
- if (preview) {
- bNodePreview *new_preview = newimaadr(fd, preview);
- if (new_preview) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- BKE_node_instance_hash_insert(new_previews, key, new_preview);
- }
- }
- }
- BKE_node_instance_hash_free(ntree->previews, NULL);
- ntree->previews = new_previews;
- }
+ if (ntree->previews) {
+ bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews");
+ bNodeInstanceHashIterator iter;
+
+ NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
+ bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ if (preview) {
+ bNodePreview* new_preview = newimaadr(fd, preview);
+ if (new_preview) {
+ bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+ BKE_node_instance_hash_insert(new_previews, key, new_preview);
+ }
+ }
+ }
+ BKE_node_instance_hash_free(ntree->previews, NULL);
+ ntree->previews = new_previews;
+ }
#else
/* XXX TODO */
ntree->previews = NULL;
@@ -4084,10 +4084,10 @@ static void direct_link_text(FileData *fd, Text *text)
text->compiled = NULL;
#if 0
- if (text->flags & TXT_ISEXT) {
- BKE_text_reload(text);
- }
- /* else { */
+ if (text->flags & TXT_ISEXT) {
+ BKE_text_reload(text);
+ }
+ /* else { */
#endif
link_list(fd, &text->lines);
@@ -5071,7 +5071,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob)
* some leaked memory rather then crashing immediately
* while bad this _is_ an exceptional case - campbell */
#if 0
- BKE_pose_free(ob->pose);
+ BKE_pose_free(ob->pose);
#else
MEM_freeN(ob->pose);
#endif
@@ -5540,15 +5540,15 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob)
else if (md->type == eModifierType_Collision) {
CollisionModifierData *collmd = (CollisionModifierData *)md;
#if 0
- // TODO: CollisionModifier should use pointcache
- // + have proper reset events before enabling this
- collmd->x = newdataadr(fd, collmd->x);
- collmd->xnew = newdataadr(fd, collmd->xnew);
- collmd->mfaces = newdataadr(fd, collmd->mfaces);
-
- collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
- collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
- collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
+ // TODO: CollisionModifier should use pointcache
+ // + have proper reset events before enabling this
+ collmd->x = newdataadr(fd, collmd->x);
+ collmd->xnew = newdataadr(fd, collmd->xnew);
+ collmd->mfaces = newdataadr(fd, collmd->mfaces);
+
+ collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
+ collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
+ collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
#endif
collmd->x = NULL;
@@ -5752,16 +5752,66 @@ static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb)
direct_link_curvemapping(fd, hmd->curfalloff);
}
}
+ else if (md->type == eGpencilModifierType_Noise) {
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+
+ gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
+ if (gpmd->curve_intensity) {
+ direct_link_curvemapping(fd, gpmd->curve_intensity);
+ /* initialize the curve. Maybe this could be moved to modififer logic */
+ BKE_curvemapping_initialize(gpmd->curve_intensity);
+ }
+ }
else if (md->type == eGpencilModifierType_Thick) {
ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
gpmd->curve_thickness = newdataadr(fd, gpmd->curve_thickness);
if (gpmd->curve_thickness) {
direct_link_curvemapping(fd, gpmd->curve_thickness);
- /* initialize the curve. Maybe this could be moved to modififer logic */
BKE_curvemapping_initialize(gpmd->curve_thickness);
}
}
+ else if (md->type == eGpencilModifierType_Vertexcolor) {
+ VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md;
+ gpmd->colorband = newdataadr(fd, gpmd->colorband);
+ gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
+ if (gpmd->curve_intensity) {
+ direct_link_curvemapping(fd, gpmd->curve_intensity);
+ BKE_curvemapping_initialize(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Smooth) {
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
+ if (gpmd->curve_intensity) {
+ direct_link_curvemapping(fd, gpmd->curve_intensity);
+ BKE_curvemapping_initialize(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Color) {
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+ gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
+ if (gpmd->curve_intensity) {
+ direct_link_curvemapping(fd, gpmd->curve_intensity);
+ BKE_curvemapping_initialize(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Tint) {
+ TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
+ gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
+ if (gpmd->curve_intensity) {
+ direct_link_curvemapping(fd, gpmd->curve_intensity);
+ BKE_curvemapping_initialize(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Opacity) {
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+ gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
+ if (gpmd->curve_intensity) {
+ direct_link_curvemapping(fd, gpmd->curve_intensity);
+ BKE_curvemapping_initialize(gpmd->curve_intensity);
+ }
+ }
}
}
@@ -6333,6 +6383,15 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce)
if (sce->toolsettings->gp_paint) {
link_paint(fd, sce, &sce->toolsettings->gp_paint->paint);
}
+ if (sce->toolsettings->gp_vertexpaint) {
+ link_paint(fd, sce, &sce->toolsettings->gp_vertexpaint->paint);
+ }
+ if (sce->toolsettings->gp_sculptpaint) {
+ link_paint(fd, sce, &sce->toolsettings->gp_sculptpaint->paint);
+ }
+ if (sce->toolsettings->gp_weightpaint) {
+ link_paint(fd, sce, &sce->toolsettings->gp_weightpaint->paint);
+ }
if (sce->toolsettings->sculpt) {
sce->toolsettings->sculpt->gravity_object = newlibadr(
@@ -6615,6 +6674,9 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->wpaint);
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->uvsculpt);
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_paint);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_vertexpaint);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_sculptpaint);
+ direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_weightpaint);
direct_link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
@@ -6895,7 +6957,7 @@ static void lib_link_gpencil(FileData *fd, Main *UNUSED(bmain), bGPdata *gpd)
{
/* Relink all data-lock linked by GP data-lock */
/* Layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* Layer -> Parent References */
gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent);
}
@@ -6909,9 +6971,6 @@ static void lib_link_gpencil(FileData *fd, Main *UNUSED(bmain), bGPdata *gpd)
/* relinks grease-pencil data - used for direct_link and old file linkage */
static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
bGPDpalette *palette;
/* we must firstly have some grease-pencil data to link! */
@@ -6929,6 +6988,7 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_VERTEXMODE;
}
/* init stroke buffer */
@@ -6952,7 +7012,7 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
/* relink layers */
link_list(fd, &gpd->layers);
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* relink frames */
link_list(fd, &gpl->frames);
@@ -6960,24 +7020,24 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gpl->runtime.icon_id = 0;
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* Relink masks. */
+ link_list(fd, &gpl->mask_layers);
+
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* relink strokes (and their points) */
link_list(fd, &gpf->strokes);
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* relink stroke points array */
gps->points = newdataadr(fd, gps->points);
+ /* Relink geometry*/
+ gps->triangles = newdataadr(fd, gps->triangles);
/* relink weight data */
if (gps->dvert) {
gps->dvert = newdataadr(fd, gps->dvert);
direct_link_dverts(fd, gps->totpoints, gps->dvert);
}
-
- /* the triangulation is not saved, so need to be recalculated */
- gps->triangles = NULL;
- gps->tot_triangles = 0;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
}
}
}
@@ -7198,10 +7258,10 @@ static void direct_link_area(FileData *fd, ScrArea *area)
* so sacrifice a few old files for now to avoid crashes with new files!
* committed: r28002 */
#if 0
- sima->gpd = newdataadr(fd, sima->gpd);
- if (sima->gpd) {
- direct_link_gpencil(fd, sima->gpd);
- }
+ sima->gpd = newdataadr(fd, sima->gpd);
+ if (sima->gpd) {
+ direct_link_gpencil(fd, sima->gpd);
+ }
#endif
}
else if (sl->spacetype == SPACE_NODE) {
@@ -7232,10 +7292,10 @@ static void direct_link_area(FileData *fd, ScrArea *area)
* simple return NULL here (sergey)
*/
#if 0
- if (sseq->gpd) {
- sseq->gpd = newdataadr(fd, sseq->gpd);
- direct_link_gpencil(fd, sseq->gpd);
- }
+ if (sseq->gpd) {
+ sseq->gpd = newdataadr(fd, sseq->gpd);
+ direct_link_gpencil(fd, sseq->gpd);
+ }
#endif
sseq->scopes.reference_ibuf = NULL;
sseq->scopes.zebra_ibuf = NULL;
@@ -7906,11 +7966,11 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
sima->iuser.scene = NULL;
#if 0
- /* Those are allocated and freed by space code, no need to handle them here. */
- MEM_SAFE_FREE(sima->scopes.waveform_1);
- MEM_SAFE_FREE(sima->scopes.waveform_2);
- MEM_SAFE_FREE(sima->scopes.waveform_3);
- MEM_SAFE_FREE(sima->scopes.vecscope);
+ /* Those are allocated and freed by space code, no need to handle them here. */
+ MEM_SAFE_FREE(sima->scopes.waveform_1);
+ MEM_SAFE_FREE(sima->scopes.waveform_2);
+ MEM_SAFE_FREE(sima->scopes.waveform_3);
+ MEM_SAFE_FREE(sima->scopes.vecscope);
#endif
sima->scopes.ok = 0;
@@ -8281,8 +8341,8 @@ static void direct_link_speaker(FileData *fd, Speaker *spk)
direct_link_animdata(fd, spk->adt);
#if 0
- spk->sound = newdataadr(fd, spk->sound);
- direct_link_sound(fd, spk->sound);
+ spk->sound = newdataadr(fd, spk->sound);
+ direct_link_sound(fd, spk->sound);
#endif
}
@@ -8905,12 +8965,12 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
while (bhead && bhead->code == DATA) {
void *data;
#if 0
- /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
- short *sp = fd->filesdna->structs[bhead->SDNAnr];
- char *tmp = malloc(100);
- allocname = fd->filesdna->types[sp[0]];
- strcpy(tmp, allocname);
- data = read_struct(fd, bhead, tmp);
+ /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
+ short* sp = fd->filesdna->structs[bhead->SDNAnr];
+ char* tmp = malloc(100);
+ allocname = fd->filesdna->types[sp[0]];
+ strcpy(tmp, allocname);
+ data = read_struct(fd, bhead, tmp);
#else
data = read_struct(fd, bhead, allocname);
#endif
@@ -9309,11 +9369,6 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
user->walk_navigation.teleport_time = 0.2f; /* s */
}
- /* grease pencil multisamples */
- if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "short", "gpencil_multisamples")) {
- user->gpencil_multisamples = 4;
- }
-
/* tablet pressure threshold */
if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "float", "pressure_threshold_max")) {
user->pressure_threshold_max = 1.0f;
@@ -9722,7 +9777,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = read_libblock(fd, libmain, bhead, 0, true, NULL);
}
break;
- /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
+ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
case ID_SCRN:
bhead->code = ID_SCR;
/* pass on to default */
@@ -9877,7 +9932,7 @@ static BHead *find_previous_lib(FileData *fd, BHead *bhead)
static BHead *find_bhead(FileData *fd, void *old)
{
#if 0
- BHead *bhead;
+ BHead* bhead;
#endif
struct BHeadSort *bhs, bhs_s;
@@ -9897,11 +9952,11 @@ static BHead *find_bhead(FileData *fd, void *old)
}
#if 0
- for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
- if (bhead->old == old) {
- return bhead;
- }
- }
+ for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
+ if (bhead->old == old) {
+ return bhead;
+ }
+ }
#endif
return NULL;
@@ -10032,9 +10087,9 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
/* Commented because this can print way too much. */
#if 0
- if (G.debug & G_DEBUG) {
- printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
- }
+ if (G.debug & G_DEBUG) {
+ printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
+ }
#endif
}
@@ -10870,7 +10925,7 @@ static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *li
static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
{
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
expand_doit(fd, mainvar, gpl->parent);
}
@@ -11813,9 +11868,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* Does this library have any more linked data-blocks we need to read? */
if (has_linked_ids_to_read(mainptr)) {
#if 0
- printf("Reading linked data-blocks from %s (%s)\n",
- mainptr->curlib->id.name,
- mainptr->curlib->name);
+ printf("Reading linked data-blocks from %s (%s)\n",
+ mainptr->curlib->id.name,
+ mainptr->curlib->name);
#endif
/* Open file if it has not been done yet. */
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index df946168056..4500de7bbec 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1116,80 +1116,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 276, 4)) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
-
- if (ts->gp_sculpt.brush[0].size == 0) {
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- GP_Sculpt_Data *brush;
-
- brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
- brush->size = 25;
- brush->strength = 0.3f;
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE;
-
- brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS];
- brush->size = 25;
- brush->strength = 0.5f;
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_SCULPT_TYPE_GRAB];
- brush->size = 50;
- brush->strength = 0.3f;
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_SCULPT_TYPE_PUSH];
- brush->size = 25;
- brush->strength = 0.3f;
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_SCULPT_TYPE_TWIST];
- brush->size = 50;
- brush->strength = 0.3f; // XXX?
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_SCULPT_TYPE_PINCH];
- brush->size = 50;
- brush->strength = 0.5f; // XXX?
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE];
- brush->size = 25;
- brush->strength = 0.5f;
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
-
- brush = &gset->brush[GP_SCULPT_TYPE_CLONE];
- brush->size = 50;
- brush->strength = 1.0f;
- }
-
if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "gpencil_v3d_align")) {
-#if 0 /* XXX: Cannot do this, as we get random crashes... */
- if (scene->gpd) {
- bGPdata *gpd = scene->gpd;
-
- /* Copy over the settings stored in the GP data-block linked to the scene,
- * for minimal disruption. */
- ts->gpencil_v3d_align = 0;
-
- if (gpd->flag & GP_DATA_VIEWALIGN) {
- ts->gpencil_v3d_align |= GP_PROJECT_VIEWSPACE;
- }
- if (gpd->flag & GP_DATA_DEPTH_VIEW) {
- ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_VIEW;
- }
- if (gpd->flag & GP_DATA_DEPTH_STROKE) {
- ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_STROKE;
- }
-
- if (gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS) {
- ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_STROKE_ENDPOINTS;
- }
- }
- else {
- /* Default to cursor for all standard 3D views */
- ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
- }
-#endif
-
ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
ts->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
ts->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
@@ -1203,7 +1130,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Ensure that the datablock's onion-skinning toggle flag
* stays in sync with the status of the actual layers
*/
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl->flag & GP_LAYER_ONIONSKIN) {
enabled = true;
}
@@ -1424,22 +1351,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 277, 3)) {
/* ------- init of grease pencil initialization --------------- */
if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "*palcolor")) {
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- ToolSettings *ts = scene->toolsettings;
- /* initialize use position for sculpt brushes */
- ts->gp_sculpt.flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
-
- /* new strength sculpt brush */
- if (ts->gp_sculpt.brush[0].size >= 11) {
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- GP_Sculpt_Data *brush;
-
- brush = &gset->brush[GP_SCULPT_TYPE_STRENGTH];
- brush->size = 25;
- brush->strength = 0.5f;
- brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
- }
- }
/* Convert Grease Pencil to new palettes/brushes
* Loop all strokes and create the palette and all colors
*/
@@ -1447,7 +1358,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (BLI_listbase_is_empty(&gpd->palettes)) {
/* create palette */
bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette");
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* create color using layer name */
bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info);
if (palcolor != NULL) {
@@ -1475,8 +1386,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f);
/* flush relevant layer-settings to strokes */
- 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) {
/* set stroke to palette and force recalculation */
BLI_strncpy(gps->colorname, gpl->info, sizeof(gps->colorname));
gps->thickness = gpl->thickness;
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index e29c4f8658f..2035ee3590f 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -52,6 +52,7 @@
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_view3d_types.h"
#include "DNA_genfile.h"
#include "DNA_workspace_types.h"
@@ -63,6 +64,7 @@
#include "DNA_world_types.h"
#include "BKE_animsys.h"
+#include "BKE_brush.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -71,6 +73,8 @@
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idprop.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
@@ -573,7 +577,7 @@ static void do_versions_fix_annotations(bGPdata *gpd)
for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
/* fix layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* unlock/unhide layer */
gpl->flag &= ~GP_LAYER_LOCKED;
gpl->flag &= ~GP_LAYER_HIDE;
@@ -582,8 +586,8 @@ static void do_versions_fix_annotations(bGPdata *gpd)
/* disable tint */
gpl->tintcolor[3] = 0.0f;
- 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) {
if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) {
/* copy color settings */
copy_v4_v4(gpl->color, palcolor->color);
@@ -1057,6 +1061,48 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa
callback(gpmd->curfalloff);
}
}
+ else if (md->type == eGpencilModifierType_Noise) {
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ callback(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Vertexcolor) {
+ VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ callback(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Smooth) {
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ callback(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Color) {
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ callback(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Opacity) {
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ callback(gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Tint) {
+ TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ callback(gpmd->curve_intensity);
+ }
+ }
}
}
@@ -1554,7 +1600,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (gpd == NULL) {
continue;
}
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (STREQ(gpl->info, "RulerData3D")) {
gpl->flag |= GP_LAYER_IS_RULER;
break;
@@ -1588,6 +1634,34 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 282, 2)) {
+ /* Init all Vertex/Sculpt and Weight Paint brushes. */
+ Brush *brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2);
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+
+ BKE_brush_gpencil_vertex_presets(bmain, ts);
+ BKE_brush_gpencil_sculpt_presets(bmain, ts);
+ BKE_brush_gpencil_weight_presets(bmain, ts);
+
+ /* Ensure new Paint modes. */
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL);
+
+ /* Set default Draw brush. */
+ if (brush != NULL) {
+ Paint *paint = &ts->gp_paint->paint;
+ BKE_paint_brush_set(paint, brush);
+ /* Enable cursor by default. */
+ paint->flags |= PAINT_SHOW_BRUSH;
+ }
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, scene);
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -1774,36 +1848,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
#endif
{
- /* Grease pencil sculpt and paint cursors */
- if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "weighttype")) {
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- /* sculpt brushes */
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- if (gset) {
- gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
- }
- }
- }
-
- {
- 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_Sculpt_Data *gp_brush;
-
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- ToolSettings *ts = scene->toolsettings;
- /* sculpt brushes */
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
- gp_brush = &gset->brush[i];
- gp_brush->flag |= GP_SCULPT_FLAG_ENABLE_CURSOR;
- copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
- copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
- }
- }
- }
-
/* Init grease pencil edit line color */
if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "line_color[4]")) {
for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
@@ -1866,8 +1910,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
/* init grease pencil grids and paper */
- if (!DNA_struct_elem_find(
- fd->filesdna, "gp_paper_opacity", "float", "gpencil_paper_color[3]")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_color[3]")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *area = screen->areabase.first; area; area = area->next) {
for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
@@ -2621,7 +2664,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "short", "line_change")) {
for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
gpl->line_change = gpl->thickness;
if ((gpl->thickness < 1) || (gpl->thickness > 10)) {
gpl->thickness = 3;
@@ -2953,34 +2996,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* grease pencil main material show switches */
for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) {
if (mat->gp_style) {
- mat->gp_style->flag |= GP_STYLE_STROKE_SHOW;
- mat->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ mat->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ mat->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 33)) {
- /* Grease pencil reset sculpt brushes after struct rename */
- if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "weighttype")) {
- 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);
-
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- /* sculpt brushes */
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- if (gset) {
- for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
- GP_Sculpt_Data *gp_brush = &gset->brush[i];
- gp_brush->size = 30;
- 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);
- }
- }
- }
- }
if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "overscan")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
@@ -3214,7 +3236,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* init Annotations onion skin */
if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "int", "gstep")) {
for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f);
ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f);
}
@@ -3420,20 +3442,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Grease pencil target weight */
- if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "float", "weight")) {
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- /* sculpt brushes */
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- if (gset) {
- for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
- GP_Sculpt_Data *gp_brush = &gset->brush[i];
- gp_brush->weight = 1.0f;
- }
- }
- }
- }
-
/* Grease pencil cutter/select segment intersection threshold */
if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "float", "isect_threshold")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
@@ -3653,7 +3661,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (gpd->flag & GP_DATA_ANNOTATIONS) {
continue;
}
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* default channel color */
ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f);
}
@@ -3744,26 +3752,24 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
/* init grease pencil brush gradients */
- if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "gradient_f")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "hardeness")) {
for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
if (brush->gpencil_settings != NULL) {
BrushGpencilSettings *gp = brush->gpencil_settings;
- gp->gradient_f = 1.0f;
- gp->gradient_s[0] = 1.0f;
- gp->gradient_s[1] = 1.0f;
+ gp->hardeness = 1.0f;
+ copy_v2_fl(gp->aspect_ratio, 1.0f);
}
}
}
/* init grease pencil stroke gradients */
- if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "gradient_f")) {
+ if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "hardeness")) {
for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- 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) {
- gps->gradient_f = 1.0f;
- gps->gradient_s[0] = 1.0f;
- gps->gradient_s[1] = 1.0f;
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ gps->hardeness = 1.0f;
+ copy_v2_fl(gps->aspect_ratio, 1.0f);
}
}
}
@@ -4217,7 +4223,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Fix wrong 3D viewport copying causing corrupt pointers (T69974). */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
@@ -4507,6 +4512,272 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 283, 7)) {
+ /* Init default Grease Pencil Vertex paint mix factor for Viewport. */
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "View3DOverlay", "float", "gpencil_vertex_paint_opacity")) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.gpencil_vertex_paint_opacity = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Update Grease Pencil after drawing engine and code refactor.
+ * It uses the seed variable of Array modifier to avoid double patching for
+ * files created with a development version. */
+ if (!DNA_struct_elem_find(fd->filesdna, "ArrayGpencilModifierData", "int", "seed")) {
+ /* Init new Grease Pencil Paint tools. */
+ {
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->gpencil_settings != NULL) {
+ brush->gpencil_vertex_tool = brush->gpencil_settings->brush_type;
+ brush->gpencil_sculpt_tool = brush->gpencil_settings->brush_type;
+ brush->gpencil_weight_tool = brush->gpencil_settings->brush_type;
+ }
+ }
+
+ BKE_paint_toolslots_init_from_main(bmain);
+ }
+
+ LISTBASE_FOREACH (Material *, mat, &bmain->materials) {
+ MaterialGPencilStyle *gp_style = mat->gp_style;
+ if (gp_style == NULL) {
+ continue;
+ }
+ /* Fix Grease Pencil Material colors to Linear. */
+ srgb_to_linearrgb_v4(gp_style->stroke_rgba, gp_style->stroke_rgba);
+ srgb_to_linearrgb_v4(gp_style->fill_rgba, gp_style->fill_rgba);
+
+ /* Move old gradient variables to texture. */
+ if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) {
+ gp_style->texture_angle = gp_style->gradient_angle;
+ copy_v2_v2(gp_style->texture_scale, gp_style->gradient_scale);
+ copy_v2_v2(gp_style->texture_offset, gp_style->gradient_shift);
+ }
+ /* Set Checker material as Solid. This fill mode has been removed and replaced
+ * by textures. */
+ if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_CHECKER) {
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ }
+ /* Update Alpha channel for texture opacity. */
+ if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) {
+ gp_style->fill_rgba[3] *= gp_style->texture_opacity;
+ }
+ /* Stroke stencil mask to mix = 1. */
+ if (gp_style->flag & GP_MATERIAL_STROKE_PATTERN) {
+ gp_style->mix_stroke_factor = 1.0f;
+ gp_style->flag &= ~GP_MATERIAL_STROKE_PATTERN;
+ }
+ /* Mix disabled, set mix factor to 0. */
+ else if ((gp_style->flag & GP_MATERIAL_STROKE_TEX_MIX) == 0) {
+ gp_style->mix_stroke_factor = 0.0f;
+ }
+ }
+
+ /* Fix Grease Pencil VFX and modifiers. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type != OB_GPENCIL) {
+ continue;
+ }
+
+ /* VFX. */
+ LISTBASE_FOREACH (ShaderFxData *, fx, &ob->shader_fx) {
+ switch (fx->type) {
+ case eShaderFxType_Colorize: {
+ ColorizeShaderFxData *vfx = (ColorizeShaderFxData *)fx;
+ if (ELEM(vfx->mode, eShaderFxColorizeMode_GrayScale, eShaderFxColorizeMode_Sepia)) {
+ vfx->factor = 1.0f;
+ }
+ srgb_to_linearrgb_v4(vfx->low_color, vfx->low_color);
+ srgb_to_linearrgb_v4(vfx->high_color, vfx->high_color);
+ break;
+ }
+ case eShaderFxType_Pixel: {
+ PixelShaderFxData *vfx = (PixelShaderFxData *)fx;
+ srgb_to_linearrgb_v4(vfx->rgba, vfx->rgba);
+ break;
+ }
+ case eShaderFxType_Rim: {
+ RimShaderFxData *vfx = (RimShaderFxData *)fx;
+ srgb_to_linearrgb_v3_v3(vfx->rim_rgb, vfx->rim_rgb);
+ srgb_to_linearrgb_v3_v3(vfx->mask_rgb, vfx->mask_rgb);
+ break;
+ }
+ case eShaderFxType_Shadow: {
+ ShadowShaderFxData *vfx = (ShadowShaderFxData *)fx;
+ srgb_to_linearrgb_v4(vfx->shadow_rgba, vfx->shadow_rgba);
+ break;
+ }
+ case eShaderFxType_Glow: {
+ GlowShaderFxData *vfx = (GlowShaderFxData *)fx;
+ srgb_to_linearrgb_v3_v3(vfx->glow_color, vfx->glow_color);
+ vfx->glow_color[3] = 1.0f;
+ srgb_to_linearrgb_v3_v3(vfx->select_color, vfx->select_color);
+ vfx->blur[1] = vfx->blur[0];
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /* Modifiers. */
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ switch ((GpencilModifierType)md->type) {
+ case eGpencilModifierType_Array: {
+ ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
+ mmd->seed = 1;
+ if ((mmd->offset[0] != 0.0f) || (mmd->offset[1] != 0.0f) ||
+ (mmd->offset[2] != 0.0f)) {
+ mmd->flag |= GP_ARRAY_USE_OFFSET;
+ }
+ if ((mmd->shift[0] != 0.0f) || (mmd->shift[1] != 0.0f) || (mmd->shift[2] != 0.0f)) {
+ mmd->flag |= GP_ARRAY_USE_OFFSET;
+ }
+ if (mmd->object != NULL) {
+ mmd->flag |= GP_ARRAY_USE_OB_OFFSET;
+ }
+ break;
+ }
+ case eGpencilModifierType_Noise: {
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+ mmd->factor /= 25.0f;
+ mmd->factor_thickness = mmd->factor;
+ mmd->factor_strength = mmd->factor;
+ mmd->factor_uvs = mmd->factor;
+ mmd->noise_scale = (mmd->flag & GP_NOISE_FULL_STROKE) ? 0.0f : 1.0f;
+
+ if (mmd->curve_intensity == NULL) {
+ mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (mmd->curve_intensity) {
+ BKE_curvemapping_initialize(mmd->curve_intensity);
+ }
+ }
+ break;
+ }
+ case eGpencilModifierType_Tint: {
+ TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+ srgb_to_linearrgb_v3_v3(mmd->rgb, mmd->rgb);
+ if (mmd->curve_intensity == NULL) {
+ mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (mmd->curve_intensity) {
+ BKE_curvemapping_initialize(mmd->curve_intensity);
+ }
+ }
+ break;
+ }
+ case eGpencilModifierType_Smooth: {
+ SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md;
+ if (mmd->curve_intensity == NULL) {
+ mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (mmd->curve_intensity) {
+ BKE_curvemapping_initialize(mmd->curve_intensity);
+ }
+ }
+ break;
+ }
+ case eGpencilModifierType_Opacity: {
+ OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
+ if (mmd->curve_intensity == NULL) {
+ mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (mmd->curve_intensity) {
+ BKE_curvemapping_initialize(mmd->curve_intensity);
+ }
+ }
+ break;
+ }
+ case eGpencilModifierType_Color: {
+ ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
+ if (mmd->curve_intensity == NULL) {
+ mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (mmd->curve_intensity) {
+ BKE_curvemapping_initialize(mmd->curve_intensity);
+ }
+ }
+ break;
+ }
+ case eGpencilModifierType_Thick: {
+ if (!DNA_struct_elem_find(
+ fd->filesdna, "ThickGpencilModifierData", "float", "thickness_fac")) {
+ ThickGpencilModifierData *mmd = (ThickGpencilModifierData *)md;
+ mmd->thickness_fac = mmd->thickness;
+ }
+ break;
+ }
+ case eGpencilModifierType_Multiply: {
+ MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
+ mmd->fading_opacity = 1.0 - mmd->fading_opacity;
+ break;
+ }
+ case eGpencilModifierType_Subdiv: {
+ const short simple = (1 << 0);
+ SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+ if (mmd->flag & simple) {
+ mmd->flag &= ~simple;
+ mmd->type = GP_SUBDIV_SIMPLE;
+ }
+ break;
+ }
+ case eGpencilModifierType_Vertexcolor: {
+ VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md;
+ if (mmd->curve_intensity == NULL) {
+ mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (mmd->curve_intensity) {
+ BKE_curvemapping_initialize(mmd->curve_intensity);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ /* Fix Layers Colors and Vertex Colors to Linear.
+ * Also set lights to on for layers. */
+ LISTBASE_FOREACH (bGPdata *, gpd, &bmain->gpencils) {
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ continue;
+ }
+ /* Onion colors. */
+ srgb_to_linearrgb_v3_v3(gpd->gcolor_prev, gpd->gcolor_prev);
+ srgb_to_linearrgb_v3_v3(gpd->gcolor_next, gpd->gcolor_next);
+ /* Z-depth Offset. */
+ gpd->zdepth_offset = 0.150f;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ gpl->flag |= GP_LAYER_USE_LIGHTS;
+ srgb_to_linearrgb_v4(gpl->tintcolor, gpl->tintcolor);
+ gpl->vertex_paint_opacity = 1.0f;
+
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ /* Set initial opacity for fill color. */
+ gps->fill_opacity_fac = 1.0f;
+
+ /* Calc geometry data because in old versions this data was not saved. */
+ BKE_gpencil_stroke_geometry_update(gps);
+
+ srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill);
+ int i;
+ bGPDspoint *pt;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 00276f9c4a9..f0127330b1b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -44,10 +44,12 @@
#include "BKE_appdir.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
+#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
@@ -235,6 +237,13 @@ static void blo_update_defaults_screen(bScreen *screen,
/* Enable Sliders. */
saction->flag |= SACTION_SLIDERS;
}
+ else if (sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = sa->spacedata.first;
+ /* Set Material Color by default. */
+ v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
+ /* Enable Annotations. */
+ v3d->flag2 |= V3D_SHOW_ANNOTATION;
+ }
}
}
}
@@ -583,7 +592,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
}
- if (app_template && STREQ(app_template, "2D_Animation")) {
+ /* New grease pencil brushes and vertex paint setup. */
+ {
/* Update Grease Pencil brushes. */
Brush *brush;
@@ -617,8 +627,49 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
BKE_id_delete(bmain, brush);
}
+ /* Rename and fix materials. */
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ Material *ma = NULL;
+ rename_id_for_versioning(bmain, ID_MA, "Black", "Solid Stroke");
+ rename_id_for_versioning(bmain, ID_MA, "Red", "Squares Stroke");
+ rename_id_for_versioning(bmain, ID_MA, "Grey", "Solid Fill");
+ rename_id_for_versioning(bmain, ID_MA, "Black Dots", "Dots Stroke");
+
+ /* Dots Stroke. */
+ ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
+ }
+ ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
+
+ /* Squares Stroke. */
+ ma = BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_gpencil_material_add(bmain, "Squares Stroke");
+ }
+ ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE;
+
+ /* Change Solid Fill settings. */
+ ma = BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2);
+ if (ma != NULL) {
+ ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ }
+ }
+
/* Reset all grease pencil brushes. */
Scene *scene = bmain->scenes.first;
- BKE_brush_gpencil_presets(bmain, scene->toolsettings);
+ BKE_brush_gpencil_paint_presets(bmain, scene->toolsettings);
+
+ /* Ensure new Paint modes. */
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL);
+
+ /* Enable cursor. */
+ GpPaint *gp_paint = scene->toolsettings->gp_paint;
+ gp_paint->paint.flags |= PAINT_SHOW_BRUSH;
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, scene);
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 0c9363043ee..81df00ebdef 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1830,6 +1830,13 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase)
write_curvemapping(wd, gpmd->curve_thickness);
}
}
+ else if (md->type == eGpencilModifierType_Noise) {
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ write_curvemapping(wd, gpmd->curve_intensity);
+ }
+ }
else if (md->type == eGpencilModifierType_Hook) {
HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
@@ -1837,6 +1844,39 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase)
write_curvemapping(wd, gpmd->curfalloff);
}
}
+ else if (md->type == eGpencilModifierType_Vertexcolor) {
+ VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md;
+ if (gpmd->colorband) {
+ writestruct(wd, DATA, ColorBand, 1, gpmd->colorband);
+ }
+ if (gpmd->curve_intensity) {
+ write_curvemapping(wd, gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Smooth) {
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ if (gpmd->curve_intensity) {
+ write_curvemapping(wd, gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Color) {
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+ if (gpmd->curve_intensity) {
+ write_curvemapping(wd, gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Opacity) {
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+ if (gpmd->curve_intensity) {
+ write_curvemapping(wd, gpmd->curve_intensity);
+ }
+ }
+ else if (md->type == eGpencilModifierType_Tint) {
+ TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
+ if (gpmd->curve_intensity) {
+ write_curvemapping(wd, gpmd->curve_intensity);
+ }
+ }
}
}
@@ -2546,6 +2586,18 @@ static void write_scene(WriteData *wd, Scene *sce)
writestruct(wd, DATA, GpPaint, 1, tos->gp_paint);
write_paint(wd, &tos->gp_paint->paint);
}
+ if (tos->gp_vertexpaint) {
+ writestruct(wd, DATA, GpVertexPaint, 1, tos->gp_vertexpaint);
+ write_paint(wd, &tos->gp_vertexpaint->paint);
+ }
+ if (tos->gp_sculptpaint) {
+ writestruct(wd, DATA, GpSculptPaint, 1, tos->gp_sculptpaint);
+ write_paint(wd, &tos->gp_sculptpaint->paint);
+ }
+ if (tos->gp_weightpaint) {
+ writestruct(wd, DATA, GpWeightPaint, 1, tos->gp_weightpaint);
+ write_paint(wd, &tos->gp_weightpaint->paint);
+ }
/* write grease-pencil custom ipo curve to file */
if (tos->gp_interpolate.custom_ipo) {
write_curvemapping(wd, tos->gp_interpolate.custom_ipo);
@@ -2741,14 +2793,17 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd)
/* write grease-pencil layers to file */
writelist(wd, DATA, bGPDlayer, &gpd->layers);
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* Write mask list. */
+ writelist(wd, DATA, bGPDlayer_Mask, &gpl->mask_layers);
/* write this layer's frames to file */
writelist(wd, DATA, bGPDframe, &gpl->frames);
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* write strokes */
writelist(wd, DATA, bGPDstroke, &gpf->strokes);
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points);
+ writestruct(wd, DATA, bGPDtriangle, gps->tot_triangles, gps->triangles);
write_dverts(wd, gps->totpoints, gps->dvert);
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 687ee492c3b..01d84f6b5d8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -1310,7 +1310,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
obdata,
NodeType::GEOMETRY,
OperationCode::GEOMETRY_EVAL,
- function_bind(BKE_gpencil_eval_geometry, _1, (bGPdata *)obdata_cow));
+ function_bind(BKE_gpencil_frame_active_set, _1, (bGPdata *)obdata_cow));
op_node->set_as_entry();
break;
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 78e05a69819..6791125d1e9 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -2123,6 +2123,15 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
add_relation(material_key, geometry_key, "Material -> GP Data");
}
}
+
+ /* Layer parenting need react to the parent object transformation. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ if (gpl->parent != NULL) {
+ ComponentKey transform_key(&gpl->parent->id, NodeType::TRANSFORM);
+ ComponentKey gpd_geom_key(&gpd->id, NodeType::GEOMETRY);
+ add_relation(transform_key, gpd_geom_key, "GPencil Parent Layer");
+ }
+ }
break;
}
default:
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 95521ee9e47..1841f5f024f 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -43,6 +43,7 @@
#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_scene.h"
@@ -791,6 +792,9 @@ void update_id_after_copy(const Depsgraph *depsgraph,
}
BKE_pose_pchan_index_rebuild(object_cow->pose);
}
+ if (object_cow->type == OB_GPENCIL) {
+ BKE_gpencil_update_orig_pointers(object_orig, object_cow);
+ }
update_particles_after_copy(depsgraph, object_orig, object_cow);
update_modifiers_orig_pointers(object_orig, object_cow);
update_proxy_pointers_after_copy(depsgraph, object_orig, object_cow);
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 6d7b422c4fb..1f04739644e 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRC
intern/draw_cache_extract_mesh.c
intern/draw_cache_impl_curve.c
intern/draw_cache_impl_displist.c
+ intern/draw_cache_impl_gpencil.c
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.c
intern/draw_cache_impl_metaball.c
@@ -111,12 +112,13 @@ set(SRC
engines/workbench/workbench_studiolight.c
engines/workbench/workbench_volume.c
engines/external/external_engine.c
+ engines/gpencil/gpencil_antialiasing.c
engines/gpencil/gpencil_cache_utils.c
- engines/gpencil/gpencil_draw_cache_impl.c
- engines/gpencil/gpencil_draw_utils.c
+ engines/gpencil/gpencil_draw_data.c
engines/gpencil/gpencil_engine.c
engines/gpencil/gpencil_engine.h
engines/gpencil/gpencil_render.c
+ engines/gpencil/gpencil_shader.c
engines/gpencil/gpencil_shader_fx.c
engines/select/select_draw_utils.c
engines/select/select_engine.c
@@ -129,6 +131,7 @@ set(SRC
engines/overlay/overlay_engine.c
engines/overlay/overlay_extra.c
engines/overlay/overlay_facing.c
+ engines/overlay/overlay_gpencil.c
engines/overlay/overlay_grid.c
engines/overlay/overlay_image.c
engines/overlay/overlay_lattice.c
@@ -277,36 +280,16 @@ data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_fill_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_fill_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_geom.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_simple_mix_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_blend_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_point_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_point_geom.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_point_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_background_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_paper_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_geom.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_frag.glsl SRC)
-
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_vert.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_common_lib.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_layer_blend_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_mask_invert_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_vert.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_vfx_frag.glsl SRC)
data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC)
data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC)
@@ -340,6 +323,9 @@ data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC)
data_to_c_simple(engines/overlay/shaders/edit_curve_handle_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/edit_curve_point_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/edit_curve_wire_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_gpencil_canvas_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_gpencil_guide_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/edit_gpencil_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/edit_lattice_point_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/edit_lattice_wire_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/edit_mesh_common_lib.glsl SRC)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index c6aedd40afb..b4c23d5e57c 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -129,7 +129,6 @@ void DRW_draw_select_id(struct Depsgraph *depsgraph,
/* grease pencil render */
bool DRW_render_check_grease_pencil(struct Depsgraph *depsgraph);
void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
-void DRW_gpencil_freecache(struct Object *ob);
/* This is here because GPUViewport needs it */
struct DRWInstanceDataList *DRW_instance_data_list_create(void);
diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c
new file mode 100644
index 00000000000..e81073db4a5
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c
@@ -0,0 +1,169 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "DRW_render.h"
+
+#include "gpencil_engine.h"
+
+#include "smaa_textures.h"
+
+void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata)
+{
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_TextureList *txl = vedata->txl;
+ GPENCIL_PassList *psl = vedata->psl;
+ DRWShadingGroup *grp;
+
+ const float *size = DRW_viewport_size_get();
+ const float *sizeinv = DRW_viewport_invert_size_get();
+ float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]};
+
+ if (pd->simplify_antialias) {
+ /* No AA fallback. */
+ DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(2);
+ grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "blendTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
+ DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", false);
+ DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ return;
+ }
+
+ if (txl->smaa_search_tx == NULL) {
+ txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH,
+ SEARCHTEX_HEIGHT,
+ 0,
+ 2,
+ searchTexBytes,
+ GPU_R8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH,
+ AREATEX_HEIGHT,
+ 0,
+ 2,
+ areaTexBytes,
+ GPU_RG8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ GPU_texture_bind(txl->smaa_search_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_search_tx, true);
+ GPU_texture_unbind(txl->smaa_search_tx);
+
+ GPU_texture_bind(txl->smaa_area_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_area_tx, true);
+ GPU_texture_unbind(txl->smaa_area_tx);
+ }
+
+ {
+ pd->smaa_edge_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_RG8, &draw_engine_gpencil_type);
+ pd->smaa_weight_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_RGBA8, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(pd->smaa_edge_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(pd->smaa_weight_tx),
+ });
+ }
+
+ {
+ /* Stage 1: Edge detection. */
+ DRW_PASS_CREATE(psl->smaa_edge_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(0);
+ grp = DRW_shgroup_create(sh, psl->smaa_edge_ps);
+ DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 2: Blend Weight/Coord. */
+ DRW_PASS_CREATE(psl->smaa_weight_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(1);
+ grp = DRW_shgroup_create(sh, psl->smaa_weight_ps);
+ DRW_shgroup_uniform_texture(grp, "edgesTex", pd->smaa_edge_tx);
+ DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx);
+ DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 3: Resolve. */
+ DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(2);
+ grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "blendTex", pd->smaa_weight_tx);
+ DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
+ DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", true);
+ DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata)
+{
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_PassList *psl = vedata->psl;
+
+ if (!pd->simplify_antialias) {
+ GPU_framebuffer_bind(fbl->smaa_edge_fb);
+ DRW_draw_pass(psl->smaa_edge_ps);
+
+ GPU_framebuffer_bind(fbl->smaa_weight_fb);
+ DRW_draw_pass(psl->smaa_weight_ps);
+ }
+
+ GPU_framebuffer_bind(pd->scene_fb);
+ DRW_draw_pass(psl->smaa_resolve_ps);
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 5357d6167be..743171b09fb 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -33,324 +33,368 @@
#include "BKE_gpencil.h"
#include "BKE_object.h"
+#include "BLI_memblock.h"
+#include "BLI_link_utils.h"
+
#include "gpencil_engine.h"
#include "draw_cache_impl.h"
#include "DEG_depsgraph.h"
-/* verify if exist a non instanced version of the object */
-static bool gpencil_has_noninstanced_object(Object *ob_instance)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const ViewLayer *view_layer = draw_ctx->view_layer;
- Object *ob = NULL;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- ob = base->object;
- if (ob->type != OB_GPENCIL) {
- continue;
- }
- /* is not duplicated and the name is equals */
- if ((ob->base_flag & BASE_FROM_DUPLI) == 0) {
- if (STREQ(ob->id.name, ob_instance->id.name)) {
- return true;
- }
- }
- }
-
- return false;
-}
+/* -------------------------------------------------------------------- */
+/** \name Object
+ * \{ */
-/* add a gpencil object to cache to defer drawing */
-tGPencilObjectCache *gpencil_object_cache_add(tGPencilObjectCache *cache_array,
- Object *ob,
- int *gp_cache_size,
- int *gp_cache_used)
+GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- tGPencilObjectCache *cache_elem = NULL;
- RegionView3D *rv3d = draw_ctx->rv3d;
- View3D *v3d = draw_ctx->v3d;
- tGPencilObjectCache *p = NULL;
-
- /* By default a cache is created with one block with a predefined number of free slots,
- * if the size is not enough, the cache is reallocated adding a new block of free slots.
- * This is done in order to keep cache small. */
- if (*gp_cache_used + 1 > *gp_cache_size) {
- if ((*gp_cache_size == 0) || (cache_array == NULL)) {
- p = MEM_callocN(sizeof(struct tGPencilObjectCache) * GP_CACHE_BLOCK_SIZE,
- "tGPencilObjectCache");
- *gp_cache_size = GP_CACHE_BLOCK_SIZE;
- }
- else {
- *gp_cache_size += GP_CACHE_BLOCK_SIZE;
- p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size);
- }
- cache_array = p;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ GPENCIL_tObject *tgp_ob = BLI_memblock_alloc(pd->gp_object_pool);
+
+ tgp_ob->layers.first = tgp_ob->layers.last = NULL;
+ tgp_ob->vfx.first = tgp_ob->vfx.last = NULL;
+ tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->obmat[3]);
+ tgp_ob->is_drawmode3d = (gpd->draw_mode == GP_DRAWMODE_3D) || pd->draw_depth_only;
+ tgp_ob->object_scale = mat4_to_scale(ob->obmat);
+
+ /* Find the normal most likely to represent the gpObject. */
+ /* TODO: This does not work quite well if you use
+ * strokes not aligned with the object axes. Maybe we could try to
+ * compute the minimum axis of all strokes. But this would be more
+ * computationaly heavy and should go into the GPData evaluation. */
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ /* Convert bbox to matrix */
+ float mat[4][4], size[3], center[3];
+ BKE_boundbox_calc_size_aabb(bbox, size);
+ BKE_boundbox_calc_center_aabb(bbox, center);
+ unit_m4(mat);
+ copy_v3_v3(mat[3], center);
+ /* Avoid division by 0.0 later. */
+ add_v3_fl(size, 1e-8f);
+ rescale_m4(mat, size);
+ /* BBox space to World. */
+ mul_m4_m4m4(mat, ob->obmat, mat);
+ if (DRW_view_is_persp_get(NULL)) {
+ /* BBox center to camera vector. */
+ sub_v3_v3v3(tgp_ob->plane_normal, pd->camera_pos, mat[3]);
}
- /* zero out all pointers */
- cache_elem = &cache_array[*gp_cache_used];
- memset(cache_elem, 0, sizeof(*cache_elem));
-
- cache_elem->ob = ob;
- cache_elem->gpd = (bGPdata *)ob->data;
- cache_elem->name = BKE_id_to_unique_string_key(&ob->id);
-
- copy_v3_v3(cache_elem->loc, ob->obmat[3]);
- copy_m4_m4(cache_elem->obmat, ob->obmat);
- cache_elem->idx = *gp_cache_used;
-
- /* object is duplicated (particle) */
- if (ob->base_flag & BASE_FROM_DUPLI) {
- /* Check if the original object is not in the viewlayer
- * and cannot be managed as dupli. This is slower, but required to keep
- * the particle drawing FPS and display instanced objects in scene
- * without the original object */
- bool has_original = gpencil_has_noninstanced_object(ob);
- cache_elem->is_dup_ob = (has_original) ? ob->base_flag & BASE_FROM_DUPLI : false;
+ else {
+ copy_v3_v3(tgp_ob->plane_normal, pd->camera_z_axis);
+ }
+ /* World to BBox space. */
+ invert_m4(mat);
+ /* Normalize the vector in BBox space. */
+ mul_mat3_m4_v3(mat, tgp_ob->plane_normal);
+ normalize_v3(tgp_ob->plane_normal);
+
+ transpose_m4(mat);
+ /* mat is now a "normal" matrix which will transform
+ * BBox space normal to world space. */
+ mul_mat3_m4_v3(mat, tgp_ob->plane_normal);
+ normalize_v3(tgp_ob->plane_normal);
+
+ /* Define a matrix that will be used to render a triangle to merge the depth of the rendered
+ * gpencil object with the rest of the scene. */
+ unit_m4(tgp_ob->plane_mat);
+ copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal);
+ orthogonalize_m4(tgp_ob->plane_mat, 2);
+ mul_mat3_m4_v3(ob->obmat, size);
+ float radius = len_v3(size);
+ mul_m4_v3(ob->obmat, center);
+ rescale_m4(tgp_ob->plane_mat, (float[3]){radius, radius, radius});
+ copy_v3_v3(tgp_ob->plane_mat[3], center);
+
+ /* Add to corresponding list if is in front. */
+ if (ob->dtx & OB_DRAWXRAY) {
+ BLI_LINKS_APPEND(&pd->tobjects_infront, tgp_ob);
}
else {
- cache_elem->is_dup_ob = false;
+ BLI_LINKS_APPEND(&pd->tobjects, tgp_ob);
}
- cache_elem->scale = mat4_to_scale(ob->obmat);
+ return tgp_ob;
+}
- /* save FXs */
- cache_elem->pixfactor = cache_elem->gpd->pixfactor;
- cache_elem->shader_fx = ob->shader_fx;
+#define SORT_IMPL_LINKTYPE GPENCIL_tObject
- /* save wire mode (object mode is always primary option) */
- if (ob->dt == OB_WIRE) {
- cache_elem->shading_type[0] = (int)OB_WIRE;
+#define SORT_IMPL_FUNC gpencil_tobject_sort_fn_r
+#include "../../blenlib/intern/list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+
+#undef SORT_IMPL_LINKTYPE
+
+static int gpencil_tobject_dist_sort(const void *a, const void *b)
+{
+ const GPENCIL_tObject *ob_a = (const GPENCIL_tObject *)a;
+ const GPENCIL_tObject *ob_b = (const GPENCIL_tObject *)b;
+ /* Reminder, camera_z is negative in front of the camera. */
+ if (ob_a->camera_z > ob_b->camera_z) {
+ return 1;
}
- else {
- if (v3d) {
- cache_elem->shading_type[0] = (int)v3d->shading.type;
- }
+ else if (ob_a->camera_z < ob_b->camera_z) {
+ return -1;
}
-
- /* shgrp array */
- cache_elem->tot_layers = 0;
- int totgpl = BLI_listbase_count(&cache_elem->gpd->layers);
- if (totgpl > 0) {
- cache_elem->shgrp_array = MEM_callocN(sizeof(tGPencilObjectCache_shgrp) * totgpl, __func__);
+ else {
+ return 0;
}
+}
- /* calculate zdepth from point of view */
- float zdepth = 0.0;
- if (rv3d) {
- if (rv3d->is_persp) {
- zdepth = ED_view3d_calc_zfac(rv3d, ob->obmat[3], NULL);
- }
- else {
- zdepth = -dot_v3v3(rv3d->viewinv[2], ob->obmat[3]);
+void gpencil_object_cache_sort(GPENCIL_PrivateData *pd)
+{
+ /* Sort object by distance to the camera. */
+ if (pd->tobjects.first) {
+ pd->tobjects.first = gpencil_tobject_sort_fn_r(pd->tobjects.first, gpencil_tobject_dist_sort);
+ /* Relink last pointer. */
+ while (pd->tobjects.last->next) {
+ pd->tobjects.last = pd->tobjects.last->next;
}
}
- else {
- /* In render mode, rv3d is not available, so use the distance to camera.
- * The real distance is not important, but the relative distance to the camera plane
- * in order to sort by z_depth of the objects
- */
- float vn[3] = {0.0f, 0.0f, -1.0f}; /* always face down */
- float plane_cam[4];
- struct Object *camera = draw_ctx->scene->camera;
- if (camera) {
- mul_m4_v3(camera->obmat, vn);
- normalize_v3(vn);
- plane_from_point_normal_v3(plane_cam, camera->loc, vn);
- zdepth = dist_squared_to_plane_v3(ob->obmat[3], plane_cam);
+ if (pd->tobjects_infront.first) {
+ pd->tobjects_infront.first = gpencil_tobject_sort_fn_r(pd->tobjects_infront.first,
+ gpencil_tobject_dist_sort);
+ /* Relink last pointer. */
+ while (pd->tobjects_infront.last->next) {
+ pd->tobjects_infront.last = pd->tobjects_infront.last->next;
}
}
- cache_elem->zdepth = zdepth;
- /* increase slots used in cache */
- (*gp_cache_used)++;
-
- return cache_array;
-}
-/* add a shading group to the cache to create later */
-GpencilBatchGroup *gpencil_group_cache_add(GpencilBatchGroup *cache_array,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps,
- const short type,
- const bool onion,
- const int vertex_idx,
- int *grp_size,
- int *grp_used)
-{
- GpencilBatchGroup *cache_elem = NULL;
- GpencilBatchGroup *p = NULL;
-
- /* By default a cache is created with one block with a predefined number of free slots,
- * if the size is not enough, the cache is reallocated adding a new block of free slots.
- * This is done in order to keep cache small. */
- if (*grp_used + 1 > *grp_size) {
- if ((*grp_size == 0) || (cache_array == NULL)) {
- p = MEM_callocN(sizeof(struct GpencilBatchGroup) * GPENCIL_GROUPS_BLOCK_SIZE,
- "GpencilBatchGroup");
- *grp_size = GPENCIL_GROUPS_BLOCK_SIZE;
+ /* Join both lists, adding infront. */
+ if (pd->tobjects_infront.first != NULL) {
+ if (pd->tobjects.last != NULL) {
+ pd->tobjects.last->next = pd->tobjects_infront.first;
+ pd->tobjects.last = pd->tobjects_infront.last;
}
else {
- *grp_size += GPENCIL_GROUPS_BLOCK_SIZE;
- p = MEM_recallocN(cache_array, sizeof(struct GpencilBatchGroup) * *grp_size);
+ /* Only in front objects. */
+ pd->tobjects.first = pd->tobjects_infront.first;
+ pd->tobjects.last = pd->tobjects_infront.last;
}
- cache_array = p;
}
- /* zero out all data */
- cache_elem = &cache_array[*grp_used];
- memset(cache_elem, 0, sizeof(*cache_elem));
-
- cache_elem->gpl = gpl;
- cache_elem->gpf = gpf;
- cache_elem->gps = gps;
- cache_elem->type = type;
- cache_elem->onion = onion;
- cache_elem->vertex_idx = vertex_idx;
+}
- /* increase slots used in cache */
- (*grp_used)++;
+/** \} */
- return cache_array;
-}
+/* -------------------------------------------------------------------- */
+/** \name Layer
+ * \{ */
-/* get current cache data */
-static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
+static float gpencil_layer_final_opacity_get(const GPENCIL_PrivateData *pd,
+ const Object *ob,
+ const bGPDlayer *gpl)
{
- return ob->runtime.gpencil_cache;
+ const bool is_obact = ((pd->obact) && (pd->obact == ob));
+ const bool is_fade = ((pd->fade_layer_opacity > -1.0f) && (is_obact) &&
+ ((gpl->flag & GP_LAYER_ACTIVE) == 0));
+
+ /* Defines layer opacity. For active object depends of layer opacity factor, and
+ * for no active object, depends if the fade grease pencil objects option is enabled. */
+ if (!pd->is_render) {
+ if (is_obact && is_fade) {
+ return gpl->opacity * pd->fade_layer_opacity;
+ }
+ else if (!is_obact && (pd->fade_gp_object_opacity > -1.0f)) {
+ return gpl->opacity * pd->fade_gp_object_opacity;
+ }
+ }
+ return gpl->opacity;
}
-/* verify if cache is valid */
-static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
+static void gpencil_layer_final_tint_and_alpha_get(const GPENCIL_PrivateData *pd,
+ const bGPdata *gpd,
+ const bGPDlayer *gpl,
+ const bGPDframe *gpf,
+ float r_tint[4],
+ float *r_alpha)
{
- bool valid = true;
- if (cache == NULL) {
- return false;
- }
-
- cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
- if (cfra != cache->cache_frame) {
- valid = false;
- }
- else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
- valid = false;
- }
- else if (gpd->flag & GP_DATA_PYTHON_UPDATED) {
- gpd->flag &= ~GP_DATA_PYTHON_UPDATED;
- valid = false;
+ const bool use_onion = (gpf != NULL) && (gpf->runtime.onion_id != 0.0f);
+ if (use_onion) {
+ const bool use_onion_custom_col = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
+ const bool use_onion_fade = (gpd->onion_flag & GP_ONION_FADE) != 0;
+ const bool use_next_col = gpf->runtime.onion_id > 0.0f;
+
+ const float *onion_col_custom = (use_onion_custom_col) ?
+ (use_next_col ? gpd->gcolor_next : gpd->gcolor_prev) :
+ U.gpencil_new_layer_col;
+
+ copy_v4_fl4(r_tint, UNPACK3(onion_col_custom), 1.0f);
+
+ *r_alpha = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f;
+ *r_alpha *= gpd->onion_factor;
+ *r_alpha = (gpd->onion_factor > 0.0f) ? clamp_f(*r_alpha, 0.1f, 1.0f) :
+ clamp_f(*r_alpha, 0.01f, 1.0f);
}
- else if (cache->is_editmode) {
- valid = false;
- }
- else if (cache->is_dirty) {
- valid = false;
+ else {
+ copy_v4_v4(r_tint, gpl->tintcolor);
+ if (GPENCIL_SIMPLIFY_TINT(pd->scene)) {
+ r_tint[3] = 0.0f;
+ }
+ *r_alpha = 1.0f;
}
- return valid;
+ *r_alpha *= pd->xray_alpha;
}
-/* cache init */
-static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
+GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
+ const Object *ob,
+ const bGPDlayer *gpl,
+ const bGPDframe *gpf,
+ GPENCIL_tObject *tgp_ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
- GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+ const bool is_in_front = (ob->dtx & OB_DRAWXRAY);
+ const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
+ const bool overide_vertcol = (pd->v3d_color_type != -1);
+ const bool is_vert_col_mode = (pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) ||
+ GPENCIL_VERTEX_MODE(gpd) || pd->is_render;
+ bool is_masked = (gpl->flag & GP_LAYER_USE_MASK) && !BLI_listbase_is_empty(&gpl->mask_layers);
+
+ float vert_col_opacity = (overide_vertcol) ? (is_vert_col_mode ? 1.0f : 0.0f) :
+ gpl->vertex_paint_opacity;
+ /* Negate thickness sign to tag that strokes are in screen space.
+ * Convert to world units (by default, 1 meter = 2000 px). */
+ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR);
+ float layer_opacity = gpencil_layer_final_opacity_get(pd, ob, gpl);
+ float layer_tint[4];
+ float layer_alpha;
+ gpencil_layer_final_tint_and_alpha_get(pd, gpd, gpl, gpf, layer_tint, &layer_alpha);
+
+ /* Create the new layer descriptor. */
+ GPENCIL_tLayer *tgp_layer = BLI_memblock_alloc(pd->gp_layer_pool);
+ BLI_LINKS_APPEND(&tgp_ob->layers, tgp_layer);
+ tgp_layer->layer_id = BLI_findindex(&gpd->layers, gpl);
+ tgp_layer->mask_bits = NULL;
+ tgp_layer->mask_invert_bits = NULL;
+ tgp_layer->blend_ps = NULL;
+
+ /* Masking: Go through mask list and extract valid masks in a bitmap. */
+ if (is_masked) {
+ bool valid_mask = false;
+ /* Warning: only GP_MAX_MASKBITS amount of bits.
+ * TODO(fclem) Find a better system without any limitation. */
+ tgp_layer->mask_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
+ tgp_layer->mask_invert_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
+ BLI_bitmap_set_all(tgp_layer->mask_bits, false, GP_MAX_MASKBITS);
+
+ LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
+ bGPDlayer *gpl_mask = BKE_gpencil_layer_named_get(gpd, mask->name);
+ if (gpl_mask && (gpl_mask != gpl) && ((gpl_mask->flag & GP_LAYER_HIDE) == 0) &&
+ ((mask->flag & GP_MASK_HIDE) == 0)) {
+ int index = BLI_findindex(&gpd->layers, gpl_mask);
+ if (index < GP_MAX_MASKBITS) {
+ const bool invert = (mask->flag & GP_MASK_INVERT) != 0;
+ BLI_BITMAP_SET(tgp_layer->mask_bits, index, true);
+ BLI_BITMAP_SET(tgp_layer->mask_invert_bits, index, invert);
+ valid_mask = true;
+ }
+ }
+ }
- if (!cache) {
- cache = MEM_callocN(sizeof(*cache), __func__);
- ob->runtime.gpencil_cache = cache;
- }
- else {
- memset(cache, 0, sizeof(*cache));
+ if (valid_mask) {
+ pd->use_mask_fb = true;
+ }
+ else {
+ tgp_layer->mask_bits = NULL;
+ }
+ is_masked = valid_mask;
}
- cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
-
- cache->is_dirty = true;
+ /* Blending: Force blending for masked layer. */
+ if (is_masked || (gpl->blend_mode != eGplBlendMode_Regular) || (layer_opacity < 1.0f)) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL;
+ switch (gpl->blend_mode) {
+ case eGplBlendMode_Regular:
+ state |= DRW_STATE_BLEND_ALPHA_PREMUL;
+ break;
+ case eGplBlendMode_Add:
+ state |= DRW_STATE_BLEND_ADD_FULL;
+ break;
+ case eGplBlendMode_Subtract:
+ state |= DRW_STATE_BLEND_SUB;
+ break;
+ case eGplBlendMode_Multiply:
+ case eGplBlendMode_Divide:
+ case eGplBlendMode_Overlay:
+ state |= DRW_STATE_BLEND_MUL;
+ break;
+ }
- cache->cache_frame = cfra;
+ if (ELEM(gpl->blend_mode, eGplBlendMode_Subtract, eGplBlendMode_Overlay)) {
+ /* For these effect to propagate, we need a signed floating point buffer. */
+ pd->use_signed_fb = true;
+ }
- return cache;
-}
+ tgp_layer->blend_ps = DRW_pass_create("GPencil Blend Layer", state);
+
+ GPUShader *sh = GPENCIL_shader_layer_blend_get();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, tgp_layer->blend_ps);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", gpl->blend_mode);
+ DRW_shgroup_uniform_float_copy(grp, "blendOpacity", layer_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_layer_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_layer_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "maskBuf", (is_masked) ? &pd->mask_tx : &pd->dummy_tx);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (gpl->blend_mode == eGplBlendMode_Overlay) {
+ /* We cannot do custom blending on MultiTarget framebuffers.
+ * Workaround by doing 2 passes. */
+ grp = DRW_shgroup_create(sh, tgp_layer->blend_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", 999);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
-/* clear cache */
-static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
-{
- if (!cache) {
- return;
+ pd->use_layer_fb = true;
}
- GPU_BATCH_DISCARD_SAFE(cache->b_stroke.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_point.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_fill.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_edit.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_edlin.batch);
-
- MEM_SAFE_FREE(cache->b_stroke.batch);
- MEM_SAFE_FREE(cache->b_point.batch);
- MEM_SAFE_FREE(cache->b_fill.batch);
- MEM_SAFE_FREE(cache->b_edit.batch);
- MEM_SAFE_FREE(cache->b_edlin.batch);
-
- /* internal format data */
- MEM_SAFE_FREE(cache->b_stroke.format);
- MEM_SAFE_FREE(cache->b_point.format);
- MEM_SAFE_FREE(cache->b_fill.format);
- MEM_SAFE_FREE(cache->b_edit.format);
- MEM_SAFE_FREE(cache->b_edlin.format);
-
- MEM_SAFE_FREE(cache->grp_cache);
- cache->grp_size = 0;
- cache->grp_used = 0;
-}
-
-/* get cache */
-GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
-{
- bGPdata *gpd = (bGPdata *)ob->data;
-
- GpencilBatchCache *cache = gpencil_batch_get_element(ob);
- if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
- if (cache) {
- gpencil_batch_cache_clear(cache);
- }
- return gpencil_batch_cache_init(ob, cfra);
- }
- else {
- return cache;
+ /* Geometry pass */
+ {
+ GPUTexture *depth_tex = (is_in_front) ? pd->dummy_tx : pd->scene_depth_tx;
+ GPUTexture **mask_tex = (is_masked) ? &pd->mask_tx : &pd->dummy_tx;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND_ALPHA_PREMUL;
+ /* For 2D mode, we render all strokes with uniform depth (increasing with stroke id). */
+ state |= tgp_ob->is_drawmode3d ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_GREATER;
+ /* Always write stencil. Only used as optimization for blending. */
+ state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
+
+ tgp_layer->geom_ps = DRW_pass_create("GPencil Layer", state);
+
+ struct GPUShader *sh = GPENCIL_shader_geometry_get();
+ DRWShadingGroup *grp = tgp_layer->base_shgrp = DRW_shgroup_create(sh, tgp_layer->geom_ps);
+
+ DRW_shgroup_uniform_texture_persistent(grp, "gpSceneDepthTexture", depth_tex);
+ DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex);
+ DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal);
+ DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", tgp_ob->is_drawmode3d);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessScale", tgp_ob->object_scale);
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get());
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get());
+ DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
+ DRW_shgroup_uniform_float_copy(grp, "vertexColorOpacity", vert_col_opacity);
+ DRW_shgroup_uniform_vec4_copy(grp, "layerTint", layer_tint);
+ DRW_shgroup_uniform_float_copy(grp, "layerOpacity", layer_alpha);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
}
-}
-/* set cache as dirty */
-void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
-{
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ return tgp_layer;
}
-/* free batch cache */
-void DRW_gpencil_batch_cache_free(bGPdata *UNUSED(gpd))
+GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number)
{
- return;
-}
-
-/* wrapper to clear cache */
-void DRW_gpencil_freecache(struct Object *ob)
-{
- if ((ob) && (ob->type == OB_GPENCIL)) {
- gpencil_batch_cache_clear(ob->runtime.gpencil_cache);
- MEM_SAFE_FREE(ob->runtime.gpencil_cache);
- bGPdata *gpd = (bGPdata *)ob->data;
- if (gpd) {
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ if (number >= 0) {
+ GPENCIL_tLayer *layer = tgp_ob->layers.first;
+ while (layer != NULL) {
+ if (layer->layer_id == number) {
+ return layer;
+ }
+ layer = layer->next;
}
}
-
- /* clear all frames evaluated data */
- 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);
- }
-
- ob->runtime.gpencil_tot_layers = 0;
- MEM_SAFE_FREE(ob->runtime.gpencil_evaluated_frames);
+ return NULL;
}
+
+/** \} */
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
deleted file mode 100644
index a2016b9c1e6..00000000000
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ /dev/null
@@ -1,1021 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008, Blender Foundation
- * This is a new part of Blender
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "BLI_polyfill_2d.h"
-#include "BLI_math_color.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-
-#include "BKE_deform.h"
-#include "BKE_gpencil.h"
-
-#include "DRW_render.h"
-
-#include "ED_gpencil.h"
-#include "ED_view3d.h"
-
-#include "UI_resources.h"
-
-#include "gpencil_engine.h"
-
-/* Helper to add stroke point to vbo */
-static void gpencil_set_stroke_point(GPUVertBuf *vbo,
- const bGPDspoint *pt,
- int idx,
- uint pos_id,
- uint color_id,
- uint thickness_id,
- uint uvdata_id,
- short thickness,
- const float ink[4])
-{
-
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- float col[4];
- ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
-
- GPU_vertbuf_attr_set(vbo, color_id, idx, col);
-
- /* transfer both values using the same shader variable */
- float uvdata[2] = {pt->uv_fac, pt->uv_rot};
- GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
-
- /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */
- float thick = max_ff(pt->pressure * thickness, 1.0f);
- GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick);
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
-}
-
-/* Helper to add buffer_stroke point to vbo */
-static void gpencil_set_buffer_stroke_point(GPUVertBuf *vbo,
- const bGPDspoint *pt,
- int idx,
- uint pos_id,
- uint color_id,
- uint thickness_id,
- uint uvdata_id,
- uint prev_pos_id,
- const float ref_pt[3],
- short thickness,
- const float ink[4])
-{
-
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- float col[4];
- ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
-
- GPU_vertbuf_attr_set(vbo, color_id, idx, col);
-
- /* transfer both values using the same shader variable */
- float uvdata[2] = {pt->uv_fac, pt->uv_rot};
- GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
-
- /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */
- float thick = max_ff(pt->pressure * thickness, 1.0f);
- GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick);
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
- /* reference point to follow drawing path */
- GPU_vertbuf_attr_set(vbo, prev_pos_id, idx, ref_pt);
-}
-
-/* Helper to add a new fill point and texture coordinates to vertex buffer */
-static void gpencil_set_fill_point(GPUVertBuf *vbo,
- int idx,
- bGPDspoint *pt,
- const float fcolor[4],
- const float uv[2],
- uint pos_id,
- uint color_id,
- uint text_id)
-{
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
- GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
- GPU_vertbuf_attr_set(vbo, text_id, idx, uv);
-}
-
-static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex)
-{
- if (be->vbo->vertex_alloc <= be->vbo_len + totvertex) {
- uint newsize = be->vbo->vertex_alloc +
- (((totvertex / GPENCIL_VBO_BLOCK_SIZE) + 1) * GPENCIL_VBO_BLOCK_SIZE);
- GPU_vertbuf_data_resize(be->vbo, newsize);
- }
-}
-
-static void gpencil_elem_format_ensure(GpencilBatchCacheElem *be)
-{
- if (be->format == NULL) {
- be->format = MEM_callocN(sizeof(GPUVertFormat), __func__);
- }
-}
-
-/* create batch geometry data for points stroke shader */
-void gpencil_get_point_geom(GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- short thickness,
- const float ink[4],
- const int alignment_mode)
-{
- int totvertex = gps->totpoints;
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->thickness_id = GPU_vertformat_attr_add(
- be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- be->uvdata_id = GPU_vertformat_attr_add(
- be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- be->prev_pos_id = GPU_vertformat_attr_add(
- be->format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, totvertex);
-
- /* draw stroke curve */
- const bGPDspoint *pt = gps->points;
- float alpha;
- float col[4];
-
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* set point */
- alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
-
- float thick = max_ff(pt->pressure * thickness, 1.0f);
-
- GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col);
- GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick);
-
- /* transfer both values using the same shader variable */
- float uvdata[2] = {pt->uv_fac, pt->uv_rot};
- GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
-
- GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
-
- /* use previous point to determine stroke direction */
- bGPDspoint *pt2 = NULL;
- float fpt[3];
- if (alignment_mode != GP_STYLE_FOLLOW_PATH) {
- /* add small offset to get a vector */
- copy_v3_v3(fpt, &pt->x);
- fpt[0] += 0.00001f;
- fpt[1] += 0.00001f;
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
- }
- else {
- if (i == 0) {
- if (gps->totpoints > 1) {
- /* extrapolate a point before first point */
- pt2 = &gps->points[1];
- interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f);
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
- }
- else {
- /* add small offset to get a vector */
- copy_v3_v3(fpt, &pt->x);
- fpt[0] += 0.00001f;
- fpt[1] += 0.00001f;
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
- }
- }
- else {
- pt2 = &gps->points[i - 1];
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x);
- }
- }
- be->vbo_len++;
- }
-}
-
-/* create batch geometry data for stroke shader */
-void gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- short thickness,
- const float ink[4])
-{
- bGPDspoint *points = gps->points;
- int totpoints = gps->totpoints;
- /* if cyclic needs more vertex */
- int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0;
- int totvertex = totpoints + cyclic_add + 2;
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->thickness_id = GPU_vertformat_attr_add(
- be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- be->uvdata_id = GPU_vertformat_attr_add(
- be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, totvertex);
-
- /* draw stroke curve */
- const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints; i++, pt++) {
- /* first point for adjacency (not drawn) */
- if (i == 0) {
- if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
- gpencil_set_stroke_point(be->vbo,
- &points[totpoints - 1],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
- else {
- gpencil_set_stroke_point(be->vbo,
- &points[1],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
- }
- /* set point */
- gpencil_set_stroke_point(be->vbo,
- pt,
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
-
- if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
- /* draw line to first point to complete the cycle */
- gpencil_set_stroke_point(be->vbo,
- &points[0],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- /* now add adjacency point (not drawn) */
- gpencil_set_stroke_point(be->vbo,
- &points[1],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
- /* last adjacency point (not drawn) */
- else {
- gpencil_set_stroke_point(be->vbo,
- &points[totpoints - 2],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
-}
-
-/* create batch geometry data for stroke shader */
-void gpencil_get_fill_geom(struct GpencilBatchCacheElem *be,
- Object *ob,
- bGPDstroke *gps,
- const float color[4])
-{
- BLI_assert(gps->totpoints >= 3);
-
- /* Calculate triangles cache for filling area (must be done only after changes) */
- if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (gps->tot_triangles == 0) ||
- (gps->triangles == NULL)) {
- BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps);
- }
-
- BLI_assert(gps->tot_triangles >= 1);
- int totvertex = gps->tot_triangles * 3;
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->uvdata_id = GPU_vertformat_attr_add(
- be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, totvertex);
-
- /* Draw all triangles for filling the polygon (cache must be calculated before) */
- bGPDtriangle *stroke_triangle = gps->triangles;
- for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- gpencil_set_fill_point(be->vbo,
- be->vbo_len,
- &gps->points[stroke_triangle->verts[j]],
- color,
- stroke_triangle->uv[j],
- be->pos_id,
- be->color_id,
- be->uvdata_id);
- be->vbo_len++;
- }
- }
-}
-
-/* create batch geometry data for current buffer stroke shader */
-GPUBatch *gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ARegion *region = draw_ctx->region;
- RegionView3D *rv3d = draw_ctx->rv3d;
- ToolSettings *ts = scene->toolsettings;
- Object *ob = draw_ctx->obact;
-
- tGPspoint *points = gpd->runtime.sbuffer;
- int totpoints = gpd->runtime.sbuffer_used;
- /* if cyclic needs more vertex */
- int cyclic_add = (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC) ? 1 : 0;
- int totvertex = totpoints + cyclic_add + 2;
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id, thickness_id, uvdata_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, totvertex);
-
- /* draw stroke curve */
- const tGPspoint *tpt = points;
- bGPDspoint pt, pt2, pt3;
- int idx = 0;
-
- /* get origin to reproject point */
- float origin[3];
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
-
- for (int i = 0; i < totpoints; i++, tpt++) {
- ED_gpencil_tpoint_to_point(region, origin, tpt, &pt);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
-
- /* first point for adjacency (not drawn) */
- if (i == 0) {
- if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
- ED_gpencil_tpoint_to_point(region, origin, &points[totpoints - 1], &pt2);
- gpencil_set_stroke_point(vbo,
- &pt2,
- idx,
- pos_id,
- color_id,
- thickness_id,
- uvdata_id,
- thickness,
- gpd->runtime.scolor);
- idx++;
- }
- else {
- ED_gpencil_tpoint_to_point(region, origin, &points[1], &pt2);
- gpencil_set_stroke_point(vbo,
- &pt2,
- idx,
- pos_id,
- color_id,
- thickness_id,
- uvdata_id,
- thickness,
- gpd->runtime.scolor);
- idx++;
- }
- }
-
- /* set point */
- gpencil_set_stroke_point(
- vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- }
-
- /* last adjacency point (not drawn) */
- if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
- /* draw line to first point to complete the cycle */
- ED_gpencil_tpoint_to_point(region, origin, &points[0], &pt2);
- gpencil_set_stroke_point(
- vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- /* now add adjacency point (not drawn) */
- ED_gpencil_tpoint_to_point(region, origin, &points[1], &pt3);
- gpencil_set_stroke_point(
- vbo, &pt3, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- }
- /* last adjacency point (not drawn) */
- else {
- ED_gpencil_tpoint_to_point(region, origin, &points[totpoints - 2], &pt2);
- gpencil_set_stroke_point(
- vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- }
-
- return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* create batch geometry data for current buffer point shader */
-GPUBatch *gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ARegion *region = draw_ctx->region;
- RegionView3D *rv3d = draw_ctx->rv3d;
- ToolSettings *ts = scene->toolsettings;
- Object *ob = draw_ctx->obact;
-
- tGPspoint *points = gpd->runtime.sbuffer;
- int totpoints = gpd->runtime.sbuffer_used;
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id, thickness_id, uvdata_id, prev_pos_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- prev_pos_id = GPU_vertformat_attr_add(&format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, totpoints);
-
- /* draw stroke curve */
- const tGPspoint *tpt = points;
- bGPDspoint pt;
- int idx = 0;
-
- /* get origin to reproject point */
- float origin[3];
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
-
- for (int i = 0; i < totpoints; i++, tpt++) {
- ED_gpencil_tpoint_to_point(region, origin, tpt, &pt);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
-
- /* use previous point to determine stroke direction (drawing path) */
- bGPDspoint pt2;
- float ref_pt[3];
-
- if (i == 0) {
- if (totpoints > 1) {
- /* extrapolate a point before first point */
- tGPspoint *tpt2 = &points[1];
- ED_gpencil_tpoint_to_point(region, origin, tpt2, &pt2);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
-
- interp_v3_v3v3(ref_pt, &pt2.x, &pt.x, 1.5f);
- }
- else {
- copy_v3_v3(ref_pt, &pt.x);
- }
- }
- else {
- tGPspoint *tpt2 = &points[i - 1];
- ED_gpencil_tpoint_to_point(region, origin, tpt2, &pt2);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
-
- copy_v3_v3(ref_pt, &pt2.x);
- }
-
- /* set point */
- gpencil_set_buffer_stroke_point(vbo,
- &pt,
- idx,
- pos_id,
- color_id,
- thickness_id,
- uvdata_id,
- prev_pos_id,
- ref_pt,
- thickness,
- gpd->runtime.scolor);
- idx++;
- }
-
- return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* create batch geometry data for current buffer control point shader */
-GPUBatch *gpencil_get_buffer_ctrlpoint_geom(bGPdata *gpd)
-{
- bGPDcontrolpoint *cps = gpd->runtime.cp_points;
- int totpoints = gpd->runtime.tot_cp_points;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->gp_sculpt.guide.use_guide) {
- totpoints++;
- }
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id, size_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, totpoints);
-
- int idx = 0;
- for (int i = 0; i < gpd->runtime.tot_cp_points; i++) {
- bGPDcontrolpoint *cp = &cps[i];
-
- GPU_vertbuf_attr_set(vbo, color_id, idx, cp->color);
-
- /* scale size */
- float size = cp->size * 0.8f;
- GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &cp->x);
- idx++;
- }
-
- if (ts->gp_sculpt.guide.use_guide) {
- float size = 10 * 0.8f;
- float color[4];
- float position[3];
- if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) {
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- copy_v3_v3(position, ts->gp_sculpt.guide.location);
- }
- else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT &&
- ts->gp_sculpt.guide.reference_object != NULL) {
- UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
- copy_v3_v3(position, ts->gp_sculpt.guide.reference_object->loc);
- }
- else {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- copy_v3_v3(position, scene->cursor.location);
- }
- GPU_vertbuf_attr_set(vbo, pos_id, idx, position);
- GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
- GPU_vertbuf_attr_set(vbo, color_id, idx, color);
- }
-
- return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* create batch geometry data for current buffer fill shader */
-GPUBatch *gpencil_get_buffer_fill_geom(bGPdata *gpd)
-{
- if (gpd == NULL) {
- return NULL;
- }
-
- const tGPspoint *points = gpd->runtime.sbuffer;
- int totpoints = gpd->runtime.sbuffer_used;
- if (totpoints < 3) {
- return NULL;
- }
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ARegion *region = draw_ctx->region;
- ToolSettings *ts = scene->toolsettings;
- Object *ob = draw_ctx->obact;
-
- /* get origin to reproject point */
- float origin[3];
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
-
- int tot_triangles = totpoints - 2;
- /* allocate memory for temporary areas */
- uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__);
- float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__);
-
- /* Convert points to array and triangulate
- * Here a cache is not used because while drawing the information changes all the time, so the
- * cache would be recalculated constantly, so it is better to do direct calculation for each
- * function call
- */
- for (int i = 0; i < totpoints; i++) {
- const tGPspoint *pt = &points[i];
- points2d[i][0] = pt->x;
- points2d[i][1] = pt->y;
- }
- BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles);
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
-
- /* draw triangulation data */
- if (tot_triangles > 0) {
- GPU_vertbuf_data_alloc(vbo, tot_triangles * 3);
-
- const tGPspoint *tpt;
- bGPDspoint pt;
-
- int idx = 0;
- for (int i = 0; i < tot_triangles; i++) {
- for (int j = 0; j < 3; j++) {
- tpt = &points[tmp_triangles[i][j]];
- ED_gpencil_tpoint_to_point(region, origin, tpt, &pt);
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x);
- GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill);
- idx++;
- }
- }
- }
-
- /* clear memory */
- if (tmp_triangles) {
- MEM_freeN(tmp_triangles);
- }
- if (points2d) {
- MEM_freeN(points2d);
- }
-
- return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* Draw selected verts for strokes being edited */
-void gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- float alpha,
- short dflag)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Object *ob = draw_ctx->obact;
- bGPdata *gpd = ob->data;
- const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- int vgindex = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, vgindex)) {
- vgindex = -1;
- }
-
- /* Get size of verts:
- * - The selected state needs to be larger than the unselected state so that
- * they stand out more.
- * - We use the theme setting for size of the unselected verts
- */
- float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
- float vsize;
- if ((int)bsize > 8) {
- vsize = 10.0f;
- bsize = 8.0f;
- }
- else {
- vsize = bsize + 2;
- }
-
- /* for now, we assume that the base color of the points is not too close to the real color */
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
-
- float unselectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor);
- unselectColor[3] = alpha;
-
- float linecolor[4];
- copy_v4_v4(linecolor, gpd->line_color);
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->thickness_id = GPU_vertformat_attr_add(
- be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, gps->totpoints);
-
- /* Draw start and end point differently if enabled stroke direction hint */
- bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
-
- /* Draw all the stroke points (selected or not) */
- bGPDspoint *pt = gps->points;
- MDeformVert *dvert = gps->dvert;
-
- float fcolor[4];
- float fsize = 0;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* weight paint */
- if (is_weight_paint) {
- float weight = (dvert && dvert->dw && (vgindex > -1)) ?
- BKE_defvert_find_weight(dvert, vgindex) :
- 0.0f;
- float hue = 2.0f * (1.0f - weight) / 3.0f;
- hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
- selectColor[3] = 1.0f;
- copy_v4_v4(fcolor, selectColor);
- fsize = vsize;
- }
- else {
- if (show_direction_hint && i == 0) {
- /* start point in green bigger */
- ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f);
- fsize = vsize + 4;
- }
- else if (show_direction_hint && (i == gps->totpoints - 1)) {
- /* end point in red smaller */
- ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f);
- fsize = vsize + 1;
- }
- else if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
- ARRAY_SET_ITEMS(fcolor, linecolor[0], linecolor[1], linecolor[2], selectColor[3]);
- mul_v4_fl(fcolor, 0.9f);
- copy_v4_v4(fcolor, fcolor);
- fsize = vsize * 0.8f;
- }
- else if (pt->flag & GP_SPOINT_SELECT) {
- copy_v4_v4(fcolor, selectColor);
- fsize = vsize;
- }
- else {
- copy_v4_v4(fcolor, unselectColor);
- fsize = bsize;
- }
- }
-
- GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
- GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize);
- GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
- be->vbo_len++;
- if (gps->dvert != NULL) {
- dvert++;
- }
- }
-}
-
-/* Draw lines for strokes being edited */
-void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- float alpha,
- const bool hide_select)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Object *ob = draw_ctx->obact;
- bGPdata *gpd = ob->data;
- const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
-
- int vgindex = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, vgindex)) {
- vgindex = -1;
- }
-
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
- float linecolor[4];
- copy_v4_v4(linecolor, gpd->line_color);
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, gps->totpoints);
-
- /* Draw all the stroke lines (selected or not) */
- bGPDspoint *pt = gps->points;
- MDeformVert *dvert = gps->dvert;
-
- float fcolor[4];
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* weight paint */
- if (is_weight_paint) {
- float weight = (dvert && dvert->dw && (vgindex > -1)) ?
- BKE_defvert_find_weight(dvert, vgindex) :
- 0.0f;
- float hue = 2.0f * (1.0f - weight) / 3.0f;
- hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
- selectColor[3] = 1.0f;
- copy_v4_v4(fcolor, selectColor);
- }
- else {
- if ((pt->flag & GP_SPOINT_SELECT) && (!hide_select)) {
- copy_v4_v4(fcolor, selectColor);
- }
- else {
- copy_v4_v4(fcolor, linecolor);
- }
- }
-
- GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
- GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
- be->vbo_len++;
-
- if (gps->dvert != NULL) {
- dvert++;
- }
- }
-}
-
-static void set_grid_point(GPUVertBuf *vbo,
- int idx,
- const float col_grid[4],
- uint pos_id,
- uint color_id,
- float v1,
- float v2,
- const int axis)
-{
- GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid);
-
- float pos[3];
- /* Set the grid in the selected axis */
- switch (axis) {
- case GP_LOCKAXIS_X: {
- ARRAY_SET_ITEMS(pos, 0.0f, v1, v2);
- break;
- }
- case GP_LOCKAXIS_Y: {
- ARRAY_SET_ITEMS(pos, v1, 0.0f, v2);
- break;
- }
- case GP_LOCKAXIS_Z:
- default: /* view aligned */
- {
- ARRAY_SET_ITEMS(pos, v1, v2, 0.0f);
- break;
- }
- }
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, pos);
-}
-
-/* Draw grid lines */
-GPUBatch *gpencil_get_grid(Object *ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
- View3D *v3d = draw_ctx->v3d;
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool do_center = (gpd->grid.lines <= 0) ? false : true;
-
- float col_grid[4];
-
- /* verify we have something to draw and valid values */
- if (gpd->grid.scale[0] == 0.0f) {
- gpd->grid.scale[0] = 1.0f;
- }
- if (gpd->grid.scale[1] == 0.0f) {
- gpd->grid.scale[1] = 1.0f;
- }
-
- if (v3d->overlay.gpencil_grid_opacity < 0.1f) {
- v3d->overlay.gpencil_grid_opacity = 0.1f;
- }
-
- /* set color */
- copy_v3_v3(col_grid, gpd->grid.color);
- col_grid[3] = v3d->overlay.gpencil_grid_opacity;
-
- const int axis = ts->gp_sculpt.lock_axis;
-
- const char *grid_unit = NULL;
- const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
- const float grid_w = gpd->grid.scale[0] * ED_scene_grid_scale(scene, &grid_unit);
- const float grid_h = gpd->grid.scale[1] * ED_scene_grid_scale(scene, &grid_unit);
- const float space_w = (grid_w / gridlines);
- const float space_h = (grid_h / gridlines);
- const float offset[2] = {gpd->grid.offset[0], gpd->grid.offset[1]};
-
- const uint vertex_len = 2 * (gridlines * 4 + 2);
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, vertex_len);
-
- int idx = 0;
-
- for (int a = 1; a <= gridlines; a++) {
- const float line_w = a * space_w;
- const float line_h = a * space_h;
-
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], -line_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], -line_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], +line_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], +line_h + offset[1], axis);
- idx++;
-
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], -grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], +grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], -grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], +grid_h + offset[1], axis);
- idx++;
- }
- /* center lines */
- if (do_center) {
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], 0.0f + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], 0.0f + offset[1], axis);
- idx++;
-
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], -grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], +grid_h + offset[1], axis);
- idx++;
- }
- return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
new file mode 100644
index 00000000000..77baadfc83a
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -0,0 +1,502 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_light_types.h"
+
+#include "BKE_image.h"
+
+#include "BLI_hash.h"
+#include "BLI_math_color.h"
+#include "BLI_memblock.h"
+
+#include "GPU_uniformbuffer.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "gpencil_engine.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Material
+ * \{ */
+
+static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_PrivateData *pd)
+{
+ GPENCIL_MaterialPool *matpool = BLI_memblock_alloc(pd->gp_material_pool);
+ matpool->next = NULL;
+ matpool->used_count = 0;
+ if (matpool->ubo == NULL) {
+ matpool->ubo = GPU_uniformbuffer_create(sizeof(matpool->mat_data), NULL, NULL);
+ }
+ pd->last_material_pool = matpool;
+ return matpool;
+}
+
+static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_premult)
+{
+ ImBuf *ibuf;
+ ImageUser iuser = {NULL};
+ struct GPUTexture *gpu_tex = NULL;
+ void *lock;
+
+ iuser.ok = true;
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf != NULL && ibuf->rect != NULL) {
+ gpu_tex = GPU_texture_from_blender(image, &iuser, ibuf, GL_TEXTURE_2D);
+ *r_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
+ }
+ BKE_image_release_ibuf(image, ibuf, lock);
+
+ return gpu_tex;
+}
+
+static void gpencil_uv_transform_get(const float ofs[2],
+ const float scale[2],
+ const float rotation,
+ float r_uvmat[3][2])
+{
+ /* OPTI this could use 3x2 matrices and reduce the number of operations drastically. */
+ float mat[4][4];
+ unit_m4(mat);
+ /* Offset to center. */
+ translate_m4(mat, 0.5f, 0.5f, 0.0f);
+ /* Reversed order. */
+ rescale_m4(mat, (float[3]){1.0f / scale[0], 1.0f / scale[1], 0.0});
+ rotate_m4(mat, 'Z', -rotation);
+ translate_m4(mat, ofs[0], ofs[1], 0.0f);
+ /* Convert to 3x2 */
+ copy_v2_v2(r_uvmat[0], mat[0]);
+ copy_v2_v2(r_uvmat[1], mat[1]);
+ copy_v2_v2(r_uvmat[2], mat[3]);
+}
+
+#define HSV_SATURATION 0.5
+#define HSV_VALUE 0.8
+
+static void gpencil_object_random_color_get(const Object *ob, float r_color[3])
+{
+ /* Duplicated from workbench_material.c */
+ uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
+ if (ob->id.lib) {
+ hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
+ }
+ float hue = BLI_hash_int_01(hash);
+ float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
+ hsv_to_rgb_v(hsv, r_color);
+}
+
+static void gpencil_shade_color(float color[3])
+{
+ /* This is scene refered color, not gamma corrected and not per perceptual.
+ * So we lower the threshold a bit. (1.0 / 3.0) */
+ if (color[0] + color[1] + color[2] > 1.1) {
+ add_v3_fl(color, -0.25f);
+ }
+ else {
+ add_v3_fl(color, 0.15f);
+ }
+ CLAMP3(color, 0.0f, 1.0f);
+}
+
+/* Apply all overrides from the solid viewport mode to the GPencil material. */
+static MaterialGPencilStyle *gpencil_viewport_material_overrides(GPENCIL_PrivateData *pd,
+ Object *ob,
+ int color_type,
+ MaterialGPencilStyle *gp_style)
+{
+ static MaterialGPencilStyle gp_style_tmp;
+
+ switch (color_type) {
+ case V3D_SHADING_MATERIAL_COLOR:
+ copy_v4_v4(gp_style_tmp.stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gp_style_tmp.fill_rgba, gp_style->fill_rgba);
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ break;
+ case V3D_SHADING_TEXTURE_COLOR:
+ memcpy(&gp_style_tmp, gp_style, sizeof(*gp_style));
+ gp_style = &gp_style_tmp;
+ if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) {
+ copy_v4_fl(gp_style->stroke_rgba, 1.0f);
+ gp_style->mix_stroke_factor = 0.0f;
+ }
+
+ if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) {
+ copy_v4_fl(gp_style->fill_rgba, 1.0f);
+ gp_style->mix_factor = 0.0f;
+ }
+ else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) {
+ /* gp_style->fill_rgba is needed for correct gradient. */
+ gp_style->mix_factor = 0.0f;
+ }
+ break;
+ case V3D_SHADING_RANDOM_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ gpencil_object_random_color_get(ob, gp_style->fill_rgba);
+ gp_style->fill_rgba[3] = 1.0f;
+ copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba);
+ gpencil_shade_color(gp_style->stroke_rgba);
+ break;
+ case V3D_SHADING_SINGLE_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ copy_v3_v3(gp_style->fill_rgba, pd->v3d_single_color);
+ gp_style->fill_rgba[3] = 1.0f;
+ copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba);
+ gpencil_shade_color(gp_style->stroke_rgba);
+ break;
+ case V3D_SHADING_OBJECT_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ copy_v4_v4(gp_style->fill_rgba, ob->color);
+ copy_v4_v4(gp_style->stroke_rgba, ob->color);
+ gpencil_shade_color(gp_style->stroke_rgba);
+ break;
+ case V3D_SHADING_VERTEX_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ copy_v4_fl(gp_style->fill_rgba, 1.0f);
+ copy_v4_fl(gp_style->stroke_rgba, 1.0f);
+ break;
+ default:
+ break;
+ }
+ return gp_style;
+}
+
+/**
+ * Creates a linked list of material pool containing all materials assigned for a given object.
+ * We merge the material pools together if object does not contain a huge amount of materials.
+ * Also return an offset to the first material of the object in the ubo.
+ **/
+GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs)
+{
+ GPENCIL_MaterialPool *matpool = pd->last_material_pool;
+
+ int mat_len = max_ii(1, ob->totcol);
+
+ bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GP_MATERIAL_BUFFER_LEN);
+
+ if (reuse_matpool) {
+ /* Share the matpool with other objects. Return offset to first material. */
+ *ofs = matpool->used_count;
+ }
+ else {
+ matpool = gpencil_material_pool_add(pd);
+ *ofs = 0;
+ }
+
+ /* Force vertex color in solid mode with vertex paint mode. Same behavior as meshes. */
+ bGPdata *gpd = (bGPdata *)ob->data;
+ int color_type = (pd->v3d_color_type != -1 && GPENCIL_VERTEX_MODE(gpd)) ?
+ V3D_SHADING_VERTEX_COLOR :
+ pd->v3d_color_type;
+
+ GPENCIL_MaterialPool *pool = matpool;
+ for (int i = 0; i < mat_len; i++) {
+ if ((i > 0) && (pool->used_count == GP_MATERIAL_BUFFER_LEN)) {
+ pool->next = gpencil_material_pool_add(pd);
+ pool = pool->next;
+ }
+ int mat_id = pool->used_count++;
+
+ gpMaterial *mat_data = &pool->mat_data[mat_id];
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, i + 1);
+
+ if (gp_style->mode == GP_MATERIAL_MODE_LINE) {
+ mat_data->flag = 0;
+ }
+ else {
+ switch (gp_style->alignment_mode) {
+ case GP_MATERIAL_FOLLOW_PATH:
+ mat_data->flag = GP_STROKE_ALIGNMENT_STROKE;
+ break;
+ case GP_MATERIAL_FOLLOW_OBJ:
+ mat_data->flag = GP_STROKE_ALIGNMENT_OBJECT;
+ break;
+ case GP_MATERIAL_FOLLOW_FIXED:
+ default:
+ mat_data->flag = GP_STROKE_ALIGNMENT_FIXED;
+ break;
+ }
+
+ if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
+ mat_data->flag |= GP_STROKE_DOTS;
+ }
+ }
+
+ if ((gp_style->mode != GP_MATERIAL_MODE_LINE) ||
+ (gp_style->flag & GP_MATERIAL_DISABLE_STENCIL)) {
+ mat_data->flag |= GP_STROKE_OVERLAP;
+ }
+
+ gp_style = gpencil_viewport_material_overrides(pd, ob, color_type, gp_style);
+
+ /* Stroke Style */
+ if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) {
+ bool premul;
+ pool->tex_stroke[mat_id] = gpencil_image_texture_get(gp_style->sima, &premul);
+ mat_data->flag |= pool->tex_stroke[mat_id] ? GP_STROKE_TEXTURE_USE : 0;
+ mat_data->flag |= premul ? GP_STROKE_TEXTURE_PREMUL : 0;
+ copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba);
+ mat_data->stroke_texture_mix = 1.0f - gp_style->mix_stroke_factor;
+ mat_data->stroke_u_scale = 500.0f / gp_style->texture_pixsize;
+ }
+ else /* if (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_SOLID) */ {
+ pool->tex_stroke[mat_id] = NULL;
+ mat_data->flag &= ~GP_STROKE_TEXTURE_USE;
+ copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba);
+ mat_data->stroke_texture_mix = 0.0f;
+ }
+
+ /* Fill Style */
+ if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) {
+ bool use_clip = (gp_style->flag & GP_MATERIAL_TEX_CLAMP) != 0;
+ bool premul;
+ pool->tex_fill[mat_id] = gpencil_image_texture_get(gp_style->ima, &premul);
+ mat_data->flag |= pool->tex_fill[mat_id] ? GP_FILL_TEXTURE_USE : 0;
+ mat_data->flag |= premul ? GP_FILL_TEXTURE_PREMUL : 0;
+ mat_data->flag |= use_clip ? GP_FILL_TEXTURE_CLIP : 0;
+ gpencil_uv_transform_get(gp_style->texture_offset,
+ gp_style->texture_scale,
+ gp_style->texture_angle,
+ mat_data->fill_uv_transform);
+ copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
+ mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
+ }
+ else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) {
+ bool use_radial = (gp_style->gradient_type == GP_MATERIAL_GRADIENT_RADIAL);
+ pool->tex_fill[mat_id] = NULL;
+ mat_data->flag |= GP_FILL_GRADIENT_USE;
+ mat_data->flag |= use_radial ? GP_FILL_GRADIENT_RADIAL : 0;
+ gpencil_uv_transform_get(gp_style->texture_offset,
+ gp_style->texture_scale,
+ gp_style->texture_angle,
+ mat_data->fill_uv_transform);
+ copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
+ copy_v4_v4(mat_data->fill_mix_color, gp_style->mix_rgba);
+ mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
+ if (gp_style->flag & GP_MATERIAL_FLIP_FILL) {
+ swap_v4_v4(mat_data->fill_color, mat_data->fill_mix_color);
+ }
+ }
+ else /* if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) */ {
+ pool->tex_fill[mat_id] = NULL;
+ copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
+ mat_data->fill_texture_mix = 0.0f;
+ }
+ }
+
+ return matpool;
+}
+
+void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
+ int mat_id,
+ GPUTexture **r_tex_stroke,
+ GPUTexture **r_tex_fill,
+ GPUUniformBuffer **r_ubo_mat)
+{
+ GPENCIL_MaterialPool *matpool = first_pool;
+ int pool_id = mat_id / GP_MATERIAL_BUFFER_LEN;
+ for (int i = 0; i < pool_id; i++) {
+ matpool = matpool->next;
+ }
+ mat_id = mat_id % GP_MATERIAL_BUFFER_LEN;
+ *r_ubo_mat = matpool->ubo;
+ if (r_tex_fill) {
+ *r_tex_fill = matpool->tex_fill[mat_id];
+ }
+ if (r_tex_stroke) {
+ *r_tex_stroke = matpool->tex_stroke[mat_id];
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lights
+ * \{ */
+
+GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd)
+{
+ GPENCIL_LightPool *lightpool = BLI_memblock_alloc(pd->gp_light_pool);
+ lightpool->light_used = 0;
+ /* Tag light list end. */
+ lightpool->light_data[0].color[0] = -1.0;
+ if (lightpool->ubo == NULL) {
+ lightpool->ubo = GPU_uniformbuffer_create(sizeof(lightpool->light_data), NULL, NULL);
+ }
+ pd->last_light_pool = lightpool;
+ return lightpool;
+}
+
+void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3])
+{
+ if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) {
+ return;
+ }
+
+ gpLight *gp_light = &lightpool->light_data[lightpool->light_used];
+ gp_light->type = GP_LIGHT_TYPE_AMBIENT;
+ copy_v3_v3(gp_light->color, color);
+ lightpool->light_used++;
+
+ if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) {
+ /* Tag light list end. */
+ gp_light[1].color[0] = -1.0f;
+ }
+}
+
+static float light_power_get(const Light *la)
+{
+ if (la->type == LA_AREA) {
+ return 1.0f / (4.0f * M_PI);
+ }
+ else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
+ return 1.0f / (4.0f * M_PI * M_PI);
+ }
+ else {
+ return 1.0f / M_PI;
+ }
+}
+
+void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob)
+{
+ Light *la = (Light *)ob->data;
+
+ if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) {
+ return;
+ }
+
+ gpLight *gp_light = &lightpool->light_data[lightpool->light_used];
+ float(*mat)[4] = (float(*)[4])gp_light->right;
+
+ if (la->type == LA_SPOT) {
+ copy_m4_m4(mat, ob->imat);
+ gp_light->type = GP_LIGHT_TYPE_SPOT;
+ gp_light->spotsize = cosf(la->spotsize * 0.5f);
+ gp_light->spotblend = (1.0f - gp_light->spotsize) * la->spotblend;
+ }
+ else if (la->type == LA_AREA) {
+ /* Simulate area lights using a spot light. */
+ normalize_m4_m4(mat, ob->obmat);
+ invert_m4(mat);
+ gp_light->type = GP_LIGHT_TYPE_SPOT;
+ gp_light->spotsize = cosf(M_PI * 0.5f);
+ gp_light->spotblend = (1.0f - gp_light->spotsize) * 1.0f;
+ }
+ else if (la->type == LA_SUN) {
+ normalize_v3_v3(gp_light->forward, ob->obmat[2]);
+ gp_light->type = GP_LIGHT_TYPE_SUN;
+ }
+ else {
+ gp_light->type = GP_LIGHT_TYPE_POINT;
+ }
+ copy_v4_v4(gp_light->position, ob->obmat[3]);
+ copy_v3_v3(gp_light->color, &la->r);
+ mul_v3_fl(gp_light->color, la->energy * light_power_get(la));
+
+ lightpool->light_used++;
+
+ if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) {
+ /* Tag light list end. */
+ gp_light[1].color[0] = -1.0f;
+ }
+}
+
+/**
+ * Creates a single pool containing all lights assigned (light linked) for a given object.
+ **/
+GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *UNUSED(ob))
+{
+ GPENCIL_LightPool *lightpool = pd->last_light_pool;
+
+ if (lightpool == NULL) {
+ lightpool = gpencil_light_pool_add(pd);
+ }
+ /* TODO(fclem) Light linking. */
+ // gpencil_light_pool_populate(lightpool, ob);
+
+ return lightpool;
+}
+
+void gpencil_material_pool_free(void *storage)
+{
+ GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage;
+ DRW_UBO_FREE_SAFE(matpool->ubo);
+}
+
+void gpencil_light_pool_free(void *storage)
+{
+ GPENCIL_LightPool *lightpool = (GPENCIL_LightPool *)storage;
+ DRW_UBO_FREE_SAFE(lightpool->ubo);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Layer Data
+ * \{ */
+
+static void gpencil_view_layer_data_free(void *storage)
+{
+ GPENCIL_ViewLayerData *vldata = (GPENCIL_ViewLayerData *)storage;
+
+ BLI_memblock_destroy(vldata->gp_light_pool, gpencil_light_pool_free);
+ BLI_memblock_destroy(vldata->gp_material_pool, gpencil_material_pool_free);
+ BLI_memblock_destroy(vldata->gp_maskbit_pool, NULL);
+ BLI_memblock_destroy(vldata->gp_object_pool, NULL);
+ BLI_memblock_destroy(vldata->gp_layer_pool, NULL);
+ BLI_memblock_destroy(vldata->gp_vfx_pool, NULL);
+}
+
+GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void)
+{
+ GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure(
+ &draw_engine_gpencil_type, gpencil_view_layer_data_free);
+
+ /* NOTE(fclem) Putting this stuff in viewlayer means it is shared by all viewports.
+ * For now it is ok, but in the future, it could become a problem if we implement
+ * the caching system. */
+ if (*vldata == NULL) {
+ *vldata = MEM_callocN(sizeof(**vldata), "GPENCIL_ViewLayerData");
+
+ (*vldata)->gp_light_pool = BLI_memblock_create(sizeof(GPENCIL_LightPool));
+ (*vldata)->gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool));
+ (*vldata)->gp_maskbit_pool = BLI_memblock_create(BLI_BITMAP_SIZE(GP_MAX_MASKBITS));
+ (*vldata)->gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject));
+ (*vldata)->gp_layer_pool = BLI_memblock_create(sizeof(GPENCIL_tLayer));
+ (*vldata)->gp_vfx_pool = BLI_memblock_create(sizeof(GPENCIL_tVfx));
+ }
+
+ return *vldata;
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
deleted file mode 100644
index d44aa5764b1..00000000000
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ /dev/null
@@ -1,2071 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2017, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_render.h"
-
-#include "BKE_gpencil.h"
-#include "BKE_gpencil_modifier.h"
-#include "BKE_image.h"
-#include "BKE_material.h"
-#include "BKE_paint.h"
-
-#include "BLI_hash.h"
-
-#include "ED_gpencil.h"
-
-#include "DNA_gpencil_types.h"
-#include "DNA_material_types.h"
-#include "DNA_view3d_types.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-/* For EvaluationContext... */
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-
-#include "IMB_imbuf_types.h"
-
-#include "gpencil_engine.h"
-
-#include "UI_resources.h"
-
-/* fill type to communicate to shader */
-#define SOLID 0
-#define GRADIENT 1
-#define RADIAL 2
-#define CHECKER 3
-#define TEXTURE 4
-#define PATTERN 5
-
-/* Verify if must fade object or not. */
-static bool gpencil_fade_object_check(GPENCIL_StorageList *stl, Object *ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- const bool is_overlay = (bool)((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
- (v3d->gp_flag & V3D_GP_SHOW_PAPER));
-
- if ((!is_overlay) || (ob == draw_ctx->obact) ||
- ((v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL) == 0) ||
- (v3d->overlay.gpencil_paper_opacity == 1.0f)) {
- return false;
- }
-
- const bool playing = stl->storage->is_playing;
- const bool is_render = (bool)stl->storage->is_render;
- const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
-
- return (bool)((!is_render) && (!playing) && (!is_mat_preview) && (!is_select));
-}
-
-/* Define Fade layer uniforms. */
-static void gpencil_set_fade_layer_uniforms(
- GPENCIL_StorageList *stl, DRWShadingGroup *grp, Object *ob, bGPDlayer *gpl, const bool skip)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
- const bool is_fade = (v3d) && (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) &&
- (draw_ctx->obact) && (draw_ctx->obact == ob) &&
- ((gpl->flag & GP_LAYER_ACTIVE) == 0);
-
- const bool playing = stl->storage->is_playing;
- const bool is_render = (bool)stl->storage->is_render;
- const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
-
- /* If drawing or not fading layer, skip. */
- if ((!overlay) || (skip) || (!is_fade) || (is_render) || (playing) || (is_mat_preview) ||
- (is_select)) {
- DRW_shgroup_uniform_int_copy(grp, "fade_layer", 0);
- return;
- }
-
- /* If layer is above active, use alpha (2) if below use mix with background (1). */
- if (stl->storage->is_ontop) {
- DRW_shgroup_uniform_int_copy(grp, "fade_layer", 2);
- }
- else {
- DRW_shgroup_uniform_int_copy(grp, "fade_layer", 1);
- }
- if (v3d) {
- DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
- DRW_shgroup_uniform_float(grp, "fade_layer_factor", &v3d->overlay.gpencil_fade_layer, 1);
- }
-}
-
-/* Define Fade object uniforms. */
-static void gpencil_set_fade_ob_uniforms(View3D *v3d, DRWShadingGroup *grp, bool status)
-{
- DRW_shgroup_uniform_bool_copy(grp, "fade_ob", status);
- if (v3d) {
- DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
- DRW_shgroup_uniform_float(grp, "fade_ob_factor", &v3d->overlay.gpencil_paper_opacity, 1);
- }
-}
-
-/* Get number of vertex for using in GPU VBOs */
-static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
- tGPencilObjectCache *cache_ob,
- GpencilBatchCache *cache,
- bGPdata *gpd)
-{
- if ((!cache->is_dirty) || (gpd == NULL)) {
- return;
- }
-
- Object *ob = cache_ob->ob;
- const bool main_onion = stl->storage->is_main_onion;
- const bool playing = stl->storage->is_playing;
- const bool overlay = stl->storage->is_main_overlay;
- const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
- main_onion && !playing && gpencil_onion_active(gpd);
-
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- /* Onion skinning. */
- const int step = gpd->gstep;
- const int mode = gpd->onion_mode;
- const short onion_keytype = gpd->onion_keytype;
-
- cache_ob->tot_vertex = 0;
- cache_ob->tot_triangles = 0;
- int idx_eval = 0;
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *init_gpf = NULL;
- const bool is_onion = ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN));
- if (gpl->flag & GP_LAYER_HIDE) {
- idx_eval++;
- continue;
- }
-
- /* Relative onion mode needs to find the frame range before. */
- int frame_from = -9999;
- int frame_to = 9999;
- if ((is_onion) && (mode == GP_ONION_MODE_RELATIVE)) {
- /* 1) Found first Frame. */
- int idx = 0;
- if (gpl->actframe) {
- for (bGPDframe *gf = gpl->actframe->prev; gf; gf = gf->prev) {
- idx++;
- frame_from = gf->framenum;
- if (idx >= step) {
- break;
- }
- }
- /* 2) Found last Frame. */
- idx = 0;
- for (bGPDframe *gf = gpl->actframe->next; gf; gf = gf->next) {
- idx++;
- frame_to = gf->framenum;
- if (idx >= gpd->gstep_next) {
- break;
- }
- }
- }
- }
-
- /* If multiedit or onion skin need to count all frames of the layer. */
- if ((is_multiedit) || (is_onion)) {
- init_gpf = gpl->frames.first;
- }
- else {
- init_gpf = &ob->runtime.gpencil_evaluated_frames[idx_eval];
- }
-
- if (init_gpf == NULL) {
- continue;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (!is_onion) {
- if ((!is_multiedit) ||
- ((is_multiedit) && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) {
- cache_ob->tot_vertex += gps->totpoints + 3;
- cache_ob->tot_triangles += gps->totpoints - 1;
- }
- }
- else {
- bool select = ((is_multiedit) &&
- ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)));
-
- if (!select) {
- /* Only selected frames. */
- if ((mode == GP_ONION_MODE_SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
- continue;
- }
- /* Verify keyframe type. */
- if ((onion_keytype > -1) && (gpf->key_type != onion_keytype)) {
- continue;
- }
- /* Absolute range. */
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- if ((gpl->actframe) && (abs(gpl->actframe->framenum - gpf->framenum) > step)) {
- continue;
- }
- }
- /* Relative range. */
- if (mode == GP_ONION_MODE_RELATIVE) {
- if ((gpf->framenum < frame_from) || (gpf->framenum > frame_to)) {
- continue;
- }
- }
- }
-
- cache_ob->tot_vertex += gps->totpoints + 3;
- cache_ob->tot_triangles += gps->totpoints - 1;
- }
- }
-
- /* If not multiframe nor Onion skin, don't need follow counting. */
- if ((!is_multiedit) && (!is_onion)) {
- break;
- }
- }
- idx_eval++;
- }
-
- cache->b_fill.tot_vertex = cache_ob->tot_triangles * 3;
- cache->b_stroke.tot_vertex = cache_ob->tot_vertex;
- cache->b_point.tot_vertex = cache_ob->tot_vertex;
- cache->b_edit.tot_vertex = cache_ob->tot_vertex;
- cache->b_edlin.tot_vertex = cache_ob->tot_vertex;
-}
-
-/* Helper for doing all the checks on whether a stroke can be drawn */
-static bool gpencil_can_draw_stroke(struct MaterialGPencilStyle *gp_style,
- const bGPDstroke *gps,
- const bool onion,
- const bool is_mat_preview)
-{
- /* skip stroke if it doesn't have any valid data */
- if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
- return false;
- }
-
- /* if mat preview render always visible */
- if (is_mat_preview) {
- return true;
- }
-
- /* check if the color is visible */
- if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) {
- return false;
- }
-
- /* stroke can be drawn */
- return true;
-}
-
-/* recalc the internal geometry caches for fill and uvs */
-static void gpencil_recalc_geometry_caches(Object *ob,
- bGPDlayer *gpl,
- MaterialGPencilStyle *gp_style,
- bGPDstroke *gps)
-{
- if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
- /* Calculate triangles cache for filling area (must be done only after changes) */
- if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) {
- if ((gps->totpoints > 2) && (gp_style->flag & GP_STYLE_FILL_SHOW) &&
- ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0) ||
- (gpl->blend_mode != eGplBlendMode_Regular))) {
- BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps);
- }
- }
-
- /* calc uv data along the stroke */
- ED_gpencil_calc_stroke_uv(ob, gps);
-
- /* clear flag */
- gps->flag &= ~GP_STROKE_RECALC_GEOMETRY;
- }
-}
-
-static void set_wireframe_color(Object *ob,
- bGPDlayer *gpl,
- View3D *v3d,
- GPENCIL_StorageList *stl,
- MaterialGPencilStyle *gp_style,
- int id,
- const bool is_fill)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- World *world = draw_ctx->scene->world;
-
- float color[4];
- if (((gp_style->stroke_rgba[3] < GPENCIL_ALPHA_OPACITY_THRESH) ||
- (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0))) &&
- (gp_style->fill_rgba[3] >= GPENCIL_ALPHA_OPACITY_THRESH)) {
- copy_v4_v4(color, gp_style->fill_rgba);
- }
- else {
- copy_v4_v4(color, gp_style->stroke_rgba);
- }
-
- /* wire color */
- if ((v3d) && (id > -1)) {
- const char type = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- /* if fill and wire, use background color */
- if ((is_fill) && (stl->shgroups[id].shading_type[0] == OB_WIRE)) {
- if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_THEME) {
- UI_GetThemeColor4fv(TH_BACK, stl->shgroups[id].wire_color);
- stl->shgroups[id].wire_color[3] = 1.0f;
- }
- else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) {
- color[0] = world->horr;
- color[1] = world->horg;
- color[2] = world->horb;
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- }
- else {
- copy_v3_v3(color, v3d->shading.background_color);
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- }
- return;
- }
-
- /* strokes */
- switch (type) {
- case V3D_SHADING_SINGLE_COLOR: {
- if (stl->shgroups[id].shading_type[0] == OB_WIRE) {
- UI_GetThemeColor4fv(TH_WIRE, color);
- }
- else {
- copy_v3_v3(color, v3d->shading.single_color);
- }
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- break;
- }
- case V3D_SHADING_OBJECT_COLOR: {
- copy_v4_v4(color, ob->color);
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- break;
- }
- case V3D_SHADING_RANDOM_COLOR: {
- uint gpl_hash = 1;
- uint ob_hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
- if (gpl) {
- gpl_hash = BLI_ghashutil_strhash_p_murmur(gpl->info);
- }
-
- float hue = BLI_hash_int_01(ob_hash * gpl_hash);
- float hsv[3] = {hue, 0.40f, 0.8f};
- float wire_col[3];
- hsv_to_rgb_v(hsv, &wire_col[0]);
-
- copy_v3_v3(stl->shgroups[id].wire_color, wire_col);
- stl->shgroups[id].wire_color[3] = 1.0f;
- break;
- }
- default: {
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- break;
- }
- }
- }
- else {
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- }
-
- /* if solid, the alpha must be set to alpha */
- if (stl->shgroups[id].shading_type[0] == OB_SOLID) {
- stl->shgroups[id].wire_color[3] = 1.0f;
- }
-}
-
-/* create shading group for filling */
-static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- DRWPass *pass,
- GPUShader *shader,
- Object *ob,
- float (*obmat)[4],
- bGPdata *gpd,
- bGPDlayer *gpl,
- MaterialGPencilStyle *gp_style,
- int id,
- const int shading_type[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- /* e_data.gpencil_fill_sh */
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
-
- DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
-
- DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
-
- /* set style type */
- switch (gp_style->fill_style) {
- case GP_STYLE_FILL_STYLE_SOLID:
- stl->shgroups[id].fill_style = SOLID;
- break;
- case GP_STYLE_FILL_STYLE_GRADIENT:
- if (gp_style->gradient_type == GP_STYLE_GRADIENT_LINEAR) {
- stl->shgroups[id].fill_style = GRADIENT;
- }
- else {
- stl->shgroups[id].fill_style = RADIAL;
- }
- break;
- case GP_STYLE_FILL_STYLE_CHECKER:
- stl->shgroups[id].fill_style = CHECKER;
- break;
- case GP_STYLE_FILL_STYLE_TEXTURE:
- if (gp_style->flag & GP_STYLE_FILL_PATTERN) {
- stl->shgroups[id].fill_style = PATTERN;
- }
- else {
- stl->shgroups[id].fill_style = TEXTURE;
- }
- break;
- default:
- stl->shgroups[id].fill_style = GP_STYLE_FILL_STYLE_SOLID;
- break;
- }
- DRW_shgroup_uniform_int(grp, "fill_type", &stl->shgroups[id].fill_style, 1);
-
- DRW_shgroup_uniform_float(grp, "mix_factor", &gp_style->mix_factor, 1);
-
- DRW_shgroup_uniform_float(grp, "gradient_angle", &gp_style->gradient_angle, 1);
- DRW_shgroup_uniform_float(grp, "gradient_radius", &gp_style->gradient_radius, 1);
- DRW_shgroup_uniform_float(grp, "pattern_gridsize", &gp_style->pattern_gridsize, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_scale", gp_style->gradient_scale, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_shift", gp_style->gradient_shift, 1);
-
- DRW_shgroup_uniform_float(grp, "texture_angle", &gp_style->texture_angle, 1);
- DRW_shgroup_uniform_vec2(grp, "texture_scale", gp_style->texture_scale, 1);
- DRW_shgroup_uniform_vec2(grp, "texture_offset", gp_style->texture_offset, 1);
- DRW_shgroup_uniform_float(grp, "texture_opacity", &gp_style->texture_opacity, 1);
- DRW_shgroup_uniform_float(grp, "layer_opacity", &gpl->opacity, 1);
-
- stl->shgroups[id].texture_mix = gp_style->flag & GP_STYLE_FILL_TEX_MIX ? 1 : 0;
- DRW_shgroup_uniform_int(grp, "texture_mix", &stl->shgroups[id].texture_mix, 1);
-
- stl->shgroups[id].texture_flip = gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 0;
- DRW_shgroup_uniform_int(grp, "texture_flip", &stl->shgroups[id].texture_flip, 1);
-
- stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE;
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->shgroups[id].xray_mode, 1);
- DRW_shgroup_uniform_int(grp, "drawmode", (const int *)&gpd->draw_mode, 1);
-
- /* viewport x-ray */
- stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
- DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
-
- /* shading type */
- stl->shgroups[id].shading_type[0] = GPENCIL_USE_SOLID(stl) ? (int)OB_RENDER : shading_type[0];
- if (v3d) {
- stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- }
-
- DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
-
- /* wire color */
- set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, true);
- DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
-
- /* image texture */
- if ((gp_style->flag & GP_STYLE_FILL_TEX_MIX) ||
- (gp_style->fill_style & GP_STYLE_FILL_STYLE_TEXTURE)) {
- ImBuf *ibuf;
- Image *image = gp_style->ima;
- ImageUser iuser = {NULL};
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, ibuf, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "myTexture", texture);
- DRW_shgroup_uniform_bool_copy(
- grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
-
- stl->shgroups[id].texture_clamp = gp_style->flag & GP_STYLE_COLOR_TEX_CLAMP ? 1 : 0;
- DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
-
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- }
- else {
- /* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
- stl->shgroups[id].texture_clamp = 0;
- DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
- }
-
- return grp;
-}
-
-/* check if some onion is enabled */
-bool gpencil_onion_active(bGPdata *gpd)
-{
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
- return true;
- }
- }
- return false;
-}
-
-/* create shading group for strokes */
-DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- DRWPass *pass,
- GPUShader *shader,
- Object *ob,
- float (*obmat)[4],
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDstroke *gps,
- MaterialGPencilStyle *gp_style,
- int id,
- bool onion,
- const float scale,
- const int shading_type[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const float *viewport_size = DRW_viewport_size_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- /* e_data.gpencil_stroke_sh */
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
-
- DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
-
- DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
-
- DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
-
- /* avoid wrong values */
- if ((gpd) && (gpd->pixfactor == 0.0f)) {
- gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- }
-
- /* object scale and depth */
- if ((ob) && (id > -1)) {
- stl->shgroups[id].obj_scale = scale;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
- stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
-
- stl->shgroups[id].stroke_style = gp_style->stroke_style;
- stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
- if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
- if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
- }
- }
- DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
-
- stl->shgroups[id].caps_mode[0] = gps->caps[0];
- stl->shgroups[id].caps_mode[1] = gps->caps[1];
- DRW_shgroup_uniform_int(grp, "caps_mode", &stl->shgroups[id].caps_mode[0], 2);
-
- stl->shgroups[id].gradient_f = gps->gradient_f;
- copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s);
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1);
-
- /* viewport x-ray */
- stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
- DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
-
- stl->shgroups[id].shading_type[0] = (GPENCIL_USE_SOLID(stl) || onion) ? (int)OB_RENDER :
- shading_type[0];
- if (v3d) {
- stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- }
- DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
-
- /* wire color */
- set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
- DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
-
- /* mix stroke factor */
- stl->shgroups[id].mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->shgroups[id].mix_stroke_factor, 1);
- }
- else {
- stl->storage->obj_scale = 1.0f;
- stl->storage->keep_size = 0;
- stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
- DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
- if (gpd) {
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
- }
- else {
- DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
- }
- const int zero[2] = {0, 0};
- DRW_shgroup_uniform_int(grp, "caps_mode", &zero[0], 2);
-
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1);
-
- /* viewport x-ray */
- DRW_shgroup_uniform_int(grp, "viewport_xray", &stl->storage->is_xray, 1);
- DRW_shgroup_uniform_int(grp, "shading_type", (const int *)&stl->storage->shade_render, 2);
-
- /* mix stroke factor */
- stl->storage->mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->storage->mix_stroke_factor, 1);
- }
-
- DRW_shgroup_uniform_vec4(grp, "colormix", gp_style->stroke_rgba, 1);
-
- if ((gpd) && (id > -1)) {
- stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE;
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->shgroups[id].xray_mode, 1);
- }
- else {
- /* for drawing always on predefined z-depth */
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
- }
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, false);
-
- /* image texture for pattern */
- if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- ImBuf *ibuf;
- Image *image = gp_style->sima;
- ImageUser iuser = {NULL};
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, ibuf, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "myTexture", texture);
- DRW_shgroup_uniform_bool_copy(
- grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
-
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- }
- else {
- /* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
- }
-
- return grp;
-}
-
-/* create shading group for points */
-static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- DRWPass *pass,
- GPUShader *shader,
- Object *ob,
- float (*obmat)[4],
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDstroke *gps,
- MaterialGPencilStyle *gp_style,
- int id,
- bool onion,
- const float scale,
- const int shading_type[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const float *viewport_size = DRW_viewport_size_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- /* e_data.gpencil_stroke_sh */
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
-
- DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
- DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
-
- DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
-
- /* avoid wrong values */
- if ((gpd) && (gpd->pixfactor == 0.0f)) {
- gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- }
-
- /* object scale and depth */
- if ((ob) && (id > -1)) {
- stl->shgroups[id].obj_scale = scale;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
- stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
-
- stl->shgroups[id].mode = gp_style->mode;
- stl->shgroups[id].stroke_style = gp_style->stroke_style;
- stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
- if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
- if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
- }
- }
- DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
- DRW_shgroup_uniform_int(grp, "mode", &stl->shgroups[id].mode, 1);
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
-
- stl->shgroups[id].gradient_f = gps->gradient_f;
- copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s);
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->shgroups[id].gradient_s, 1);
-
- /* viewport x-ray */
- stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
- DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
-
- stl->shgroups[id].shading_type[0] = (GPENCIL_USE_SOLID(stl) || onion) ? (int)OB_RENDER :
- shading_type[0];
- if (v3d) {
- stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- }
- DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
-
- /* wire color */
- set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
- DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
-
- /* mix stroke factor */
- stl->shgroups[id].mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->shgroups[id].mix_stroke_factor, 1);
-
- /* lock rotation of dots and boxes */
- stl->shgroups[id].alignment_mode = gp_style->alignment_mode;
- DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->shgroups[id].alignment_mode, 1);
- }
- else {
- stl->storage->obj_scale = 1.0f;
- stl->storage->keep_size = 0;
- stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
- stl->storage->mode = gp_style->mode;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
- DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
- DRW_shgroup_uniform_int(grp, "mode", &stl->storage->mode, 1);
- if (gpd) {
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
- }
- else {
- DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
- }
-
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->storage->gradient_s, 1);
-
- /* viewport x-ray */
- DRW_shgroup_uniform_int(grp, "viewport_xray", &stl->storage->is_xray, 1);
- DRW_shgroup_uniform_int(grp, "shading_type", (const int *)&stl->storage->shade_render, 2);
-
- /* mix stroke factor */
- stl->storage->mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->storage->mix_stroke_factor, 1);
-
- /* lock rotation of dots and boxes */
- DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->storage->alignment_mode, 1);
- }
-
- DRW_shgroup_uniform_vec4(grp, "colormix", gp_style->stroke_rgba, 1);
-
- if ((gpd) && (id > -1)) {
- stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE;
- DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&stl->shgroups[id].xray_mode, 1);
- }
- else {
- /* for drawing always on predefined z-depth */
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
- }
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, false);
-
- /* image texture */
- if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- ImBuf *ibuf;
- Image *image = gp_style->sima;
- ImageUser iuser = {NULL};
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, ibuf, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "myTexture", texture);
- DRW_shgroup_uniform_bool_copy(
- grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
-
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- }
- else {
- /* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
- }
-
- return grp;
-}
-
-/* add fill vertex info */
-static void gpencil_add_fill_vertexdata(GpencilBatchCache *cache,
- Object *ob,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps,
- float opacity,
- const float tintcolor[4],
- const bool onion,
- const bool custonion)
-{
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- if (gps->totpoints >= 3) {
- float tfill[4];
- /* set color using material, tint color and opacity */
- interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
- tfill[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
- if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0) ||
- (gpl->blend_mode != eGplBlendMode_Regular)) {
- if (cache->is_dirty) {
- const float *color;
- if (!onion) {
- color = tfill;
- }
- else {
- if (custonion) {
- color = tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gps->runtime.tmp_fill_rgba), tintcolor[3]);
- color = tfill;
- }
- }
- /* create vertex data */
- const int old_len = cache->b_fill.vbo_len;
- gpencil_get_fill_geom(&cache->b_fill, ob, gps, color);
-
- /* add to list of groups */
- if (old_len < cache->b_fill.vbo_len) {
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Fill,
- onion,
- cache->b_fill.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- }
- }
-}
-
-/* add stroke vertex info */
-static void gpencil_add_stroke_vertexdata(GpencilBatchCache *cache,
- Object *ob,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps,
- const float opacity,
- const float tintcolor[4],
- const bool onion,
- const bool custonion)
-{
- float tcolor[4];
- float ink[4];
- short sthickness;
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- const int alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH;
-
- /* set color using base color, tint color and opacity */
- if (cache->is_dirty) {
- if (!onion) {
- /* if special stroke, use fill color as stroke color */
- if (gps->flag & GP_STROKE_NOFILL) {
- interp_v3_v3v3(tcolor, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
- tcolor[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
- }
- else {
- interp_v3_v3v3(tcolor, gps->runtime.tmp_stroke_rgba, tintcolor, tintcolor[3]);
- tcolor[3] = gps->runtime.tmp_stroke_rgba[3] * opacity;
- }
- copy_v4_v4(ink, tcolor);
- }
- else {
- if (custonion) {
- copy_v4_v4(ink, tintcolor);
- }
- else {
- ARRAY_SET_ITEMS(tcolor, UNPACK3(gps->runtime.tmp_stroke_rgba), opacity);
- copy_v4_v4(ink, tcolor);
- }
- }
-
- sthickness = gps->thickness + gpl->line_change;
- CLAMP_MIN(sthickness, 1);
-
- if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
- /* create vertex data */
- const int old_len = cache->b_stroke.vbo_len;
- gpencil_get_stroke_geom(&cache->b_stroke, gps, sthickness, ink);
-
- /* add to list of groups */
- if (old_len < cache->b_stroke.vbo_len) {
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Stroke,
- onion,
- cache->b_stroke.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- else {
- /* create vertex data */
- const int old_len = cache->b_point.vbo_len;
- gpencil_get_point_geom(&cache->b_point, gps, sthickness, ink, alignment_mode);
-
- /* add to list of groups */
- if (old_len < cache->b_point.vbo_len) {
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Point,
- onion,
- cache->b_point.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- }
-}
-
-/* add edit points vertex info */
-static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- ToolSettings *ts = draw_ctx->scene->toolsettings;
- const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) && (ts->gpencil_selectmode_sculpt &
- (GP_SCULPT_MASK_SELECTMODE_POINT |
- GP_SCULPT_MASK_SELECTMODE_STROKE |
- GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
-
- const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) &&
- (ts->gpencil_selectmode_sculpt &
- (GP_SCULPT_MASK_SELECTMODE_POINT |
- GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
-
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
-
- /* alpha factor for edit points/line to make them more subtle */
- float edit_alpha = v3d->vertex_opacity;
-
- if (GPENCIL_ANY_EDIT_MODE(gpd)) {
- Object *obact = DRW_context_state_get()->obact;
- if ((!obact) || (obact->type != OB_GPENCIL)) {
- return;
- }
- const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
-
- /* If Sculpt mode and the mask is disabled, the select must be hidden. */
- const bool hide_select = GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask;
-
- /* Show Edit points if:
- * Edit mode: Not in Stroke selection mode
- * Sculpt mode: Not in Stroke mask mode and any other mask mode enabled
- * Weight mode: Always
- */
- const bool show_points = (show_sculpt_points) || (is_weight_paint) ||
- (GPENCIL_EDIT_MODE(gpd) &&
- ((ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE) ||
- (gps->totpoints == 1)));
-
- if (cache->is_dirty) {
- if ((obact == ob) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
- (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) && (gps->totpoints > 1)) {
-
- /* line of the original stroke */
- gpencil_get_edlin_geom(&cache->b_edlin, gps, edit_alpha, hide_select);
-
- /* add to list of groups */
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Edlin,
- false,
- cache->b_edlin.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
-
- /* If the points are hidden return. */
- if ((!show_points) || (hide_select)) {
- return;
- }
-
- /* edit points */
- if ((gps->flag & GP_STROKE_SELECT) || (is_weight_paint)) {
- if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) ||
- ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) {
- if (obact == ob) {
- gpencil_get_edit_geom(&cache->b_edit, gps, edit_alpha, gpd->flag);
-
- /* add to list of groups */
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Edit,
- false,
- cache->b_edit.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- }
- }
- }
-}
-
-/* main function to draw strokes */
-static void gpencil_draw_strokes(GpencilBatchCache *cache,
- GPENCIL_e_data *e_data,
- void *vedata,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- const float opacity,
- const float tintcolor[4],
- const bool custonion,
- tGPencilObjectCache *cache_ob)
-{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- View3D *v3d = draw_ctx->v3d;
- bGPDstroke *gps;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const bool playing = stl->storage->is_playing;
- const bool is_render = (bool)stl->storage->is_render;
- const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool overlay_multiedit = v3d != NULL ? !(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) :
- true;
-
- /* Get evaluation context */
- /* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files
- * (i.e. the thumbnail offscreen rendering fails)
- */
- Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
-
- /* get parent matrix and save as static data */
- if ((cache_ob != NULL) && (cache_ob->is_dup_ob)) {
- copy_m4_m4(gpf->runtime.parent_obmat, cache_ob->obmat);
- }
- else {
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, gpf->runtime.parent_obmat);
- }
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
-
- /* check if stroke can be drawn */
- if (gpencil_can_draw_stroke(gp_style, gps, false, is_mat_preview) == false) {
- continue;
- }
-
- /* Copy color to temp fields. */
- if ((is_multiedit) && (gp_style)) {
- copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
- }
-
- /* be sure recalc all cache in source stroke to avoid recalculation when frame change
- * and improve fps */
- gpencil_recalc_geometry_caches(
- ob, gpl, gp_style, (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps);
-
- /* if the fill has any value, it's considered a fill and is not drawn if simplify fill is
- * enabled */
- if ((stl->storage->simplify_fill) &&
- (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_REMOVE_FILL_LINE)) {
- if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
- (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID) ||
- (gpl->blend_mode != eGplBlendMode_Regular)) {
-
- continue;
- }
- }
-
- if ((gpl->actframe && (gpl->actframe->framenum == gpf->framenum)) || (!is_multiedit) ||
- (overlay_multiedit)) {
- /* hide any blend layer */
- if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Regular)) {
- /* fill */
- if ((gp_style->flag & GP_STYLE_FILL_SHOW) && (!stl->storage->simplify_fill) &&
- ((gps->flag & GP_STROKE_NOFILL) == 0)) {
- gpencil_add_fill_vertexdata(
- cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion);
- }
- /* stroke
- * No fill strokes, must show stroke always or if the total points is lower than 3,
- * because the stroke cannot be filled and it would be invisible. */
- if (((gp_style->flag & GP_STYLE_STROKE_SHOW) || (gps->flag & GP_STROKE_NOFILL) ||
- (gps->totpoints < 3)) &&
- ((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
- (gpl->blend_mode == eGplBlendMode_Regular))) {
- /* recalc strokes uv (geometry can be changed by modifiers) */
- if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
- ED_gpencil_calc_stroke_uv(ob, gps);
- }
-
- gpencil_add_stroke_vertexdata(
- cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion);
- }
- }
- }
-
- /* edit points (only in edit mode and not play animation not render) */
- if ((draw_ctx->obact == ob) && (!playing) && (!is_render) && (!cache_ob->is_dup_ob)) {
- if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
- if (!stl->g_data->shgrps_edit_line) {
- stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh,
- psl->edit_pass);
- DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_line, "gpModelMatrix", ob->obmat);
- }
- if (!stl->g_data->shgrps_edit_point) {
- stl->g_data->shgrps_edit_point = DRW_shgroup_create(e_data->gpencil_edit_point_sh,
- psl->edit_pass);
- const float *viewport_size = DRW_viewport_size_get();
- DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1);
- DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_point, "gpModelMatrix", ob->obmat);
- }
-
- gpencil_add_editpoints_vertexdata(cache, ob, gpd, gpl, gpf, gps);
- }
- }
- }
-}
-
-/* get alpha factor for onion strokes */
-static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd)
-{
-#define MIN_ALPHA_VALUE 0.01f
-
- /* if fade is disabled, opacity is equal in all frames */
- if ((gpd->onion_flag & GP_ONION_FADE) == 0) {
- color[3] = gpd->onion_factor;
- }
- else {
- /* add override opacity factor */
- color[3] += gpd->onion_factor - 0.5f;
- }
-
- CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f);
-}
-
-/* function to draw strokes for onion only */
-static void gpencil_draw_onion_strokes(GpencilBatchCache *cache,
- void *vedata,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- const float opacity,
- const float tintcolor[4],
- const bool custonion)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
-
- /* get parent matrix and save as static data */
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, gpf->runtime.parent_obmat);
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- if (gp_style == NULL) {
- continue;
- }
- copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
-
- int id = stl->storage->shgroup_id;
- /* check if stroke can be drawn */
- if (gpencil_can_draw_stroke(gp_style, gps, true, false) == false) {
- continue;
- }
- /* limit the number of shading groups */
- if (id >= GPENCIL_MAX_SHGROUPS) {
- continue;
- }
-
- /* stroke */
- gpencil_add_stroke_vertexdata(cache, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion);
-
- stl->storage->shgroup_id++;
- }
-}
-
-/* draw onion-skinning for a layer */
-static void gpencil_draw_onionskins(GpencilBatchCache *cache,
- void *vedata,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf)
-{
-
- const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
- const float alpha = 1.0f;
- float color[4];
- int idx;
- float fac = 1.0f;
- int step = 0;
- bool colflag = false;
- const int mode = gpd->onion_mode;
- bGPDframe *gpf_loop = ((gpd->onion_flag & GP_ONION_LOOP) && (mode != GP_ONION_MODE_SELECTED)) ?
- gpl->frames.first :
- NULL;
- int last = gpf->framenum;
-
- colflag = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
- const short onion_keytype = gpd->onion_keytype;
- /* -------------------------------
- * 1) Draw Previous Frames First
- * ------------------------------- */
- step = gpd->gstep;
-
- if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) {
- copy_v3_v3(color, gpd->gcolor_prev);
- }
- else {
- copy_v3_v3(color, default_color);
- }
-
- idx = 0;
- for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) {
- /* only selected frames */
- if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
- continue;
- }
- /* verify keyframe type */
- if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) {
- continue;
- }
- /* absolute range */
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- if ((gpf->framenum - gf->framenum) > step) {
- break;
- }
- }
- /* relative range */
- if (mode == GP_ONION_MODE_RELATIVE) {
- idx++;
- if (idx > step) {
- break;
- }
- }
- /* alpha decreases with distance from curframe index */
- if (mode != GP_ONION_MODE_SELECTED) {
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(step + 1));
- }
- else {
- fac = 1.0f - ((float)idx / (float)(step + 1));
- }
- color[3] = alpha * fac * 0.66f;
- }
- else {
- idx++;
- fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
- color[3] = fac;
- }
-
- /* if loop option, save the frame to use later */
- if ((mode == GP_ONION_MODE_SELECTED) && (gpd->onion_flag & GP_ONION_LOOP)) {
- gpf_loop = gf;
- }
-
- gpencil_get_onion_alpha(color, gpd);
- gpencil_draw_onion_strokes(cache, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
- }
- /* -------------------------------
- * 2) Now draw next frames
- * ------------------------------- */
- step = gpd->gstep_next;
-
- if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) {
- copy_v3_v3(color, gpd->gcolor_next);
- }
- else {
- copy_v3_v3(color, default_color);
- }
-
- idx = 0;
- for (bGPDframe *gf = gpf->next; gf; gf = gf->next) {
- /* only selected frames */
- if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
- continue;
- }
- /* verify keyframe type */
- if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) {
- continue;
- }
- /* absolute range */
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- if ((gf->framenum - gpf->framenum) > step) {
- break;
- }
- }
- /* relative range */
- if (mode == GP_ONION_MODE_RELATIVE) {
- idx++;
- if (idx > step) {
- break;
- }
- }
- /* alpha decreases with distance from curframe index */
- if (mode != GP_ONION_MODE_SELECTED) {
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(step + 1));
- }
- else {
- fac = 1.0f - ((float)idx / (float)(step + 1));
- }
- color[3] = alpha * fac * 0.66f;
- }
- else {
- idx++;
- fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
- color[3] = fac;
- }
-
- gpencil_get_onion_alpha(color, gpd);
- gpencil_draw_onion_strokes(cache, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
- if (last < gf->framenum) {
- last = gf->framenum;
- }
- }
-
- /* Draw first frame in blue for loop mode */
- if ((gpd->onion_flag & GP_ONION_LOOP) && (gpf_loop != NULL)) {
- if ((last == gpf->framenum) || (gpf->next == NULL)) {
- gpencil_get_onion_alpha(color, gpd);
- gpencil_draw_onion_strokes(cache, vedata, ob, gpd, gpl, gpf_loop, color[3], color, colflag);
- }
- }
-}
-
-/* Check if stencil is required */
-static bool gpencil_is_stencil_required(MaterialGPencilStyle *gp_style)
-{
- return (bool)((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_SOLID) &&
- ((gp_style->flag & GP_STYLE_DISABLE_STENCIL) == 0));
-}
-
-/* draw stroke in drawing buffer */
-void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
- void *vedata,
- ToolSettings *ts,
- Object *ob)
-{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- const bool is_paint_tool = (bool)((brush) && (brush->gpencil_tool == GPAINT_TOOL_DRAW));
- bGPdata *gpd_eval = ob->data;
- /* need the original to avoid cow overhead while drawing */
- bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
-
- MaterialGPencilStyle *gp_style = NULL;
- float obscale = mat4_to_scale(ob->obmat);
-
- /* use the brush material */
- Material *ma = BKE_gpencil_object_material_get_from_brush(ob, brush);
- if (ma != NULL) {
- gp_style = ma->gp_style;
- }
- /* this is not common, but avoid any special situations when brush could be without material */
- if (gp_style == NULL) {
- gp_style = BKE_gpencil_material_settings(ob, ob->actcol);
- }
-
- static float unit_mat[4][4] = {
- {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}};
-
- /* drawing strokes */
- /* Check if may need to draw the active stroke cache, only if this layer is the active layer
- * that is being edited. (Stroke buffer is currently stored in gp-data)
- */
- if (gpd->runtime.sbuffer_used > 0) {
- if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
- /* It should also be noted that sbuffer contains temporary point types
- * i.e. tGPspoints NOT bGPDspoints
- */
- short lthick = brush->size * obscale;
-
- /* save gradient info */
- stl->storage->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(stl->storage->gradient_s, brush->gpencil_settings->gradient_s);
- stl->storage->alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH;
-
- /* if only one point, don't need to draw buffer because the user has no time to see it */
- if (gpd->runtime.sbuffer_used > 1) {
- if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
- stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_stroke_create(
- e_data,
- vedata,
- psl->drawing_pass,
- e_data->gpencil_stroke_sh,
- NULL,
- unit_mat,
- gpd,
- NULL,
- NULL,
- gp_style,
- -1,
- false,
- 1.0f,
- (const int *)stl->storage->shade_render);
-
- if (gpencil_is_stencil_required(gp_style)) {
- DRW_shgroup_stencil_mask(stl->g_data->shgrps_drawing_stroke, 0x01);
- }
- else {
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_stroke,
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- }
- }
- else {
- stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_point_create(
- e_data,
- vedata,
- psl->drawing_pass,
- e_data->gpencil_point_sh,
- NULL,
- unit_mat,
- gpd,
- NULL,
- NULL,
- gp_style,
- -1,
- false,
- 1.0f,
- (const int *)stl->storage->shade_render);
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_stroke,
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- }
-
- /* use unit matrix because the buffer is in screen space and does not need conversion */
- if (gpd->runtime.mode == GP_STYLE_MODE_LINE) {
- stl->g_data->batch_buffer_stroke = gpencil_get_buffer_stroke_geom(gpd, lthick);
- }
- else {
- stl->g_data->batch_buffer_stroke = gpencil_get_buffer_point_geom(gpd, lthick);
- }
-
- /* buffer strokes, must show stroke always */
- DRW_shgroup_call(
- stl->g_data->shgrps_drawing_stroke, stl->g_data->batch_buffer_stroke, NULL);
-
- if ((gpd->runtime.sbuffer_used >= 3) &&
- (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
- ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_DISSABLE_LASSO) == 0) &&
- (gp_style->flag & GP_STYLE_FILL_SHOW)) {
- /* if not solid, fill is simulated with solid color */
- if (gpd->runtime.bfill_style > 0) {
- gpd->runtime.sfill[3] = 0.5f;
- }
- stl->g_data->shgrps_drawing_fill = DRW_shgroup_create(e_data->gpencil_drawing_fill_sh,
- psl->drawing_pass);
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_fill,
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- stl->g_data->batch_buffer_fill = gpencil_get_buffer_fill_geom(gpd);
- DRW_shgroup_call(stl->g_data->shgrps_drawing_fill, stl->g_data->batch_buffer_fill, NULL);
- }
- }
- }
- }
-
- /* control points for primitives and speed guide */
- const bool is_cppoint = (gpd->runtime.tot_cp_points > 0);
- const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide &&
- (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL));
- const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) &&
- ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0));
-
- if ((overlay) && (is_paint_tool) && (is_cppoint || is_speed_guide) && (is_show_gizmo) &&
- ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0)) {
- DRWShadingGroup *shgrp = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->drawing_pass);
- const float *viewport_size = DRW_viewport_size_get();
- DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1);
- DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", unit_mat);
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- stl->g_data->batch_buffer_ctrlpoint = gpencil_get_buffer_ctrlpoint_geom(gpd);
-
- DRW_shgroup_call(shgrp, stl->g_data->batch_buffer_ctrlpoint, NULL);
- }
-}
-
-/* create all missing batches */
-static void gpencil_batches_ensure(GpencilBatchCache *cache)
-{
- if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) {
- cache->b_point.batch = GPU_batch_create_ex(
- GPU_PRIM_POINTS, cache->b_point.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_stroke.vbo) && (cache->b_stroke.batch == NULL)) {
- cache->b_stroke.batch = GPU_batch_create_ex(
- GPU_PRIM_LINE_STRIP_ADJ, cache->b_stroke.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_fill.vbo) && (cache->b_fill.batch == NULL)) {
- cache->b_fill.batch = GPU_batch_create_ex(
- GPU_PRIM_TRIS, cache->b_fill.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_edit.vbo) && (cache->b_edit.batch == NULL)) {
- cache->b_edit.batch = GPU_batch_create_ex(
- GPU_PRIM_POINTS, cache->b_edit.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_edlin.vbo) && (cache->b_edlin.batch == NULL)) {
- cache->b_edlin.batch = GPU_batch_create_ex(
- GPU_PRIM_LINE_STRIP, cache->b_edlin.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
-}
-
-/* create all shading groups */
-static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
- void *vedata,
- Object *ob,
- GpencilBatchCache *cache,
- tGPencilObjectCache *cache_ob)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- bGPdata *gpd = (bGPdata *)ob->data;
- DRWPass *stroke_pass = GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d;
-
- GpencilBatchGroup *elm = NULL;
- DRWShadingGroup *shgrp = NULL;
- tGPencilObjectCache_shgrp *array_elm = NULL;
-
- bGPDlayer *gpl = NULL;
- bGPDlayer *gpl_prev = NULL;
- int idx = 0;
- bool tag_first = false;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
-
- const bool overlay = draw_ctx->v3d != NULL ?
- (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
- true;
- const bool screen_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true;
- const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && screen_onion &&
- overlay && gpencil_onion_active(gpd);
-
- int start_stroke = 0;
- int start_point = 0;
- int start_fill = 0;
- int start_edit = 0;
- int start_edlin = 0;
-
- uint stencil_id = 1;
- /* Flag to determine if the layer is above active layer. */
- stl->storage->is_ontop = false;
- for (int i = 0; i < cache->grp_used; i++) {
- elm = &cache->grp_cache[i];
- array_elm = &cache_ob->shgrp_array[idx];
-
- /* Limit stencil id */
- if (stencil_id > 255) {
- stencil_id = 1;
- }
-
- /* save last group when change */
- if (gpl_prev == NULL) {
- gpl_prev = elm->gpl;
- tag_first = true;
- }
- else {
- if (elm->gpl != gpl_prev) {
- /* first layer is always blend Normal */
- array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode;
- array_elm->end_shgrp = shgrp;
- gpl_prev = elm->gpl;
- tag_first = true;
- idx++;
- }
- }
-
- gpl = elm->gpl;
- if ((!stl->storage->is_ontop) && (gpl->flag & GP_LAYER_ACTIVE)) {
- stl->storage->is_ontop = true;
- }
-
- bGPDframe *gpf = elm->gpf;
- bGPDstroke *gps = elm->gps;
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- /* if the user switch used material from data to object,
- * the material could not be available */
- if (gp_style == NULL) {
- break;
- }
-
- /* limit the number of shading groups */
- if (i >= GPENCIL_MAX_SHGROUPS) {
- break;
- }
-
- const float scale = (!cache_ob->is_dup_ob) ? mat4_to_scale(gpf->runtime.parent_obmat) :
- cache_ob->scale;
- float(*obmat)[4] = (!cache_ob->is_dup_ob) ? gpf->runtime.parent_obmat : cache_ob->obmat;
- switch (elm->type) {
- case eGpencilBatchGroupType_Stroke: {
- const int len = elm->vertex_idx - start_stroke;
-
- shgrp = gpencil_shgroup_stroke_create(e_data,
- vedata,
- stroke_pass,
- e_data->gpencil_stroke_sh,
- ob,
- obmat,
- gpd,
- gpl,
- gps,
- gp_style,
- stl->storage->shgroup_id,
- elm->onion,
- scale,
- cache_ob->shading_type);
-
- /* set stencil mask id */
- if (gpencil_is_stencil_required(gp_style)) {
- if (stencil_id == 1) {
- /* Clear previous stencils. */
- DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0);
- }
- DRW_shgroup_stencil_mask(shgrp, stencil_id);
- stencil_id++;
- }
- else {
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- }
-
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len);
- }
- stl->storage->shgroup_id++;
- start_stroke = elm->vertex_idx;
- break;
- }
- case eGpencilBatchGroupType_Point: {
- const int len = elm->vertex_idx - start_point;
-
- shgrp = gpencil_shgroup_point_create(e_data,
- vedata,
- stroke_pass,
- e_data->gpencil_point_sh,
- ob,
- obmat,
- gpd,
- gpl,
- gps,
- gp_style,
- stl->storage->shgroup_id,
- elm->onion,
- scale,
- cache_ob->shading_type);
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len);
- }
- stl->storage->shgroup_id++;
- start_point = elm->vertex_idx;
- break;
- }
- case eGpencilBatchGroupType_Fill: {
- const int len = elm->vertex_idx - start_fill;
-
- shgrp = gpencil_shgroup_fill_create(e_data,
- vedata,
- stroke_pass,
- e_data->gpencil_fill_sh,
- ob,
- obmat,
- gpd,
- gpl,
- gp_style,
- stl->storage->shgroup_id,
- cache_ob->shading_type);
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len);
- }
- stl->storage->shgroup_id++;
- start_fill = elm->vertex_idx;
- break;
- }
- case eGpencilBatchGroupType_Edit: {
- if (stl->g_data->shgrps_edit_point) {
- const int len = elm->vertex_idx - start_edit;
-
- shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point);
- DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
- /* use always the same group */
- DRW_shgroup_call_range(
- stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len);
-
- start_edit = elm->vertex_idx;
- }
- break;
- }
- case eGpencilBatchGroupType_Edlin: {
- if (stl->g_data->shgrps_edit_line) {
- const int len = elm->vertex_idx - start_edlin;
-
- shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line);
- DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
- /* use always the same group */
- DRW_shgroup_call_range(
- stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len);
-
- start_edlin = elm->vertex_idx;
- }
- break;
- }
- default: {
- break;
- }
- }
- /* save first group */
- if ((shgrp != NULL) && (tag_first)) {
- array_elm = &cache_ob->shgrp_array[idx];
- array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode;
- array_elm->mask_layer = gpl->flag & GP_LAYER_USE_MASK;
- array_elm->blend_opacity = gpl->opacity;
- array_elm->init_shgrp = shgrp;
- cache_ob->tot_layers++;
-
- tag_first = false;
- }
- }
-
- /* save last group */
- if (shgrp != NULL) {
- array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode;
- array_elm->end_shgrp = shgrp;
- }
-}
-/* populate a datablock for multiedit (no onions, no modifiers) */
-void gpencil_populate_multiedit(GPENCIL_e_data *e_data,
- void *vedata,
- Object *ob,
- tGPencilObjectCache *cache_ob)
-{
- bGPdata *gpd = (bGPdata *)ob->data;
- bGPDframe *gpf = NULL;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
- GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
-
- /* check if playing animation */
- const bool playing = stl->storage->is_playing;
-
- /* calc max size of VBOs */
- gpencil_calc_vertex(stl, cache_ob, cache, gpd);
-
- /* draw strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* don't draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
- const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
- const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
-
- /* list of frames to draw */
- if (!playing) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
- }
- }
- }
- else {
- gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
- if (gpf) {
- gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
- }
- }
- }
-
- /* create batchs and shading groups */
- gpencil_batches_ensure(cache);
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
-
- cache->is_dirty = false;
-}
-
-/* helper for populate a complete grease pencil datablock */
-void gpencil_populate_datablock(GPENCIL_e_data *e_data,
- void *vedata,
- Object *ob,
- tGPencilObjectCache *cache_ob)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph);
- Scene *scene = draw_ctx->scene;
-
- /* TODO: Review why is needed this recalc when render cycles + GP object in background.
- * We need these lines to keep running the background render, but asap we get an alternative
- * solution, we must remove it and keep all logic inside gpencil_modifier module. (antoniov)
- */
- if (ob->runtime.gpencil_tot_layers == 0) {
- BKE_gpencil_modifiers_calc(draw_ctx->depsgraph, draw_ctx->scene, ob);
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
-
- /* If render mode, instead to use view switches, test if the datablock has
- * the onion activated for render. */
- const bool render_onion = (gpd && gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
- const bool main_onion = (stl->storage->is_render) ? render_onion : stl->storage->is_main_onion;
- const bool overlay = (stl->storage->is_render) ? render_onion : stl->storage->is_main_overlay;
- const bool playing = stl->storage->is_playing;
- const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
- main_onion && !playing && gpencil_onion_active(gpd);
-
- View3D *v3d = draw_ctx->v3d;
- int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
-
- bGPDframe *gpf_eval = NULL;
- const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
-
- float opacity;
- bGPDframe *gpf = NULL;
-
- GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
-
- /* if object is duplicate, only create shading groups */
- if (cache_ob->is_dup_ob) {
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
- return;
- }
-
- /* calc max size of VBOs */
- gpencil_calc_vertex(stl, cache_ob, cache, gpd);
-
- /* draw normal strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* don't draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
-
- const bool is_solomode = GPENCIL_PAINT_MODE(gpd) && (!playing) && (!stl->storage->is_render) &&
- (gpl->flag & GP_LAYER_SOLO_MODE);
-
- /* filter view layer to gp layers in the same view layer (for compo) */
- if ((stl->storage->is_render) && (gpl->viewlayername[0] != '\0')) {
- if (!STREQ(view_layer->name, gpl->viewlayername)) {
- continue;
- }
- }
-
- /* remap time */
- int remap_cfra = cfra_eval;
- if ((time_remap) && (!stl->storage->simplify_modif)) {
- remap_cfra = BKE_gpencil_time_modifier(
- draw_ctx->depsgraph, scene, ob, gpl, cfra_eval, stl->storage->is_render);
- }
-
- gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
- if (gpf == NULL) {
- continue;
- }
-
- /* if solo mode, display only frames with keyframe in the current frame */
- if ((is_solomode) && (gpf->framenum != remap_cfra)) {
- continue;
- }
-
- opacity = gpl->opacity;
- /* if pose mode, maybe the overlay to fade geometry is enabled */
- if ((draw_ctx->obact) && (draw_ctx->object_mode == OB_MODE_POSE) &&
- (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT)) {
- opacity = opacity * v3d->overlay.xray_alpha_bone;
- }
-
- /* Get evaluated frames array data */
- int idx_eval = BLI_findindex(&gpd->layers, gpl);
- gpf_eval = &ob->runtime.gpencil_evaluated_frames[idx_eval];
-
- /* draw onion skins */
- if (!ID_IS_LINKED(&gpd->id)) {
- if ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
- ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) && (!cache_ob->is_dup_ob) &&
- (gpd->id.us <= 1)) {
- if ((!stl->storage->is_render) ||
- ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) {
- gpencil_draw_onionskins(cache, vedata, ob, gpd, gpl, gpf);
- }
- }
- }
- /* draw normal strokes */
- const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
- const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
- gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf_eval, opacity, tintcolor, false, cache_ob);
- }
-
- /* create batchs and shading groups */
- gpencil_batches_ensure(cache);
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
-
- cache->is_dirty = false;
-}
-
-void gpencil_populate_particles(GPENCIL_e_data *e_data, GHash *gh_objects, void *vedata)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-
- /* add particles */
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
- if (cache_ob->is_dup_ob) {
- /* Reassign duplicate objects because memory for particles is not available
- * and need to use the original data-block and run-time data. */
- Object *ob = (Object *)BLI_ghash_lookup(gh_objects, cache_ob->name);
- if (ob) {
- cache_ob->ob = ob;
- cache_ob->gpd = (bGPdata *)ob->data;
- GpencilBatchCache *cache = ob->runtime.gpencil_cache;
- if (cache != NULL) {
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
- }
- }
- }
- }
-}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 96560d986a0..80afbb5c7a3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -29,11 +29,19 @@
#include "BKE_paint.h"
#include "BKE_shader_fx.h"
+#include "BKE_camera.h"
+#include "BKE_global.h" /* for G.debug */
+
+#include "BLI_link_utils.h"
+#include "BLI_memblock.h"
+
+#include "DNA_camera_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
#include "gpencil_engine.h"
@@ -44,1129 +52,904 @@
#include "UI_resources.h"
-extern char datatoc_gpencil_fill_vert_glsl[];
-extern char datatoc_gpencil_fill_frag_glsl[];
-extern char datatoc_gpencil_stroke_vert_glsl[];
-extern char datatoc_gpencil_stroke_geom_glsl[];
-extern char datatoc_gpencil_stroke_frag_glsl[];
-extern char datatoc_gpencil_zdepth_mix_frag_glsl[];
-extern char datatoc_gpencil_simple_mix_frag_glsl[];
-extern char datatoc_gpencil_point_vert_glsl[];
-extern char datatoc_gpencil_point_geom_glsl[];
-extern char datatoc_gpencil_point_frag_glsl[];
-extern char datatoc_gpencil_background_frag_glsl[];
-extern char datatoc_gpencil_paper_frag_glsl[];
-extern char datatoc_gpencil_edit_point_vert_glsl[];
-extern char datatoc_gpencil_edit_point_geom_glsl[];
-extern char datatoc_gpencil_edit_point_frag_glsl[];
-extern char datatoc_gpencil_blend_frag_glsl[];
-
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
-
-extern char datatoc_common_colormanagement_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-/* *********** STATIC *********** */
-static GPENCIL_e_data e_data = {NULL}; /* Engine data */
-
/* *********** FUNCTIONS *********** */
-/* create a multisample buffer if not present */
-void gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h)
+void GPENCIL_engine_init(void *ved)
{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_StorageList *stl = vedata->stl;
+ GPENCIL_TextureList *txl = vedata->txl;
GPENCIL_FramebufferList *fbl = vedata->fbl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
-
- short samples = stl->storage->multisamples;
-
- if (samples > 0) {
- if (!fbl->multisample_fb) {
- fbl->multisample_fb = GPU_framebuffer_create();
- if (fbl->multisample_fb) {
- if (txl->multisample_color == NULL) {
- txl->multisample_color = GPU_texture_create_2d_multisample(
- rect_w, rect_h, GPU_RGBA16F, NULL, samples, NULL);
- }
- if (txl->multisample_depth == NULL) {
- txl->multisample_depth = GPU_texture_create_2d_multisample(
- rect_w, rect_h, GPU_DEPTH24_STENCIL8, NULL, samples, NULL);
- }
- GPU_framebuffer_ensure_config(&fbl->multisample_fb,
- {GPU_ATTACHMENT_TEXTURE(txl->multisample_depth),
- GPU_ATTACHMENT_TEXTURE(txl->multisample_color)});
- }
- }
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ const DRWContextState *ctx = DRW_context_state_get();
+ const View3D *v3d = ctx->v3d;
+
+ if (!stl->pd) {
+ stl->pd = MEM_callocN(sizeof(GPENCIL_PrivateData), "GPENCIL_PrivateData");
+ }
+
+ if (txl->dummy_texture == NULL) {
+ float pixels[1][4] = {{1.0f, 0.0f, 1.0f, 1.0f}};
+ txl->dummy_texture = DRW_texture_create_2d(1, 1, GPU_RGBA8, DRW_TEX_WRAP, (float *)pixels);
+ }
+
+ GPENCIL_ViewLayerData *vldata = GPENCIL_view_layer_data_ensure();
+
+ /* Resize and reset memblocks. */
+ BLI_memblock_clear(vldata->gp_light_pool, gpencil_light_pool_free);
+ BLI_memblock_clear(vldata->gp_material_pool, gpencil_material_pool_free);
+ BLI_memblock_clear(vldata->gp_object_pool, NULL);
+ BLI_memblock_clear(vldata->gp_layer_pool, NULL);
+ BLI_memblock_clear(vldata->gp_vfx_pool, NULL);
+ BLI_memblock_clear(vldata->gp_maskbit_pool, NULL);
+
+ stl->pd->gp_light_pool = vldata->gp_light_pool;
+ stl->pd->gp_material_pool = vldata->gp_material_pool;
+ stl->pd->gp_maskbit_pool = vldata->gp_maskbit_pool;
+ stl->pd->gp_object_pool = vldata->gp_object_pool;
+ stl->pd->gp_layer_pool = vldata->gp_layer_pool;
+ stl->pd->gp_vfx_pool = vldata->gp_vfx_pool;
+ stl->pd->scene = ctx->scene;
+ stl->pd->last_light_pool = NULL;
+ stl->pd->last_material_pool = NULL;
+ stl->pd->tobjects.first = NULL;
+ stl->pd->tobjects.last = NULL;
+ stl->pd->tobjects_infront.first = NULL;
+ stl->pd->tobjects_infront.last = NULL;
+ stl->pd->sbuffer_tobjects.first = NULL;
+ stl->pd->sbuffer_tobjects.last = NULL;
+ stl->pd->dummy_tx = txl->dummy_texture;
+ stl->pd->draw_depth_only = !DRW_state_is_fbo();
+ stl->pd->draw_wireframe = (v3d && v3d->shading.type == OB_WIRE) && !stl->pd->draw_depth_only;
+ stl->pd->scene_depth_tx = stl->pd->draw_depth_only ? txl->dummy_texture : dtxl->depth;
+ stl->pd->scene_fb = dfbl->default_fb;
+ stl->pd->is_render = txl->render_depth_tx || (v3d && v3d->shading.type == OB_RENDER);
+ stl->pd->is_viewport = (v3d != NULL);
+ stl->pd->global_light_pool = gpencil_light_pool_add(stl->pd);
+ stl->pd->shadeless_light_pool = gpencil_light_pool_add(stl->pd);
+ /* Small HACK: we don't want the global pool to be reused,
+ * so we set the last light pool to NULL. */
+ stl->pd->last_light_pool = NULL;
+
+ bool use_scene_lights = false;
+ bool use_scene_world = false;
+
+ if (v3d) {
+ use_scene_lights = ((v3d->shading.type == OB_MATERIAL) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER));
+
+ use_scene_world = ((v3d->shading.type == OB_MATERIAL) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_WORLD)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER));
+
+ stl->pd->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1;
+ /* Special case: If Vertex Paint mode, use always Vertex mode. */
+ if (v3d->shading.type == OB_SOLID && ctx->obact && ctx->obact->type == OB_GPENCIL &&
+ ctx->obact->mode == OB_MODE_VERTEX_GPENCIL) {
+ stl->pd->v3d_color_type = V3D_SHADING_VERTEX_COLOR;
+ }
+
+ copy_v3_v3(stl->pd->v3d_single_color, v3d->shading.single_color);
+
+ /* For non active frame, use only lines in multiedit mode. */
+ const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
+ stl->pd->use_multiedit_lines_only = !overlays_on ||
+ (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
+
+ const bool shmode_xray_support = v3d->shading.type <= OB_SOLID;
+ stl->pd->xray_alpha = (shmode_xray_support && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f;
+ }
+ else if (stl->pd->is_render) {
+ use_scene_lights = true;
+ use_scene_world = true;
+ stl->pd->use_multiedit_lines_only = false;
+ stl->pd->xray_alpha = 1.0f;
+ stl->pd->v3d_color_type = -1;
+ }
+
+ stl->pd->use_lighting = (v3d && v3d->shading.type > OB_SOLID) || stl->pd->is_render;
+ stl->pd->use_lights = use_scene_lights;
+
+ if (txl->render_depth_tx != NULL) {
+ stl->pd->scene_depth_tx = txl->render_depth_tx;
+ stl->pd->scene_fb = fbl->render_fb;
+ }
+
+ gpencil_light_ambient_add(stl->pd->shadeless_light_pool, (float[3]){1.0f, 1.0f, 1.0f});
+
+ World *world = ctx->scene->world;
+ if (world != NULL && use_scene_world) {
+ gpencil_light_ambient_add(stl->pd->global_light_pool, &world->horr);
+ }
+ else if (v3d) {
+ float world_light[3];
+ copy_v3_fl(world_light, v3d->shading.studiolight_intensity);
+ gpencil_light_ambient_add(stl->pd->global_light_pool, world_light);
+ }
+
+ float viewmatinv[4][4];
+ DRW_view_viewmat_get(NULL, viewmatinv, true);
+ copy_v3_v3(stl->pd->camera_z_axis, viewmatinv[2]);
+ copy_v3_v3(stl->pd->camera_pos, viewmatinv[3]);
+ stl->pd->camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]);
+
+ if (ctx && ctx->rv3d && v3d) {
+ stl->pd->camera = (ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+ }
+ else {
+ stl->pd->camera = NULL;
}
}
-static void GPENCIL_create_framebuffers(void *vedata)
+void GPENCIL_cache_init(void *ved)
{
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
-
- /* Go full 32bits for rendering */
- eGPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F;
-
- if (DRW_state_is_fbo()) {
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
- /* create multisample framebuffer for AA */
- if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) &&
- (stl->storage->multisamples > 0)) {
- gpencil_multisample_ensure(vedata, size[0], size[1]);
- }
-
- /* Framebufers for basic object drawing */
- if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_BASIC) {
- /* temp textures for ping-pong buffers */
- stl->g_data->temp_depth_tx_a = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
- stl->g_data->temp_color_tx_a = DRW_texture_pool_query_2d(
- size[0], size[1], fb_format, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->temp_fb_a,
- {
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_depth_tx_a),
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_a),
- });
-
- stl->g_data->temp_depth_tx_b = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
- stl->g_data->temp_color_tx_b = DRW_texture_pool_query_2d(
- size[0], size[1], fb_format, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->temp_fb_b,
- {
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_depth_tx_b),
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_b),
- });
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PassList *psl = vedata->psl;
+ GPENCIL_TextureList *txl = vedata->txl;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ DRWShadingGroup *grp;
- /* used for FX effects and Layer blending */
- stl->g_data->temp_depth_tx_fx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
- stl->g_data->temp_color_tx_fx = DRW_texture_pool_query_2d(
- size[0], size[1], fb_format, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->temp_fb_fx,
- {
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_depth_tx_fx),
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_fx),
- });
- }
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ pd->cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ pd->simplify_antialias = GPENCIL_SIMPLIFY_AA(draw_ctx->scene);
+ pd->use_layer_fb = false;
+ pd->use_object_fb = false;
+ pd->use_mask_fb = false;
+ pd->use_signed_fb = false;
+
+ if (draw_ctx->v3d) {
+ const bool hide_overlay = ((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) != 0);
+ const bool show_onion = ((draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) != 0);
+ const bool playing = (draw_ctx->evil_C != NULL) ?
+ ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) !=
+ NULL :
+ false;
+ pd->do_onion = show_onion && !hide_overlay && !playing;
+ /* Save simplify flags (can change while drawing, so it's better to save). */
+ Scene *scene = draw_ctx->scene;
+ pd->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing);
+ pd->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, playing) ||
+ (draw_ctx->v3d->shading.type < OB_RENDER);
+
+ /* Fade Layer. */
+ const bool is_fade_layer = ((!hide_overlay) && (!pd->is_render) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS));
+ pd->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f;
+ /* Fade GPencil Objects. */
+ const bool is_fade_object = ((!hide_overlay) && (!pd->is_render) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL));
+ pd->fade_gp_object_opacity = (is_fade_object) ? draw_ctx->v3d->overlay.gpencil_paper_opacity :
+ -1.0f;
+ pd->fade_3d_object_opacity = ((!hide_overlay) && (!pd->is_render) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS)) ?
+ draw_ctx->v3d->overlay.gpencil_paper_opacity :
+ -1.0f;
+ }
+ else {
+ pd->do_onion = true;
+ pd->simplify_fill = false;
+ pd->simplify_fx = false;
+ pd->fade_layer_opacity = -1.0f;
+ }
- /* background framebuffer to speed up drawing process */
- if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_DRAW) {
- if (txl->background_color_tx == NULL) {
- stl->storage->background_ready = false;
+ {
+ pd->sbuffer_stroke = NULL;
+ pd->sbuffer_gpd = NULL;
+ pd->sbuffer_layer = NULL;
+ pd->stroke_batch = NULL;
+ pd->fill_batch = NULL;
+ pd->do_fast_drawing = false;
+
+ pd->obact = draw_ctx->obact;
+ if (pd->obact && pd->obact->type == OB_GPENCIL) {
+ /* Check if active object has a temp stroke data. */
+ bGPdata *gpd = (bGPdata *)pd->obact->data;
+ if (gpd->runtime.sbuffer_used > 0) {
+ pd->sbuffer_gpd = gpd;
+ pd->sbuffer_stroke = DRW_cache_gpencil_sbuffer_stroke_data_get(pd->obact);
+ pd->sbuffer_layer = BKE_gpencil_layer_active_get(pd->sbuffer_gpd);
+ pd->do_fast_drawing = false; /* TODO option */
}
- DRW_texture_ensure_2d(
- &txl->background_depth_tx, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_FILTER);
- DRW_texture_ensure_2d(
- &txl->background_color_tx, size[0], size[1], GPU_RGBA16F, DRW_TEX_FILTER);
- GPU_framebuffer_ensure_config(&fbl->background_fb,
- {
- GPU_ATTACHMENT_TEXTURE(txl->background_depth_tx),
- GPU_ATTACHMENT_TEXTURE(txl->background_color_tx),
- });
- }
- else {
- DRW_TEXTURE_FREE_SAFE(txl->background_depth_tx);
- DRW_TEXTURE_FREE_SAFE(txl->background_color_tx);
}
}
-}
-static void GPENCIL_create_shaders(void)
-{
- /* blank texture used if no texture defined for fill shader */
- if (!e_data.gpencil_blank_texture) {
- float rect[1][1][4] = {{{0.0f}}};
- e_data.gpencil_blank_texture = DRW_texture_create_2d(
- 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
+ if (pd->do_fast_drawing) {
+ pd->snapshot_buffer_dirty = (txl->snapshot_color_tx == NULL);
+ const float *size = DRW_viewport_size_get();
+ DRW_texture_ensure_2d(&txl->snapshot_depth_tx, size[0], size[1], GPU_DEPTH24_STENCIL8, 0);
+ DRW_texture_ensure_2d(&txl->snapshot_color_tx, size[0], size[1], GPU_R11F_G11F_B10F, 0);
+ DRW_texture_ensure_2d(&txl->snapshot_reveal_tx, size[0], size[1], GPU_R11F_G11F_B10F, 0);
+
+ GPU_framebuffer_ensure_config(&fbl->snapshot_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->snapshot_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->snapshot_color_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->snapshot_reveal_tx),
+ });
}
- /* normal fill shader */
- if (!e_data.gpencil_fill_sh) {
- e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_fill_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_gpencil_fill_frag_glsl,
- NULL},
- });
+ else {
+ /* Free uneeded buffers. */
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->snapshot_fb);
+ DRW_TEXTURE_FREE_SAFE(txl->snapshot_depth_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->snapshot_color_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->snapshot_reveal_tx);
}
- /* normal stroke shader using geometry to display lines (line mode) */
- if (!e_data.gpencil_stroke_sh) {
- e_data.gpencil_stroke_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_stroke_vert_glsl, NULL},
- .geom = (const char *[]){datatoc_gpencil_stroke_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_gpencil_stroke_frag_glsl,
- NULL},
- });
- }
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ DRW_PASS_CREATE(psl->merge_depth_ps, state);
- /* dot/rectangle mode for normal strokes using geometry */
- if (!e_data.gpencil_point_sh) {
- e_data.gpencil_point_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_point_vert_glsl, NULL},
- .geom = (const char *[]){datatoc_gpencil_point_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_gpencil_point_frag_glsl,
- NULL},
- });
- }
- /* used for edit points or strokes with one point only */
- if (!e_data.gpencil_edit_point_sh) {
- e_data.gpencil_edit_point_sh = DRW_shader_create_with_lib(datatoc_gpencil_edit_point_vert_glsl,
- datatoc_gpencil_edit_point_geom_glsl,
- datatoc_gpencil_edit_point_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
+ GPUShader *sh = GPENCIL_shader_depth_merge_get();
+ grp = DRW_shgroup_create(sh, psl->merge_depth_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx);
+ DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1);
+ DRW_shgroup_uniform_vec4(grp, "gpModelMatrix[0]", pd->object_bound_mat[0], 4);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT;
+ DRW_PASS_CREATE(psl->mask_invert_ps, state);
- /* used for edit lines for edit modes */
- if (!e_data.gpencil_line_sh) {
- e_data.gpencil_line_sh = DRW_shader_create_with_lib(
- datatoc_gpencil_edit_point_vert_glsl,
- NULL,
- datatoc_gpu_shader_3D_smooth_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
+ GPUShader *sh = GPENCIL_shader_mask_invert_get();
+ grp = DRW_shgroup_create(sh, psl->mask_invert_ps);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- /* used to filling during drawing */
- if (!e_data.gpencil_drawing_fill_sh) {
- e_data.gpencil_drawing_fill_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
- }
+ Camera *cam = (pd->camera != NULL) ? pd->camera->data : NULL;
- /* full screen for mix zdepth*/
- if (!e_data.gpencil_fullscreen_sh) {
- e_data.gpencil_fullscreen_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_zdepth_mix_frag_glsl, NULL);
- }
- if (!e_data.gpencil_simple_fullscreen_sh) {
- e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_simple_mix_frag_glsl, NULL);
- }
+ /* Pseudo DOF setup. */
+ if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) {
+ const float *vp_size = DRW_viewport_size_get();
+ float fstop = cam->dof.aperture_fstop;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ float focus_dist = BKE_camera_object_dof_distance(pd->camera);
+ float focal_len = cam->lens;
- /* blend */
- if (!e_data.gpencil_blend_fullscreen_sh) {
- e_data.gpencil_blend_fullscreen_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_blend_frag_glsl, NULL);
- }
+ const float scale_camera = 0.001f;
+ /* we want radius here for the aperture number */
+ float aperture = 0.5f * scale_camera * focal_len / fstop;
+ float focal_len_scaled = scale_camera * focal_len;
+ float sensor_scaled = scale_camera * sensor;
- /* shaders for use when drawing */
- if (!e_data.gpencil_background_sh) {
- e_data.gpencil_background_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_background_frag_glsl, NULL);
+ if (draw_ctx->rv3d != NULL) {
+ sensor_scaled *= draw_ctx->rv3d->viewcamtexcofac[0];
+ }
+
+ pd->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
+ pd->dof_params[1] *= vp_size[0] / sensor_scaled;
+ pd->dof_params[0] = -focus_dist * pd->dof_params[1];
}
- if (!e_data.gpencil_paper_sh) {
- e_data.gpencil_paper_sh = DRW_shader_create_fullscreen(datatoc_gpencil_paper_frag_glsl, NULL);
+ else {
+ /* Disable DoF blur scalling. */
+ pd->camera = NULL;
}
}
-void GPENCIL_engine_init(void *vedata)
+#define DRAW_NOW 2
+
+typedef struct gpIterPopulateData {
+ Object *ob;
+ GPENCIL_tObject *tgp_ob;
+ GPENCIL_PrivateData *pd;
+ GPENCIL_MaterialPool *matpool;
+ DRWShadingGroup *grp;
+ /* Last material UBO bound. Used to avoid uneeded buffer binding. */
+ GPUUniformBuffer *ubo_mat;
+ GPUUniformBuffer *ubo_lights;
+ /* Last texture bound. */
+ GPUTexture *tex_fill;
+ GPUTexture *tex_stroke;
+ /* Offset in the material pool to the first material of this object. */
+ int mat_ofs;
+ /* Is the sbuffer call need to be issued. */
+ int do_sbuffer_call;
+ /* Indices to do correct insertion of the sbuffer stroke. */
+ int stroke_index_last;
+ int stroke_index_offset;
+ /* Infos for call batching. */
+ struct GPUBatch *geom;
+ bool instancing;
+ int vfirst, vcount;
+} gpIterPopulateData;
+
+#define DISABLE_BATCHING 0
+
+static void gpencil_drawcall_flush(gpIterPopulateData *iter)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- /* init storage */
- if (!stl->storage) {
- stl->storage = MEM_callocN(sizeof(GPENCIL_Storage), "GPENCIL_Storage");
- stl->storage->shade_render[0] = OB_RENDER;
- stl->storage->shade_render[1] = 0;
+#if !DISABLE_BATCHING
+ if (iter->geom != NULL) {
+ if (iter->instancing) {
+ DRW_shgroup_call_instance_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
+ }
+ else {
+ DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
+ }
}
+#endif
- /* Not supported anymore. */
- stl->storage->multisamples = 0;
-
- /* create shaders */
- GPENCIL_create_shaders();
- GPENCIL_create_fx_shaders(&e_data);
+ iter->geom = NULL;
+ iter->vfirst = -1;
+ iter->vcount = 0;
}
-static void GPENCIL_engine_free(void)
+/* Group drawcalls that are consecutive and with the same type. Reduces GPU driver overhead. */
+static void gp_drawcall_add(
+ gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count)
{
- /* only free custom shaders, builtin shaders are freed in blender close */
- DRW_SHADER_FREE_SAFE(e_data.gpencil_fill_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_line_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
-
- DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
-
- /* effects */
- GPENCIL_delete_fx_shaders(&e_data);
+#if DISABLE_BATCHING
+ if (instancing) {
+ DRW_shgroup_call_instance_range(iter->grp, iter->ob, geom, v_first, v_count);
+ }
+ else {
+ DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count);
+ }
+#endif
+
+ int last = iter->vfirst + iter->vcount;
+ /* Interupt drawcall grouping if the sequence is not consecutive. */
+ if ((geom != iter->geom) || (v_first - last > 3)) {
+ gpencil_drawcall_flush(iter);
+ }
+ iter->geom = geom;
+ iter->instancing = instancing;
+ if (iter->vfirst == -1) {
+ iter->vfirst = v_first;
+ }
+ iter->vcount = v_first + v_count - iter->vfirst;
}
-/* Helper: Check if the main overlay and onion switches are enabled in any screen.
- *
- * This is required to generate the onion skin and limit the times the cache is updated because the
- * cache is generated only in the first screen and if the first screen has the onion disabled the
- * cache for onion skin is not generated. The loop adds time, but always is faster than regenerate
- * the cache all the times.
- */
-static void gpencil_check_screen_switches(const DRWContextState *draw_ctx,
- GPENCIL_StorageList *stl)
+static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ void *thunk);
+
+static void gp_sbuffer_cache_populate(gpIterPopulateData *iter)
{
- stl->storage->is_main_overlay = false;
- stl->storage->is_main_onion = false;
- /* Check if main onion switch is enabled in any screen. */
- Main *bmain = CTX_data_main(draw_ctx->evil_C);
-
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- if (v3d == NULL) {
- continue;
- }
- if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
- stl->storage->is_main_overlay = true;
- }
- if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) {
- stl->storage->is_main_onion = true;
- }
- }
- /* If found, don't need loop more. */
- if ((stl->storage->is_main_overlay) && (stl->storage->is_main_onion)) {
- return;
- }
- }
- }
+ iter->do_sbuffer_call = DRAW_NOW;
+ /* In order to draw the sbuffer stroke correctly mixed with other strokes,
+ * we need to offset the stroke index of the sbuffer stroke and the subsequent strokes.
+ * Remember, sbuffer stroke indices start from 0. So we add last index to avoid
+ * masking issues. */
+ iter->grp = DRW_shgroup_create_sub(iter->grp);
+ DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", iter->ubo_mat);
+ DRW_shgroup_uniform_float_copy(iter->grp, "strokeIndexOffset", iter->stroke_index_last);
+
+ const DRWContextState *ctx = DRW_context_state_get();
+ ToolSettings *ts = ctx->scene->toolsettings;
+ if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) {
+ /* In this case we can't do correct projection during stroke. We just disable depth test. */
+ DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx);
+ }
+
+ gpencil_stroke_cache_populate(NULL, NULL, iter->pd->sbuffer_stroke, iter);
+ gpencil_drawcall_flush(iter);
+
+ iter->stroke_index_offset = iter->pd->sbuffer_stroke->totpoints + 1;
+ iter->do_sbuffer_call = 0;
}
-void GPENCIL_cache_init(void *vedata)
+static void gpencil_layer_cache_populate(bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *UNUSED(gps),
+ void *thunk)
{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
- View3D *v3d = draw_ctx->v3d;
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- const View3DCursor *cursor = &scene->cursor;
-
- /* Special handling for when active object is GP object (e.g. for draw mode) */
- Object *obact = draw_ctx->obact;
- bGPdata *obact_gpd = NULL;
- MaterialGPencilStyle *gp_style = NULL;
-
- if (obact && (obact->type == OB_GPENCIL) && (obact->data)) {
- obact_gpd = (bGPdata *)obact->data;
- /* use the brush material */
- Material *ma = BKE_gpencil_object_material_get_from_brush(obact, brush);
- if (ma != NULL) {
- gp_style = ma->gp_style;
- }
- /* this is not common, but avoid any special situations when brush could be without material */
- if (gp_style == NULL) {
- gp_style = BKE_gpencil_material_settings(obact, obact->actcol);
- }
- }
+ gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
+ GPENCIL_PrivateData *pd = iter->pd;
+ bGPdata *gpd = (bGPdata *)iter->ob->data;
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(g_data), "g_data");
- stl->storage->xray = GP_XRAY_FRONT; /* used for drawing */
- stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID; /* used for drawing */
+ gpencil_drawcall_flush(iter);
+
+ if (iter->do_sbuffer_call) {
+ gp_sbuffer_cache_populate(iter);
}
- stl->storage->tonemapping = 0;
-
- stl->g_data->shgrps_edit_line = NULL;
- stl->g_data->shgrps_edit_point = NULL;
-
- /* reset textures */
- stl->g_data->batch_buffer_stroke = NULL;
- stl->g_data->batch_buffer_fill = NULL;
- stl->g_data->batch_buffer_ctrlpoint = NULL;
- stl->g_data->batch_grid = NULL;
-
- if (!stl->shgroups) {
- /* Alloc maximum size because count strokes is very slow and can be very complex due onion
- * skinning.
- */
- stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup");
+ else {
+ iter->do_sbuffer_call = !pd->do_fast_drawing && (gpd == pd->sbuffer_gpd) &&
+ (gpl == pd->sbuffer_layer) &&
+ (gpf == NULL || gpf->runtime.onion_id == 0.0f);
}
- /* init gp objects cache */
- stl->g_data->gp_cache_used = 0;
- stl->g_data->gp_cache_size = 0;
- stl->g_data->gp_object_cache = NULL;
- stl->g_data->do_instances = false;
+ GPENCIL_tLayer *tgp_layer = gpencil_layer_cache_add(pd, iter->ob, gpl, gpf, iter->tgp_ob);
- {
- /* Stroke pass 2D */
- psl->stroke_pass_2d = DRW_pass_create("GPencil Stroke Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- stl->storage->shgroup_id = 0;
- /* Stroke pass 3D */
- psl->stroke_pass_3d = DRW_pass_create("GPencil Stroke Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- stl->storage->shgroup_id = 0;
-
- /* edit pass */
- psl->edit_pass = DRW_pass_create("GPencil Edit Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
-
- /* detect if playing animation */
- if (draw_ctx->evil_C) {
-
- bool playing = ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != NULL;
- if (playing != stl->storage->is_playing) {
- stl->storage->reset_cache = true;
- }
- stl->storage->is_playing = playing;
+ const bool use_lights = pd->use_lighting && ((gpl->flag & GP_LAYER_USE_LIGHTS) != 0) &&
+ (iter->ob->dtx & OB_USE_GPENCIL_LIGHTS);
- /* Found if main overlay and onion switches are enabled in any screen. */
- gpencil_check_screen_switches(draw_ctx, stl);
- }
- else {
- stl->storage->is_playing = false;
- stl->storage->reset_cache = false;
- stl->storage->is_main_overlay = false;
- stl->storage->is_main_onion = false;
- }
- /* save render state */
- stl->storage->is_render = DRW_state_is_scene_render();
- stl->storage->is_mat_preview = (bool)stl->storage->is_render &&
- STREQ(scene->id.name + 2, "preview");
-
- if (obact_gpd) {
- /* for some reason, when press play there is a delay in the animation flag check
- * and this produces errors. To be sure, we set cache as dirty because the frame
- * is changing.
- */
- if (stl->storage->is_playing == true) {
- obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- /* if render, set as dirty to update all data */
- else if (stl->storage->is_render == true) {
- obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- }
+ iter->ubo_lights = (use_lights) ? pd->global_light_pool->ubo : pd->shadeless_light_pool->ubo;
- /* save simplify flags (can change while drawing, so it's better to save) */
- stl->storage->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, stl->storage->is_playing);
- stl->storage->simplify_modif = GPENCIL_SIMPLIFY_MODIF(scene, stl->storage->is_playing);
- stl->storage->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, stl->storage->is_playing);
- stl->storage->simplify_blend = GPENCIL_SIMPLIFY_BLEND(scene, stl->storage->is_playing);
+ gpencil_material_resources_get(iter->matpool, 0, NULL, NULL, &iter->ubo_mat);
- /* xray mode */
- if (v3d) {
- stl->storage->is_xray = XRAY_ACTIVE(v3d);
- }
- else {
- stl->storage->is_xray = 0;
- }
+ /* Iterator dependent uniforms. */
+ DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp;
+ DRW_shgroup_uniform_block_persistent(grp, "gpLightBlock", iter->ubo_lights);
+ DRW_shgroup_uniform_block(grp, "gpMaterialBlock", iter->ubo_mat);
+ DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill);
+ DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke);
+ DRW_shgroup_uniform_int_copy(grp, "gpMaterialOffset", iter->mat_ofs);
+ DRW_shgroup_uniform_float_copy(grp, "strokeIndexOffset", iter->stroke_index_offset);
+}
- /* save pixsize */
- stl->storage->pixsize = DRW_viewport_pixelsize_get();
- if ((!DRW_state_is_opengl_render()) && (stl->storage->is_render)) {
- stl->storage->pixsize = &stl->storage->render_pixsize;
- }
+static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ void *thunk)
+{
+ gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
- /* detect if painting session */
- if ((obact_gpd) && (obact_gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
- (stl->storage->is_playing == false)) {
- /* need the original to avoid cow overhead while drawing */
- bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&obact_gpd->id);
- if (((gpd_orig->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) &&
- (gpd_orig->runtime.sbuffer_used > 0) &&
- ((gpd_orig->flag & GP_DATA_STROKE_POLYGON) == 0) && !DRW_state_is_depth() &&
- (stl->storage->background_ready == true)) {
- stl->g_data->session_flag |= GP_DRW_PAINT_PAINTING;
- }
- else {
- stl->g_data->session_flag = GP_DRW_PAINT_IDLE;
- }
- }
- else {
- /* if not drawing mode */
- stl->g_data->session_flag = GP_DRW_PAINT_HOLD;
- }
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
- if (gp_style) {
- stl->storage->stroke_style = gp_style->stroke_style;
- stl->storage->color_type = GPENCIL_COLOR_SOLID;
- if (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) {
- stl->storage->color_type = GPENCIL_COLOR_TEXTURE;
- if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
- stl->storage->color_type = GPENCIL_COLOR_PATTERN;
- }
- }
+ bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
+ bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
+ bool show_fill = (gps->tot_triangles > 0) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) &&
+ (!iter->pd->simplify_fill) && ((gps->flag & GP_STROKE_NOFILL) == 0);
+
+ bool only_lines = gpl && gpf && gpl->actframe != gpf && iter->pd->use_multiedit_lines_only;
+
+ if (hide_material || (!show_stroke && !show_fill) || only_lines) {
+ return;
+ }
+
+ GPUUniformBuffer *ubo_mat;
+ GPUTexture *tex_stroke, *tex_fill;
+ gpencil_material_resources_get(
+ iter->matpool, iter->mat_ofs + gps->mat_nr, &tex_stroke, &tex_fill, &ubo_mat);
+
+ bool resource_changed = (iter->ubo_mat != ubo_mat) ||
+ (tex_fill && (iter->tex_fill != tex_fill)) ||
+ (tex_stroke && (iter->tex_stroke != tex_stroke));
+
+ if (resource_changed) {
+ gpencil_drawcall_flush(iter);
+
+ iter->grp = DRW_shgroup_create_sub(iter->grp);
+ if (iter->ubo_mat != ubo_mat) {
+ DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", ubo_mat);
+ iter->ubo_mat = ubo_mat;
}
- else {
- stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID;
- stl->storage->color_type = GPENCIL_COLOR_SOLID;
+ if (tex_fill) {
+ DRW_shgroup_uniform_texture(iter->grp, "gpFillTexture", tex_fill);
+ iter->tex_fill = tex_fill;
}
-
- /* drawing buffer pass for drawing the stroke that is being drawing by the user. The data
- * is stored in sbuffer
- */
- psl->drawing_pass = DRW_pass_create("GPencil Drawing Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS |
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- /* full screen pass to combine the result with default framebuffer */
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
- psl->mix_pass = DRW_pass_create("GPencil Mix Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
- DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass);
- DRW_shgroup_call(mix_shgrp, quad, NULL);
- DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &stl->g_data->input_color_tx);
- DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &stl->g_data->input_depth_tx);
- DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
- DRW_shgroup_uniform_int(mix_shgrp, "do_select", &stl->storage->do_select_outline, 1);
- DRW_shgroup_uniform_vec4(mix_shgrp, "select_color", stl->storage->select_color, 1);
-
- /* Mix pass no blend used to copy between passes. A separated pass is required
- * because if mix_pass is used, the accumulation of blend degrade the colors.
- *
- * This pass is used too to take the snapshot used for background_pass. This image
- * will be used as the background while the user is drawing.
- */
- psl->mix_pass_noblend = DRW_pass_create("GPencil Mix Pass no blend",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS);
- DRWShadingGroup *mix_shgrp_noblend = DRW_shgroup_create(e_data.gpencil_fullscreen_sh,
- psl->mix_pass_noblend);
- DRW_shgroup_call(mix_shgrp_noblend, quad, NULL);
- DRW_shgroup_uniform_texture_ref(
- mix_shgrp_noblend, "strokeColor", &stl->g_data->input_color_tx);
- DRW_shgroup_uniform_texture_ref(
- mix_shgrp_noblend, "strokeDepth", &stl->g_data->input_depth_tx);
- DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 1);
- DRW_shgroup_uniform_int(mix_shgrp_noblend, "do_select", &stl->storage->do_select_outline, 1);
- DRW_shgroup_uniform_vec4(mix_shgrp_noblend, "select_color", stl->storage->select_color, 1);
-
- /* Painting session pass (used only to speedup while the user is drawing )
- * This pass is used to show the snapshot of the current grease pencil strokes captured
- * when the user starts to draw (see comments above).
- * In this way, the previous strokes don't need to be redraw and the drawing process
- * is far to agile.
- */
- psl->background_pass = DRW_pass_create("GPencil Background Painting Session Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
- DRWShadingGroup *background_shgrp = DRW_shgroup_create(e_data.gpencil_background_sh,
- psl->background_pass);
- DRW_shgroup_call(background_shgrp, quad, NULL);
- DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &txl->background_color_tx);
- DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &txl->background_depth_tx);
-
- /* pass for drawing paper (only if viewport)
- * In render, the v3d is null so the paper is disabled
- * The paper is way to isolate the drawing in complex scene and to have a cleaner
- * drawing area.
- */
- if (v3d) {
- psl->paper_pass = DRW_pass_create("GPencil Paper Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
- DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass);
- DRW_shgroup_call(paper_shgrp, quad, NULL);
- DRW_shgroup_uniform_vec3(paper_shgrp, "color", v3d->shading.background_color, 1);
- DRW_shgroup_uniform_float(paper_shgrp, "opacity", &v3d->overlay.gpencil_paper_opacity, 1);
+ if (tex_stroke) {
+ DRW_shgroup_uniform_texture(iter->grp, "gpStrokeTexture", tex_stroke);
+ iter->tex_stroke = tex_stroke;
}
- /* grid pass */
- if ((v3d) && (obact) && (obact->type == OB_GPENCIL)) {
- psl->grid_pass = DRW_pass_create("GPencil Grid Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
- stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
-
- /* define grid orientation */
- switch (ts->gp_sculpt.lock_axis) {
- case GP_LOCKAXIS_VIEW: {
- /* align always to view */
- invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat);
- /* copy ob location */
- copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]);
- break;
- }
- case GP_LOCKAXIS_CURSOR: {
- float scale[3] = {1.0f, 1.0f, 1.0f};
- loc_eul_size_to_mat4(
- stl->storage->grid_matrix, cursor->location, cursor->rotation_euler, scale);
- break;
- }
- default: {
- copy_m4_m4(stl->storage->grid_matrix, obact->obmat);
- break;
- }
- }
+ /* TODO(fclem): This is a quick workaround but
+ * ideally we should have this as a permanent bind. */
+ const bool is_masked = iter->tgp_ob->layers.last->mask_bits != NULL;
+ GPUTexture **mask_tex = (is_masked) ? &iter->pd->mask_tx : &iter->pd->dummy_tx;
+ DRW_shgroup_uniform_texture_ref(iter->grp, "gpMaskTexture", mask_tex);
+ }
- /* Move the origin to Object or Cursor */
- if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
- copy_v3_v3(stl->storage->grid_matrix[3], cursor->location);
- }
- else {
- copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]);
- }
- DRW_shgroup_uniform_mat4(
- stl->g_data->shgrps_grid, "gpModelMatrix", stl->storage->grid_matrix);
- }
+ bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW);
- /* blend layers pass */
- psl->blend_pass = DRW_pass_create("GPencil Blend Layers Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
- DRWShadingGroup *blend_shgrp = DRW_shgroup_create(e_data.gpencil_blend_fullscreen_sh,
- psl->blend_pass);
- DRW_shgroup_call(blend_shgrp, quad, NULL);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1);
- DRW_shgroup_uniform_int(blend_shgrp, "mask_layer", &stl->storage->mask_layer, 1);
- DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
-
- /* create effects passes */
- if (!stl->storage->simplify_fx) {
- GPENCIL_create_fx_passes(psl);
- }
+ if (show_fill) {
+ GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_fill_get(iter->ob) :
+ DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra);
+ int vfirst = gps->runtime.fill_start * 3;
+ int vcount = gps->tot_triangles * 3;
+ gp_drawcall_add(iter, geom, false, vfirst, vcount);
}
+
+ if (show_stroke) {
+ GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_stroke_get(iter->ob) :
+ DRW_cache_gpencil_strokes_get(iter->ob, iter->pd->cfra);
+ /* Start one vert before to have gl_InstanceID > 0 (see shader). */
+ int vfirst = gps->runtime.stroke_start - 1;
+ /* Include "potential" cyclic vertex and start adj vertex (see shader). */
+ int vcount = gps->totpoints + 1 + 1;
+ gp_drawcall_add(iter, geom, true, vfirst, vcount);
+ }
+
+ iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1;
}
-static void gpencil_add_draw_data(void *vedata, Object *ob)
+static void gp_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
+ bGPdata *gpd = (bGPdata *)iter->ob->data;
+ if (gpd != iter->pd->sbuffer_gpd) {
+ return;
+ }
- int i = stl->g_data->gp_cache_used - 1;
- tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
+ GPENCIL_TextureList *txl = vedata->txl;
+ GPUTexture *depth_texture = iter->pd->scene_depth_tx;
+ GPENCIL_tObject *last_tgp_ob = iter->pd->tobjects.last;
+ /* Create another temp object that only contain the stroke. */
+ iter->tgp_ob = gpencil_object_cache_add(iter->pd, iter->ob);
+ /* Remove from the main list. */
+ iter->pd->tobjects.last = last_tgp_ob;
+ last_tgp_ob->next = NULL;
+ /* Add to sbuffer tgpobject list. */
+ BLI_LINKS_APPEND(&iter->pd->sbuffer_tobjects, iter->tgp_ob);
+ /* Remove depth test with scene (avoid self occlusion). */
+ iter->pd->scene_depth_tx = txl->dummy_texture;
- if (!cache_ob->is_dup_ob) {
- /* fill shading groups */
- if ((!is_multiedit) || (stl->storage->is_render)) {
- gpencil_populate_datablock(&e_data, vedata, ob, cache_ob);
- }
- else {
- gpencil_populate_multiedit(&e_data, vedata, ob, cache_ob);
- }
- }
+ gpencil_layer_cache_populate(
+ iter->pd->sbuffer_layer, iter->pd->sbuffer_layer->actframe, NULL, iter);
- /* FX passses */
- cache_ob->has_fx = false;
- if ((!stl->storage->simplify_fx) &&
- ((!ELEM(cache_ob->shading_type[0], OB_WIRE, OB_SOLID)) ||
- ((v3d->spacetype != SPACE_VIEW3D))) &&
- (BKE_shaderfx_has_gpencil(ob))) {
- cache_ob->has_fx = true;
- if ((!stl->storage->simplify_fx) && (!is_multiedit)) {
- gpencil_fx_prepare(&e_data, vedata, cache_ob);
- }
+ const DRWContextState *ctx = DRW_context_state_get();
+ ToolSettings *ts = ctx->scene->toolsettings;
+ if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) {
+ /* In this case we can't do correct projection during stroke. We just disable depth test. */
+ DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx);
}
+
+ iter->do_sbuffer_call = DRAW_NOW;
+ gpencil_stroke_cache_populate(NULL, NULL, iter->pd->sbuffer_stroke, iter);
+ gpencil_drawcall_flush(iter);
+
+ gpencil_vfx_cache_populate(vedata, iter->ob, iter->tgp_ob);
+
+ /* Restore state. */
+ iter->do_sbuffer_call = 0;
+ iter->pd->scene_depth_tx = depth_texture;
}
-void GPENCIL_cache_populate(void *vedata, Object *ob)
+void GPENCIL_cache_populate(void *ved, Object *ob)
{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_TextureList *txl = vedata->txl;
+
/* object must be visible */
if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
return;
}
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
- View3D *v3d = draw_ctx->v3d;
+ if (ob->data && (ob->type == OB_GPENCIL) && (ob->dt >= OB_SOLID)) {
+ gpIterPopulateData iter = {0};
+ iter.ob = ob;
+ iter.pd = pd;
+ iter.tgp_ob = gpencil_object_cache_add(pd, ob);
+ iter.matpool = gpencil_material_pool_create(pd, ob, &iter.mat_ofs);
+ iter.tex_fill = txl->dummy_texture;
+ iter.tex_stroke = txl->dummy_texture;
- if (ob->type == OB_GPENCIL && ob->data) {
+ /* Special case for rendering onion skin. */
bGPdata *gpd = (bGPdata *)ob->data;
+ bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
- /* enable multisample and basic framebuffer creation */
- stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_MULTISAMPLE;
- stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_BASIC;
-
- /* when start/stop animation the cache must be set as dirty to reset all data */
- if (stl->storage->reset_cache) {
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- stl->storage->reset_cache = false;
- }
+ BKE_gpencil_visible_stroke_iter(ob,
+ gpencil_layer_cache_populate,
+ gpencil_stroke_cache_populate,
+ &iter,
+ do_onion,
+ pd->cfra);
- if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) {
- /* bound box object are not visible, only external box*/
- if (ob->dt != OB_BOUNDBOX) {
- /* save gp objects for drawing later */
- stl->g_data->gp_object_cache = gpencil_object_cache_add(stl->g_data->gp_object_cache,
- ob,
- &stl->g_data->gp_cache_size,
- &stl->g_data->gp_cache_used);
-
- /* enable instance loop */
- if (!stl->g_data->do_instances) {
- tGPencilObjectCache *cache_ob =
- &stl->g_data->gp_object_cache[stl->g_data->gp_cache_used - 1];
- stl->g_data->do_instances = cache_ob->is_dup_ob;
- }
-
- /* load drawing data */
- gpencil_add_draw_data(vedata, ob);
- }
- }
+ gpencil_drawcall_flush(&iter);
- /* draw current painting strokes
- * (only if region is equal to originated paint region)
- *
- * Need to use original data because to use the copy of data, the paint
- * operator must update depsgraph and this makes that first events of the
- * mouse are missed if the datablock is very big due the time required to
- * copy the datablock. The search of the original data is faster than a
- * full datablock copy.
- * Using the original data doesn't require a copy and the feel when drawing
- * is far better.
- */
-
- bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
- if ((draw_ctx->obact == ob) &&
- ((gpd_orig->runtime.ar == NULL) || (gpd_orig->runtime.ar == draw_ctx->region))) {
- gpencil_populate_buffer_strokes(&e_data, vedata, ts, ob);
+ if (iter.do_sbuffer_call) {
+ gp_sbuffer_cache_populate(&iter);
}
- /* grid */
- if ((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID) &&
- (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact) &&
- ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0) &&
- ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) == 0)) {
+ gpencil_vfx_cache_populate(vedata, ob, iter.tgp_ob);
- stl->g_data->batch_grid = gpencil_get_grid(ob);
- DRW_shgroup_call(stl->g_data->shgrps_grid, stl->g_data->batch_grid, NULL);
+ if (pd->do_fast_drawing) {
+ gp_sbuffer_cache_populate_fast(vedata, &iter);
}
}
+
+ if (ob->type == OB_LAMP && pd->use_lights) {
+ gpencil_light_pool_populate(pd->global_light_pool, ob);
+ }
}
-void GPENCIL_cache_finish(void *vedata)
+void GPENCIL_cache_finish(void *ved)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- tGPencilObjectCache *cache_ob = NULL;
- Object *ob = NULL;
-
- /* create data for instances */
- if (stl->g_data->do_instances) {
- GHash *gh_objects = BLI_ghash_str_new(__func__);
- /* create hash of real object (non duplicated) */
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- cache_ob = &stl->g_data->gp_object_cache[i];
- if (!cache_ob->is_dup_ob) {
- ob = cache_ob->ob;
- char *name = BKE_id_to_unique_string_key(&ob->id);
- BLI_ghash_insert(gh_objects, name, cache_ob->ob);
- }
- }
-
- /* draw particles */
- gpencil_populate_particles(&e_data, gh_objects, vedata);
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
- /* free hash */
- BLI_ghash_free(gh_objects, MEM_freeN, NULL);
+ /* Upload UBO data. */
+ BLI_memblock_iter iter;
+ BLI_memblock_iternew(pd->gp_material_pool, &iter);
+ GPENCIL_MaterialPool *pool;
+ while ((pool = (GPENCIL_MaterialPool *)BLI_memblock_iterstep(&iter))) {
+ GPU_uniformbuffer_update(pool->ubo, pool->mat_data);
}
- if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) {
- stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_DRAW;
+ BLI_memblock_iternew(pd->gp_light_pool, &iter);
+ GPENCIL_LightPool *lpool;
+ while ((lpool = (GPENCIL_LightPool *)BLI_memblock_iterstep(&iter))) {
+ GPU_uniformbuffer_update(lpool->ubo, lpool->light_data);
}
- /* create framebuffers (only for normal drawing) */
- if (!DRW_state_is_select() || !DRW_state_is_depth()) {
- GPENCIL_create_framebuffers(vedata);
+ /* Sort object by decreasing Z to avoid most of alpha ordering issues. */
+ gpencil_object_cache_sort(pd);
+
+ /* Create framebuffers only if needed. */
+ if (pd->tobjects.first) {
+ eGPUTextureFormat format = pd->use_signed_fb ? GPU_RGBA16F : GPU_R11F_G11F_B10F;
+
+ const float *size = DRW_viewport_size_get();
+ pd->depth_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
+ pd->color_tx = DRW_texture_pool_query_2d(size[0], size[1], format, &draw_engine_gpencil_type);
+ pd->reveal_tx = DRW_texture_pool_query_2d(size[0], size[1], format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->gpencil_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(pd->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->color_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->reveal_tx),
+ });
+
+ if (pd->use_layer_fb) {
+ pd->color_layer_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+ pd->reveal_layer_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->layer_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(pd->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->color_layer_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->reveal_layer_tx),
+ });
+ };
+
+ if (pd->use_object_fb) {
+ pd->color_object_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+ pd->reveal_object_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->object_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(pd->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->color_object_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->reveal_object_tx),
+ });
+ }
+
+ if (pd->use_mask_fb) {
+ /* We need an extra depth to not disturb the normal drawing.
+ * The color_tx is needed for framebuffer cmpleteness. */
+ GPUTexture *color_tx, *depth_tx;
+ depth_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
+ color_tx = DRW_texture_pool_query_2d(size[0], size[1], GPU_R8, &draw_engine_gpencil_type);
+ /* Use high quality format for render. */
+ eGPUTextureFormat mask_format = pd->is_render ? GPU_R16 : GPU_R8;
+ pd->mask_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], mask_format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->mask_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(depth_tx),
+ GPU_ATTACHMENT_TEXTURE(color_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->mask_tx),
+ });
+ }
+
+ GPENCIL_antialiasing_init(vedata);
}
}
-/* helper function to sort inverse gpencil objects using qsort */
-static int gpencil_object_cache_compare_zdepth(const void *a1, const void *a2)
+static void GPENCIL_draw_scene_depth_only(void *ved)
{
- const tGPencilObjectCache *ps1 = a1, *ps2 = a2;
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- if (ps1->zdepth < ps2->zdepth) {
- return 1;
- }
- else if (ps1->zdepth > ps2->zdepth) {
- return -1;
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
}
- return 0;
-}
-
-/* prepare a texture with full viewport screenshot for fast drawing */
-static void gpencil_prepare_fast_drawing(GPENCIL_StorageList *stl,
- DefaultFramebufferList *dfbl,
- GPENCIL_FramebufferList *fbl,
- DRWPass *pass,
- const float clearcol[4])
-{
- if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) {
- GPU_framebuffer_bind(fbl->background_fb);
- /* clean only in first loop cycle */
- if (stl->g_data->session_flag & GP_DRW_PAINT_IDLE) {
- GPU_framebuffer_clear_color_depth_stencil(fbl->background_fb, clearcol, 1.0f, 0x0);
- stl->g_data->session_flag = GP_DRW_PAINT_FILLING;
+ for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) {
+ for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) {
+ DRW_draw_pass(layer->geom_ps);
}
- /* repeat pass to fill temp texture */
- DRW_draw_pass(pass);
- /* set default framebuffer again */
+ }
+
+ if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ pd->gp_object_pool = pd->gp_layer_pool = pd->gp_vfx_pool = pd->gp_maskbit_pool = NULL;
- stl->storage->background_ready = true;
+ /* Free temp stroke buffers. */
+ if (pd->sbuffer_gpd) {
+ DRW_cache_gpencil_sbuffer_clear(pd->obact);
}
}
-void DRW_gpencil_free_runtime_data(void *ved)
+static void gpencil_draw_mask(GPENCIL_Data *vedata, GPENCIL_tObject *ob, GPENCIL_tLayer *layer)
{
- GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = vedata->psl;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ float clear_col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float clear_depth = ob->is_drawmode3d ? 1.0f : 0.0f;
+ bool inverted = false;
+ /* OPTI(fclem) we could optimize by only clearing if the new mask_bits does not contain all
+ * the masks already rendered in the buffer, and drawing only the layers not already drawn. */
+ bool cleared = false;
- /* free gpu data */
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_stroke);
- MEM_SAFE_FREE(stl->g_data->batch_buffer_stroke);
+ DRW_stats_group_start("GPencil Mask");
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_fill);
- MEM_SAFE_FREE(stl->g_data->batch_buffer_fill);
+ GPU_framebuffer_bind(fbl->mask_fb);
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_ctrlpoint);
- MEM_SAFE_FREE(stl->g_data->batch_buffer_ctrlpoint);
+ for (int i = 0; i < GP_MAX_MASKBITS; i++) {
+ if (!BLI_BITMAP_TEST(layer->mask_bits, i)) {
+ continue;
+ }
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_grid);
- MEM_SAFE_FREE(stl->g_data->batch_grid);
+ if (BLI_BITMAP_TEST_BOOL(layer->mask_invert_bits, i) != inverted) {
+ if (cleared) {
+ DRW_draw_pass(psl->mask_invert_ps);
+ }
+ inverted = !inverted;
+ }
- if (stl->g_data->gp_object_cache == NULL) {
- return;
+ if (!cleared) {
+ cleared = true;
+ GPU_framebuffer_clear_color_depth(fbl->mask_fb, clear_col, clear_depth);
+ }
+
+ GPENCIL_tLayer *mask_layer = gpencil_layer_cache_get(ob, i);
+ BLI_assert(mask_layer);
+
+ DRW_draw_pass(mask_layer->geom_ps);
}
- /* reset all cache flags */
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
- if (cache_ob) {
- bGPdata *gpd = cache_ob->gpd;
- gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
-
- /* free shgrp array */
- cache_ob->tot_layers = 0;
- MEM_SAFE_FREE(cache_ob->name);
- MEM_SAFE_FREE(cache_ob->shgrp_array);
- }
+ if (!inverted) {
+ /* Blend shader expect an opacity mask not a reavealage buffer. */
+ DRW_draw_pass(psl->mask_invert_ps);
}
- /* free the cache itself */
- MEM_SAFE_FREE(stl->g_data->gp_object_cache);
+ DRW_stats_group_end();
}
-static void gpencil_draw_pass_range(GPENCIL_FramebufferList *fbl,
- GPENCIL_StorageList *stl,
- GPENCIL_PassList *psl,
- GPUFrameBuffer *fb,
- Object *ob,
- bGPdata *gpd,
- DRWShadingGroup *init_shgrp,
- DRWShadingGroup *end_shgrp,
- bool multi)
+static void GPENCIL_draw_object(GPENCIL_Data *vedata, GPENCIL_tObject *ob)
{
- if (init_shgrp == NULL) {
- return;
+ GPENCIL_PassList *psl = vedata->psl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
+
+ DRW_stats_group_start("GPencil Object");
+
+ GPUFrameBuffer *fb_object = (ob->vfx.first) ? fbl->object_fb : fbl->gpencil_fb;
+
+ GPU_framebuffer_bind(fb_object);
+ GPU_framebuffer_clear_depth_stencil(fb_object, ob->is_drawmode3d ? 1.0f : 0.0f, 0x00);
+
+ if (ob->vfx.first) {
+ GPU_framebuffer_multi_clear(fb_object, clear_cols);
}
- const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi));
+ for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) {
+ if (layer->mask_bits) {
+ gpencil_draw_mask(vedata, ob, layer);
+ }
+
+ if (layer->blend_ps) {
+ GPU_framebuffer_bind(fbl->layer_fb);
+ GPU_framebuffer_multi_clear(fbl->layer_fb, clear_cols);
+ }
+ else {
+ GPU_framebuffer_bind(fb_object);
+ }
+
+ DRW_draw_pass(layer->geom_ps);
- if (do_antialiasing) {
- MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+ if (layer->blend_ps) {
+ GPU_framebuffer_bind(fb_object);
+ DRW_draw_pass(layer->blend_ps);
+ }
+ }
+
+ for (GPENCIL_tVfx *vfx = ob->vfx.first; vfx; vfx = vfx->next) {
+ GPU_framebuffer_bind(*(vfx->target_fb));
+ DRW_draw_pass(vfx->vfx_ps);
}
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
- init_shgrp,
- end_shgrp);
+ copy_m4_m4(pd->object_bound_mat, ob->plane_mat);
+ pd->is_stroke_order_3d = ob->is_drawmode3d;
- if (do_antialiasing) {
- MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
+ if (pd->scene_fb) {
+ GPU_framebuffer_bind(pd->scene_fb);
+ DRW_draw_pass(psl->merge_depth_ps);
}
+
+ DRW_stats_group_end();
}
-/* draw strokes to use for selection */
-static void drw_gpencil_select_render(GPENCIL_StorageList *stl, GPENCIL_PassList *psl)
+static void GPENCIL_fast_draw_start(GPENCIL_Data *vedata)
{
- tGPencilObjectCache *cache_ob;
- tGPencilObjectCache_shgrp *array_elm = NULL;
- DRWShadingGroup *init_shgrp = NULL;
- DRWShadingGroup *end_shgrp = NULL;
-
- /* Draw all pending objects */
- if ((stl->g_data->gp_cache_used > 0) && (stl->g_data->gp_object_cache)) {
- /* sort by zdepth */
- qsort(stl->g_data->gp_object_cache,
- stl->g_data->gp_cache_used,
- sizeof(tGPencilObjectCache),
- gpencil_object_cache_compare_zdepth);
-
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- cache_ob = &stl->g_data->gp_object_cache[i];
- if (cache_ob) {
- Object *ob = cache_ob->ob;
- bGPdata *gpd = cache_ob->gpd;
- init_shgrp = NULL;
- if (cache_ob->tot_layers > 0) {
- for (int e = 0; e < cache_ob->tot_layers; e++) {
- array_elm = &cache_ob->shgrp_array[e];
- if (init_shgrp == NULL) {
- init_shgrp = array_elm->init_shgrp;
- }
- end_shgrp = array_elm->end_shgrp;
- }
- /* draw group */
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d :
- psl->stroke_pass_2d,
- init_shgrp,
- end_shgrp);
- }
- /* the cache must be dirty for next loop */
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- }
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (!pd->snapshot_buffer_dirty) {
+ /* Copy back cached render. */
+ GPU_framebuffer_blit(fbl->snapshot_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
+ GPU_framebuffer_blit(fbl->snapshot_fb, 0, fbl->gpencil_fb, 0, GPU_COLOR_BIT);
+ GPU_framebuffer_blit(fbl->snapshot_fb, 1, fbl->gpencil_fb, 1, GPU_COLOR_BIT);
+ /* Bypass drawing. */
+ pd->tobjects.first = pd->tobjects.last = NULL;
}
}
-/* draw scene */
-void GPENCIL_draw_scene(void *ved)
+static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata)
{
- GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- tGPencilObjectCache *cache_ob;
- tGPencilObjectCache_shgrp *array_elm = NULL;
- DRWShadingGroup *init_shgrp = NULL;
- DRWShadingGroup *end_shgrp = NULL;
-
- const float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- Object *obact = draw_ctx->obact;
- const bool playing = stl->storage->is_playing;
- const bool is_render = stl->storage->is_render;
- bGPdata *gpd_act = (obact) && (obact->type == OB_GPENCIL) ? (bGPdata *)obact->data : NULL;
- const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd_act);
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
-
- /* if the draw is for select, do a basic drawing and return */
- if (DRW_state_is_select() || DRW_state_is_depth()) {
- drw_gpencil_select_render(stl, psl);
- return;
+ if (pd->snapshot_buffer_dirty) {
+ /* Save to snapshot buffer. */
+ GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->snapshot_fb, 0, GPU_DEPTH_BIT);
+ GPU_framebuffer_blit(fbl->gpencil_fb, 0, fbl->snapshot_fb, 0, GPU_COLOR_BIT);
+ GPU_framebuffer_blit(fbl->gpencil_fb, 1, fbl->snapshot_fb, 1, GPU_COLOR_BIT);
+ pd->snapshot_buffer_dirty = false;
}
-
- /* paper pass to display a comfortable area to draw over complex scenes with geometry */
- if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
- if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_PAPER)) {
- DRW_draw_pass(psl->paper_pass);
- }
+ /* Draw the sbuffer stroke(s). */
+ for (GPENCIL_tObject *ob = pd->sbuffer_tobjects.first; ob; ob = ob->next) {
+ GPENCIL_draw_object(vedata, ob);
}
+}
- /* if we have a painting session, we use fast viewport drawing method */
- if ((!is_render) && (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING)) {
- GPU_framebuffer_bind(dfbl->default_fb);
-
- if (obact->dt != OB_BOUNDBOX) {
- DRW_draw_pass(psl->background_pass);
- }
+void GPENCIL_draw_scene(void *ved)
+{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
- MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+ /* Fade 3D objects. */
+ if ((!pd->is_render) && (pd->fade_3d_object_opacity > -1.0f)) {
+ mul_v4_fl(clear_cols[1], pd->fade_3d_object_opacity);
+ }
- DRW_draw_pass(psl->drawing_pass);
+ if (pd->draw_depth_only) {
+ GPENCIL_draw_scene_depth_only(vedata);
+ return;
+ }
- MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, dfbl->default_fb, txl);
+ if (pd->tobjects.first == NULL) {
+ return;
+ }
- /* grid pass */
- if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
- if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID)) {
- DRW_draw_pass(psl->grid_pass);
- }
- }
+ if (pd->do_fast_drawing) {
+ GPENCIL_fast_draw_start(vedata);
+ }
- /* free memory */
- DRW_gpencil_free_runtime_data(ved);
+ if (pd->tobjects.first) {
+ GPU_framebuffer_bind(fbl->gpencil_fb);
+ GPU_framebuffer_multi_clear(fbl->gpencil_fb, clear_cols);
+ }
- return;
+ for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) {
+ GPENCIL_draw_object(vedata, ob);
}
- if (DRW_state_is_fbo()) {
+ if (pd->do_fast_drawing) {
+ GPENCIL_fast_draw_end(vedata);
+ }
- /* Draw all pending objects */
- if (stl->g_data->gp_cache_used > 0) {
- /* sort by zdepth */
- qsort(stl->g_data->gp_object_cache,
- stl->g_data->gp_cache_used,
- sizeof(tGPencilObjectCache),
- gpencil_object_cache_compare_zdepth);
-
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- cache_ob = &stl->g_data->gp_object_cache[i];
- Object *ob = cache_ob->ob;
- bGPdata *gpd = cache_ob->gpd;
- init_shgrp = NULL;
- /* Render stroke in separated framebuffer */
- GPU_framebuffer_bind(fbl->temp_fb_a);
- GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_a, clearcol, 1.0f, 0x0);
- /* Stroke Pass:
- * draw only a subset that usually starts with a fill and ends with stroke
- */
- bool use_blend = false;
- if (cache_ob->tot_layers > 0) {
- for (int e = 0; e < cache_ob->tot_layers; e++) {
- bool is_last = (e == cache_ob->tot_layers - 1) ? true : false;
- array_elm = &cache_ob->shgrp_array[e];
-
- if (((array_elm->mode == eGplBlendMode_Regular) && (!use_blend) &&
- (!array_elm->mask_layer)) ||
- (e == 0)) {
- if (init_shgrp == NULL) {
- init_shgrp = array_elm->init_shgrp;
- }
- end_shgrp = array_elm->end_shgrp;
- }
- else {
- use_blend = true;
- /* draw pending groups */
- gpencil_draw_pass_range(
- fbl, stl, psl, fbl->temp_fb_a, ob, gpd, init_shgrp, end_shgrp, is_last);
-
- /* Draw current group in separated texture to blend later */
- init_shgrp = array_elm->init_shgrp;
- end_shgrp = array_elm->end_shgrp;
-
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_fx, clearcol, 1.0f, 0x0);
- gpencil_draw_pass_range(
- fbl, stl, psl, fbl->temp_fb_fx, ob, gpd, init_shgrp, end_shgrp, is_last);
-
- /* Blend A texture and FX texture */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_b, clearcol, 1.0f, 0x0);
- stl->storage->blend_mode = array_elm->mode;
- stl->storage->mask_layer = (int)array_elm->mask_layer;
- stl->storage->tonemapping = 1;
- DRW_draw_pass(psl->blend_pass);
- stl->storage->tonemapping = 0;
-
- /* Copy B texture to A texture to follow loop */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
-
- GPU_framebuffer_bind(fbl->temp_fb_a);
- GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_a, clearcol, 1.0f, 0x0);
- DRW_draw_pass(psl->mix_pass_noblend);
-
- /* prepare next group */
- init_shgrp = NULL;
- }
- }
- /* last group */
- gpencil_draw_pass_range(
- fbl, stl, psl, fbl->temp_fb_a, ob, gpd, init_shgrp, end_shgrp, true);
- }
-
- /* Current buffer drawing */
- if ((!is_render) && (cache_ob->is_dup_ob == false)) {
- DRW_draw_pass(psl->drawing_pass);
- }
- /* fx passes */
- if (cache_ob->has_fx == true) {
- stl->storage->tonemapping = 0;
- gpencil_fx_draw(&e_data, vedata, cache_ob);
- }
-
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_a;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_a;
-
- /* Combine with scene buffer */
- if ((!is_render) || (fbl->main == NULL)) {
- GPU_framebuffer_bind(dfbl->default_fb);
- }
- else {
- GPU_framebuffer_bind(fbl->main);
- }
- /* tonemapping */
- stl->storage->tonemapping = 1;
-
- /* active select flag and selection color */
- if (!is_render) {
- UI_GetThemeColorShadeAlpha4fv(
- (ob == draw_ctx->obact) ? TH_ACTIVE : TH_SELECT, 0, -40, stl->storage->select_color);
- }
- stl->storage->do_select_outline = ((overlay) && (ob->base_flag & BASE_SELECTED) &&
- (ob->mode == OB_MODE_OBJECT) && (!is_render) &&
- (!playing) && (v3d->flag & V3D_SELECT_OUTLINE));
-
- /* if active object is not object mode, disable for all objects */
- if ((stl->storage->do_select_outline) && (draw_ctx->obact) &&
- (draw_ctx->obact->mode != OB_MODE_OBJECT)) {
- stl->storage->do_select_outline = 0;
- }
-
- /* draw mix pass */
- DRW_draw_pass(psl->mix_pass);
-
- /* disable select flag */
- stl->storage->do_select_outline = 0;
-
- /* prepare for fast drawing */
- if (!is_render) {
- if (!playing) {
- gpencil_prepare_fast_drawing(stl, dfbl, fbl, psl->mix_pass_noblend, clearcol);
- }
- }
- else {
- /* if render, the cache must be dirty for next loop */
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- }
- /* edit points */
- if ((!is_render) && (!playing) && (is_edit)) {
- DRW_draw_pass(psl->edit_pass);
- }
- }
- /* grid pass */
- if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
- if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID)) {
- DRW_draw_pass(psl->grid_pass);
- }
- }
+ if (pd->scene_fb) {
+ GPENCIL_antialiasing_draw(vedata);
}
- /* free memory */
- DRW_gpencil_free_runtime_data(ved);
- /* reset */
- if (DRW_state_is_fbo()) {
- /* attach again default framebuffer */
- if (!is_render) {
- GPU_framebuffer_bind(dfbl->default_fb);
- }
+ pd->gp_object_pool = pd->gp_layer_pool = pd->gp_vfx_pool = pd->gp_maskbit_pool = NULL;
- /* the temp texture is ready. Now we can use fast screen drawing */
- if (stl->g_data->session_flag & GP_DRW_PAINT_FILLING) {
- stl->g_data->session_flag = GP_DRW_PAINT_READY;
- }
+ /* Free temp stroke buffers. */
+ if (pd->sbuffer_gpd) {
+ DRW_cache_gpencil_sbuffer_clear(pd->obact);
}
}
+static void GPENCIL_engine_free(void)
+{
+ GPENCIL_shader_free();
+}
+
static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data);
DrawEngineType draw_engine_gpencil_type = {
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 44a30260343..4b6059f1474 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -23,6 +23,10 @@
#ifndef __GPENCIL_ENGINE_H__
#define __GPENCIL_ENGINE_H__
+#include "DNA_gpencil_types.h"
+
+#include "BLI_bitmap.h"
+
#include "GPU_batch.h"
extern DrawEngineType draw_engine_gpencil_type;
@@ -34,204 +38,201 @@ struct Object;
struct RenderEngine;
struct RenderLayer;
struct bGPDstroke;
-
+struct View3D;
+struct GpencilBatchCache;
struct GPUBatch;
struct GPUVertBuf;
struct GPUVertFormat;
-#define GPENCIL_MAX_SHGROUPS 65536
-#define GPENCIL_GROUPS_BLOCK_SIZE 1024
+/* used to convert pixel scale. */
+#define GPENCIL_PIXEL_FACTOR 2000.0f
/* used to expand VBOs. Size has a big impact in the speed */
#define GPENCIL_VBO_BLOCK_SIZE 128
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-/* *********** OBJECTS CACHE *********** */
-typedef struct tGPencilObjectCache_shgrp {
- /** type of blend (regular, add, mult, etc...) */
- int mode;
- /** flag to enable the layer clamping */
- bool mask_layer;
- /** factor to define the opacity of the layer */
- float blend_opacity;
- DRWShadingGroup *init_shgrp;
- DRWShadingGroup *end_shgrp;
-} tGPencilObjectCache_shgrp;
-
-/* used to save gpencil object data for drawing */
-typedef struct tGPencilObjectCache {
- struct Object *ob;
- struct bGPdata *gpd;
- int idx; /*original index, can change after sort */
- char *name;
-
- /* effects */
- bool has_fx;
- ListBase shader_fx;
- float pixfactor;
- DRWShadingGroup *fx_wave_sh;
- DRWShadingGroup *fx_blur_sh;
- DRWShadingGroup *fx_colorize_sh;
- DRWShadingGroup *fx_pixel_sh;
- DRWShadingGroup *fx_rim_sh;
- DRWShadingGroup *fx_shadow_sh;
- DRWShadingGroup *fx_glow_sh;
- DRWShadingGroup *fx_swirl_sh;
- DRWShadingGroup *fx_flip_sh;
- DRWShadingGroup *fx_light_sh;
-
- float loc[3];
- float obmat[4][4];
- float zdepth; /* z-depth value to sort gp object */
- bool is_dup_ob; /* flag to tag duplicate objects */
- float scale;
-
- /* shading type */
- int shading_type[2];
-
- /* GPU data size */
- int tot_vertex;
- int tot_triangles;
-
- /* Save shader groups by layer */
- int tot_layers;
- tGPencilObjectCache_shgrp *shgrp_array;
-
-} tGPencilObjectCache;
+#define GP_MAX_MASKBITS 256
+
+/* UBO structure. Watch out for padding. Must match GLSL declaration. */
+typedef struct gpMaterial {
+ float stroke_color[4];
+ float fill_color[4];
+ float fill_mix_color[4];
+ float fill_uv_transform[3][2], _pad0[2];
+ float stroke_texture_mix;
+ float stroke_u_scale;
+ float fill_texture_mix;
+ int flag;
+} gpMaterial;
+
+/* gpMaterial->flag */
+/* WATCH Keep in sync with GLSL declaration. */
+#define GP_STROKE_ALIGNMENT_STROKE 1
+#define GP_STROKE_ALIGNMENT_OBJECT 2
+#define GP_STROKE_ALIGNMENT_FIXED 3
+#define GP_STROKE_ALIGNMENT 0x3
+#define GP_STROKE_OVERLAP (1 << 2)
+#define GP_STROKE_TEXTURE_USE (1 << 3)
+#define GP_STROKE_TEXTURE_STENCIL (1 << 4)
+#define GP_STROKE_TEXTURE_PREMUL (1 << 5)
+#define GP_STROKE_DOTS (1 << 6)
+#define GP_FILL_TEXTURE_USE (1 << 10)
+#define GP_FILL_TEXTURE_PREMUL (1 << 11)
+#define GP_FILL_TEXTURE_CLIP (1 << 12)
+#define GP_FILL_GRADIENT_USE (1 << 13)
+#define GP_FILL_GRADIENT_RADIAL (1 << 14)
+
+#define GPENCIL_LIGHT_BUFFER_LEN 128
+
+/* UBO structure. Watch out for padding. Must match GLSL declaration. */
+typedef struct gpLight {
+ float color[3], type;
+ float right[3], spotsize;
+ float up[3], spotblend;
+ float forward[4];
+ float position[4];
+} gpLight;
+
+/* gpLight->type */
+/* WATCH Keep in sync with GLSL declaration. */
+#define GP_LIGHT_TYPE_POINT 0.0
+#define GP_LIGHT_TYPE_SPOT 1.0
+#define GP_LIGHT_TYPE_SUN 2.0
+#define GP_LIGHT_TYPE_AMBIENT 3.0
+
+BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16)
+BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
+
+/* *********** Draw Datas *********** */
+typedef struct GPENCIL_MaterialPool {
+ /* Linklist. */
+ struct GPENCIL_MaterialPool *next;
+ /* GPU representatin of materials. */
+ gpMaterial mat_data[GP_MATERIAL_BUFFER_LEN];
+ /* Matching ubo. */
+ struct GPUUniformBuffer *ubo;
+ /* Texture per material. NULL means none. */
+ struct GPUTexture *tex_fill[GP_MATERIAL_BUFFER_LEN];
+ struct GPUTexture *tex_stroke[GP_MATERIAL_BUFFER_LEN];
+ /* Number of material used in this pool. */
+ int used_count;
+} GPENCIL_MaterialPool;
+
+typedef struct GPENCIL_LightPool {
+ /* GPU representatin of materials. */
+ gpLight light_data[GPENCIL_LIGHT_BUFFER_LEN];
+ /* Matching ubo. */
+ struct GPUUniformBuffer *ubo;
+ /* Number of light in the pool. */
+ int light_used;
+} GPENCIL_LightPool;
+
+typedef struct GPENCIL_ViewLayerData {
+ /* GPENCIL_tObject */
+ struct BLI_memblock *gp_object_pool;
+ /* GPENCIL_tLayer */
+ struct BLI_memblock *gp_layer_pool;
+ /* GPENCIL_tVfx */
+ struct BLI_memblock *gp_vfx_pool;
+ /* GPENCIL_MaterialPool */
+ struct BLI_memblock *gp_material_pool;
+ /* GPENCIL_LightPool */
+ struct BLI_memblock *gp_light_pool;
+ /* BLI_bitmap */
+ struct BLI_memblock *gp_maskbit_pool;
+} GPENCIL_ViewLayerData;
+
+/* *********** GPencil *********** */
+
+typedef struct GPENCIL_tVfx {
+ /** Linklist */
+ struct GPENCIL_tVfx *next;
+ DRWPass *vfx_ps;
+ /* Framebuffer reference since it may not be allocated yet. */
+ GPUFrameBuffer **target_fb;
+} GPENCIL_tVfx;
+
+typedef struct GPENCIL_tLayer {
+ /** Linklist */
+ struct GPENCIL_tLayer *next;
+ /** Geometry pass (draw all strokes). */
+ DRWPass *geom_ps;
+ /** Blend pass to composite onto the target buffer (blends modes). NULL if not needed. */
+ DRWPass *blend_ps;
+ /** First shading group created for this layer. Contains all uniforms. */
+ DRWShadingGroup *base_shgrp;
+ /** Layer id of the mask. */
+ BLI_bitmap *mask_bits;
+ BLI_bitmap *mask_invert_bits;
+ /** Index in the layer list. Used as id for masking. */
+ int layer_id;
+} GPENCIL_tLayer;
+
+typedef struct GPENCIL_tObject {
+ /** Linklist */
+ struct GPENCIL_tObject *next;
+
+ struct {
+ GPENCIL_tLayer *first, *last;
+ } layers;
+
+ struct {
+ GPENCIL_tVfx *first, *last;
+ } vfx;
+
+ /* Distance to camera. Used for sorting. */
+ float camera_z;
+ /* Used for stroke thickness scaling. */
+ float object_scale;
+ /* Normal used for shading. Based on view angle. */
+ float plane_normal[3];
+ /* Used for drawing depth merge pass. */
+ float plane_mat[4][4];
+
+ bool is_drawmode3d;
+} GPENCIL_tObject;
/* *********** LISTS *********** */
-typedef struct GPENCIL_shgroup {
- int s_clamp;
- int stroke_style;
- int color_type;
- int mode;
- int texture_mix;
- int texture_flip;
- int texture_clamp;
- int fill_style;
- int keep_size;
- int caps_mode[2];
- float obj_scale;
- int xray_mode;
- int alignment_mode;
-
- float gradient_f;
- float gradient_s[2];
-
- float mix_stroke_factor;
-
- /* color of the wireframe */
- float wire_color[4];
- /* shading type and mode */
- int shading_type[2];
- int is_xray;
-} GPENCIL_shgroup;
-
-typedef struct GPENCIL_Storage {
- int shgroup_id; /* total elements */
- int stroke_style;
- int color_type;
- int mode;
- int xray;
- int keep_size;
- float obj_scale;
- float pixfactor;
- bool is_playing;
- bool is_render;
- bool is_mat_preview;
- bool is_main_overlay;
- bool is_main_onion;
- bool background_ready;
- int is_xray;
- bool is_ontop;
- bool reset_cache;
- const float *pixsize;
- float render_pixsize;
- int tonemapping;
- int do_select_outline;
- float select_color[4];
- short multisamples;
- float grid_matrix[4][4];
-
- short framebuffer_flag; /* flag what framebuffer need to create */
-
- int blend_mode;
- int mask_layer;
-
- /* simplify settings*/
- bool simplify_fill;
- bool simplify_modif;
- bool simplify_fx;
- bool simplify_blend;
-
- float gradient_f;
- float gradient_s[2];
- int alignment_mode;
-
- float mix_stroke_factor;
-
- /* Render Matrices and data */
- float view_vecs[2][4]; /* vec4[2] */
-
- int shade_render[2];
-
- Object *camera; /* camera pointer for render mode */
-} GPENCIL_Storage;
-
-typedef enum eGpencilFramebuffer_Flag {
- GP_FRAMEBUFFER_MULTISAMPLE = (1 << 0),
- GP_FRAMEBUFFER_BASIC = (1 << 1),
- GP_FRAMEBUFFER_DRAW = (1 << 2),
-} eGpencilFramebuffer_Flag;
-
typedef struct GPENCIL_StorageList {
- struct GPENCIL_Storage *storage;
- struct g_data *g_data;
- struct GPENCIL_shgroup *shgroups;
+ struct GPENCIL_PrivateData *pd;
} GPENCIL_StorageList;
typedef struct GPENCIL_PassList {
- struct DRWPass *stroke_pass_2d;
- struct DRWPass *stroke_pass_3d;
- struct DRWPass *edit_pass;
- struct DRWPass *drawing_pass;
- struct DRWPass *mix_pass;
- struct DRWPass *mix_pass_noblend;
- struct DRWPass *background_pass;
- struct DRWPass *paper_pass;
- struct DRWPass *grid_pass;
- struct DRWPass *blend_pass;
-
- /* effects */
- struct DRWPass *fx_shader_pass;
- struct DRWPass *fx_shader_pass_blend;
-
+ /* Composite the main GPencil buffer onto the rendered image. */
+ struct DRWPass *composite_ps;
+ /* Composite the object depth to the default depth buffer to occlude overlays. */
+ struct DRWPass *merge_depth_ps;
+ /* Invert mask buffer content. */
+ struct DRWPass *mask_invert_ps;
+ /* Anti-Aliasing. */
+ struct DRWPass *smaa_edge_ps;
+ struct DRWPass *smaa_weight_ps;
+ struct DRWPass *smaa_resolve_ps;
} GPENCIL_PassList;
typedef struct GPENCIL_FramebufferList {
- struct GPUFrameBuffer *main;
- struct GPUFrameBuffer *temp_fb_a;
- struct GPUFrameBuffer *temp_fb_b;
- struct GPUFrameBuffer *temp_fb_fx;
- struct GPUFrameBuffer *background_fb;
-
- struct GPUFrameBuffer *multisample_fb;
+ struct GPUFrameBuffer *render_fb;
+ struct GPUFrameBuffer *gpencil_fb;
+ struct GPUFrameBuffer *snapshot_fb;
+ struct GPUFrameBuffer *layer_fb;
+ struct GPUFrameBuffer *object_fb;
+ struct GPUFrameBuffer *mask_fb;
+ struct GPUFrameBuffer *smaa_edge_fb;
+ struct GPUFrameBuffer *smaa_weight_fb;
} GPENCIL_FramebufferList;
typedef struct GPENCIL_TextureList {
- struct GPUTexture *texture;
-
- /* multisample textures */
- struct GPUTexture *multisample_color;
- struct GPUTexture *multisample_depth;
-
- /* Background textures for speed-up drawing. */
- struct GPUTexture *background_depth_tx;
- struct GPUTexture *background_color_tx;
-
+ /* Dummy texture to avoid errors cause by empty sampler. */
+ struct GPUTexture *dummy_texture;
+ /* Snapshot for smoother drawing. */
+ struct GPUTexture *snapshot_depth_tx;
+ struct GPUTexture *snapshot_color_tx;
+ struct GPUTexture *snapshot_reveal_tx;
+ /* Textures used by Antialiasing. */
+ struct GPUTexture *smaa_area_tx;
+ struct GPUTexture *smaa_search_tx;
+ /* Textures used during render. Containing underlying rendered scene. */
+ struct GPUTexture *render_depth_tx;
+ struct GPUTexture *render_color_tx;
} GPENCIL_TextureList;
typedef struct GPENCIL_Data {
@@ -240,248 +241,175 @@ typedef struct GPENCIL_Data {
struct GPENCIL_TextureList *txl;
struct GPENCIL_PassList *psl;
struct GPENCIL_StorageList *stl;
-
- /* render textures */
- struct GPUTexture *render_depth_tx;
- struct GPUTexture *render_color_tx;
-
} GPENCIL_Data;
/* *********** STATIC *********** */
-typedef struct g_data {
- struct DRWShadingGroup *shgrps_edit_point;
- struct DRWShadingGroup *shgrps_edit_line;
- struct DRWShadingGroup *shgrps_drawing_stroke;
- struct DRWShadingGroup *shgrps_drawing_fill;
- struct DRWShadingGroup *shgrps_grid;
-
- int gp_cache_used; /* total objects in cache */
- int gp_cache_size; /* size of the cache */
- struct tGPencilObjectCache *gp_object_cache;
-
- /* for buffer only one batch is nedeed because the drawing is only of one stroke */
- GPUBatch *batch_buffer_stroke;
- GPUBatch *batch_buffer_fill;
- GPUBatch *batch_buffer_ctrlpoint;
-
- /* grid geometry */
- GPUBatch *batch_grid;
-
- /* runtime pointers texture */
- struct GPUTexture *input_depth_tx;
- struct GPUTexture *input_color_tx;
-
- /* working textures */
- struct GPUTexture *temp_color_tx_a;
- struct GPUTexture *temp_depth_tx_a;
-
- struct GPUTexture *temp_color_tx_b;
- struct GPUTexture *temp_depth_tx_b;
-
- struct GPUTexture *temp_color_tx_fx;
- struct GPUTexture *temp_depth_tx_fx;
-
- int session_flag;
- bool do_instances;
-
-} g_data; /* Transient data */
-
-/* flags for fast drawing support */
-typedef enum eGPsession_Flag {
- GP_DRW_PAINT_HOLD = (1 << 0),
- GP_DRW_PAINT_IDLE = (1 << 1),
- GP_DRW_PAINT_FILLING = (1 << 2),
- GP_DRW_PAINT_READY = (1 << 3),
- GP_DRW_PAINT_PAINTING = (1 << 4),
-} eGPsession_Flag;
-
-typedef struct GPENCIL_e_data {
- /* textures */
- struct GPUTexture *gpencil_blank_texture;
-
- /* general drawing shaders */
- struct GPUShader *gpencil_fill_sh;
- struct GPUShader *gpencil_stroke_sh;
- struct GPUShader *gpencil_point_sh;
- struct GPUShader *gpencil_edit_point_sh;
- struct GPUShader *gpencil_line_sh;
- struct GPUShader *gpencil_drawing_fill_sh;
- struct GPUShader *gpencil_fullscreen_sh;
- struct GPUShader *gpencil_simple_fullscreen_sh;
- struct GPUShader *gpencil_blend_fullscreen_sh;
- struct GPUShader *gpencil_background_sh;
- struct GPUShader *gpencil_paper_sh;
-
- /* effects */
- struct GPUShader *gpencil_fx_blur_sh;
- struct GPUShader *gpencil_fx_colorize_sh;
- struct GPUShader *gpencil_fx_flip_sh;
- struct GPUShader *gpencil_fx_glow_prepare_sh;
- struct GPUShader *gpencil_fx_glow_resolve_sh;
- struct GPUShader *gpencil_fx_light_sh;
- struct GPUShader *gpencil_fx_pixel_sh;
- struct GPUShader *gpencil_fx_rim_prepare_sh;
- struct GPUShader *gpencil_fx_rim_resolve_sh;
- struct GPUShader *gpencil_fx_shadow_prepare_sh;
- struct GPUShader *gpencil_fx_shadow_resolve_sh;
- struct GPUShader *gpencil_fx_swirl_sh;
- struct GPUShader *gpencil_fx_wave_sh;
-
-} GPENCIL_e_data; /* Engine data */
-
-/* GPUBatch Cache Element */
-typedef struct GpencilBatchCacheElem {
- GPUBatch *batch;
- GPUVertBuf *vbo;
- int vbo_len;
- /* attr ids */
- GPUVertFormat *format;
- uint pos_id;
- uint color_id;
- uint thickness_id;
- uint uvdata_id;
- uint prev_pos_id;
-
- /* size for VBO alloc */
- int tot_vertex;
-} GpencilBatchCacheElem;
-
-/* Defines each batch group to define later the shgroup */
-typedef struct GpencilBatchGroup {
- struct bGPDlayer *gpl; /* reference to original layer */
- struct bGPDframe *gpf; /* reference to original frame */
- struct bGPDstroke *gps; /* reference to original stroke */
- short type; /* type of element */
- bool onion; /* the group is part of onion skin */
- int vertex_idx; /* index of vertex data */
-} GpencilBatchGroup;
-
-typedef enum GpencilBatchGroup_Type {
- eGpencilBatchGroupType_Stroke = 1,
- eGpencilBatchGroupType_Point = 2,
- eGpencilBatchGroupType_Fill = 3,
- eGpencilBatchGroupType_Edit = 4,
- eGpencilBatchGroupType_Edlin = 5,
-} GpencilBatchGroup_Type;
-
-/* Runtime data for GPU and evaluated frames after applying modifiers */
-typedef struct GpencilBatchCache {
- GpencilBatchCacheElem b_stroke;
- GpencilBatchCacheElem b_point;
- GpencilBatchCacheElem b_fill;
- GpencilBatchCacheElem b_edit;
- GpencilBatchCacheElem b_edlin;
-
- /** Cache is dirty */
- bool is_dirty;
- /** Edit mode flag */
- bool is_editmode;
- /** Last cache frame */
- int cache_frame;
-
- /** Total groups in arrays */
- int grp_used;
- /** Max size of the array */
- int grp_size;
- /** Array of cache elements */
- struct GpencilBatchGroup *grp_cache;
-} GpencilBatchCache;
-
-/* general drawing functions */
-struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data,
- struct GPENCIL_Data *vedata,
- struct DRWPass *pass,
- struct GPUShader *shader,
- struct Object *ob,
- float (*obmat)[4],
- struct bGPdata *gpd,
- struct bGPDlayer *gpl,
- struct bGPDstroke *gps,
- struct MaterialGPencilStyle *gp_style,
- int id,
- bool onion,
- const float scale,
- const int shading_type[2]);
-void gpencil_populate_datablock(struct GPENCIL_e_data *e_data,
- void *vedata,
- struct Object *ob,
- struct tGPencilObjectCache *cache_ob);
-void gpencil_populate_buffer_strokes(struct GPENCIL_e_data *e_data,
- void *vedata,
- struct ToolSettings *ts,
- struct Object *ob);
-void gpencil_populate_multiedit(struct GPENCIL_e_data *e_data,
- void *vedata,
- struct Object *ob,
- struct tGPencilObjectCache *cache_ob);
-void gpencil_populate_particles(struct GPENCIL_e_data *e_data,
- struct GHash *gh_objects,
- void *vedata);
-
-void gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h);
-
-/* create geometry functions */
-void gpencil_get_point_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- short thickness,
- const float ink[4],
- const int follow_mode);
-void gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- short thickness,
- const float ink[4]);
-void gpencil_get_fill_geom(struct GpencilBatchCacheElem *be,
- struct Object *ob,
- struct bGPDstroke *gps,
- const float color[4]);
-void gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- float alpha,
- short dflag);
-void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- float alpha,
- const bool hide_select);
-
-struct GPUBatch *gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, short thickness);
-struct GPUBatch *gpencil_get_buffer_fill_geom(struct bGPdata *gpd);
-struct GPUBatch *gpencil_get_buffer_point_geom(struct bGPdata *gpd, short thickness);
-struct GPUBatch *gpencil_get_buffer_ctrlpoint_geom(struct bGPdata *gpd);
-struct GPUBatch *gpencil_get_grid(Object *ob);
-
-/* object cache functions */
-struct tGPencilObjectCache *gpencil_object_cache_add(struct tGPencilObjectCache *cache_array,
- struct Object *ob,
- int *gp_cache_size,
- int *gp_cache_used);
-
-bool gpencil_onion_active(struct bGPdata *gpd);
-
-/* shading groups cache functions */
-struct GpencilBatchGroup *gpencil_group_cache_add(struct GpencilBatchGroup *cache_array,
- struct bGPDlayer *gpl,
- struct bGPDframe *gpf,
- struct bGPDstroke *gps,
- const short type,
- const bool onion,
- const int vertex_idx,
- int *grp_size,
- int *grp_used);
+typedef struct GPENCIL_PrivateData {
+ /* Pointers copied from GPENCIL_ViewLayerData. */
+ struct BLI_memblock *gp_object_pool;
+ struct BLI_memblock *gp_layer_pool;
+ struct BLI_memblock *gp_vfx_pool;
+ struct BLI_memblock *gp_material_pool;
+ struct BLI_memblock *gp_light_pool;
+ struct BLI_memblock *gp_maskbit_pool;
+ /* Last used material pool. */
+ GPENCIL_MaterialPool *last_material_pool;
+ /* Last used light pool. */
+ GPENCIL_LightPool *last_light_pool;
+ /* Common lightpool containing all lights in the scene. */
+ GPENCIL_LightPool *global_light_pool;
+ /* Common lightpool containing one ambient white light. */
+ GPENCIL_LightPool *shadeless_light_pool;
+ /* Linked list of tObjects. */
+ struct {
+ GPENCIL_tObject *first, *last;
+ } tobjects, tobjects_infront;
+ /* Temp Textures (shared with other engines). */
+ GPUTexture *depth_tx;
+ GPUTexture *color_tx;
+ GPUTexture *color_layer_tx;
+ GPUTexture *color_object_tx;
+ /* Revealage is 1 - alpha */
+ GPUTexture *reveal_tx;
+ GPUTexture *reveal_layer_tx;
+ GPUTexture *reveal_object_tx;
+ /* Mask texture */
+ GPUTexture *mask_tx;
+ /* Anti-Aliasing. */
+ GPUTexture *smaa_edge_tx;
+ GPUTexture *smaa_weight_tx;
+ /* Pointer to dtxl->depth */
+ GPUTexture *scene_depth_tx;
+ GPUFrameBuffer *scene_fb;
+ /* Copy of txl->dummy_tx */
+ GPUTexture *dummy_tx;
+ /* Copy of v3d->shading.single_color. */
+ float v3d_single_color[3];
+ /* Copy of v3d->shading.color_type or -1 to ignore. */
+ int v3d_color_type;
+ /* Current frame */
+ int cfra;
+ /* If we are rendering for final render (F12). */
+ bool is_render;
+ /* If we are in viewport display (used for VFX). */
+ bool is_viewport;
+ /* True in selection and auto_depth drawing */
+ bool draw_depth_only;
+ /* Is shading set to wireframe. */
+ bool draw_wireframe;
+ /* Used by the depth merge step. */
+ int is_stroke_order_3d;
+ float object_bound_mat[4][4];
+ /* Used for computing object distance to camera. */
+ float camera_z_axis[3], camera_z_offset;
+ float camera_pos[3];
+ /* Pseudo depth of field parameter. Used to scale blur radius. */
+ float dof_params[2];
+ /* Used for DoF Setup. */
+ Object *camera;
+ /* Copy of draw_ctx->scene for convenience. */
+ struct Scene *scene;
+
+ /* Active object. */
+ Object *obact;
+ /* Object being in draw mode. */
+ struct bGPdata *sbuffer_gpd;
+ /* Layer to append the temp stroke to. */
+ struct bGPDlayer *sbuffer_layer;
+ /* Temporary stroke currently being drawn. */
+ struct bGPDstroke *sbuffer_stroke;
+ /* List of temp objects containing the stroke. */
+ struct {
+ GPENCIL_tObject *first, *last;
+ } sbuffer_tobjects;
+ /* Batches containing the temp stroke. */
+ GPUBatch *stroke_batch;
+ GPUBatch *fill_batch;
+ bool do_fast_drawing;
+ bool snapshot_buffer_dirty;
+
+ /* Display onion skinning */
+ bool do_onion;
+ /* simplify settings */
+ bool simplify_fill;
+ bool simplify_fx;
+ bool simplify_antialias;
+ /* Use scene lighting or flat shading (global setting). */
+ bool use_lighting;
+ /* Use physical lights or just ambient lighting. */
+ bool use_lights;
+ /* Do we need additional framebuffers? */
+ bool use_layer_fb;
+ bool use_object_fb;
+ bool use_mask_fb;
+ /* Some blend mode needs to add negative values.
+ * This is only supported if target texture is signed. */
+ bool use_signed_fb;
+ /* Use only lines for multiedit and not active frame. */
+ bool use_multiedit_lines_only;
+ /* Layer opacity for fading. */
+ float fade_layer_opacity;
+ /* Opacity for fading gpencil objects. */
+ float fade_gp_object_opacity;
+ /* Opacity for fading 3D objects. */
+ float fade_3d_object_opacity;
+ /* Mask opacity uniform. */
+ float mask_opacity;
+ /* Xray transparency in solid mode. */
+ float xray_alpha;
+ /* Mask invert uniform. */
+ int mask_invert;
+} GPENCIL_PrivateData;
/* geometry batch cache functions */
struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra);
-/* effects */
-void GPENCIL_create_fx_shaders(struct GPENCIL_e_data *e_data);
-void GPENCIL_delete_fx_shaders(struct GPENCIL_e_data *e_data);
-void GPENCIL_create_fx_passes(struct GPENCIL_PassList *psl);
+GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob);
+void gpencil_object_cache_sort(GPENCIL_PrivateData *pd);
-void gpencil_fx_prepare(struct GPENCIL_e_data *e_data,
- struct GPENCIL_Data *vedata,
- struct tGPencilObjectCache *cache_ob);
-void gpencil_fx_draw(struct GPENCIL_e_data *e_data,
- struct GPENCIL_Data *vedata,
- struct tGPencilObjectCache *cache_ob);
+GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
+ const Object *ob,
+ const bGPDlayer *gpl,
+ const bGPDframe *gpf,
+ GPENCIL_tObject *tgp_ob);
+GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number);
+
+GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs);
+void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
+ int mat_id,
+ struct GPUTexture **r_tex_stroke,
+ struct GPUTexture **r_tex_fill,
+ struct GPUUniformBuffer **r_ubo_mat);
+
+void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]);
+void gpencil_light_pool_populate(GPENCIL_LightPool *matpool, Object *ob);
+GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd);
+GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *ob);
+
+/* effects */
+void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob);
+
+/* Shaders */
+struct GPUShader *GPENCIL_shader_antialiasing(int stage);
+struct GPUShader *GPENCIL_shader_geometry_get(void);
+struct GPUShader *GPENCIL_shader_composite_get(void);
+struct GPUShader *GPENCIL_shader_layer_blend_get(void);
+struct GPUShader *GPENCIL_shader_mask_invert_get(void);
+struct GPUShader *GPENCIL_shader_depth_merge_get(void);
+struct GPUShader *GPENCIL_shader_fx_blur_get(void);
+struct GPUShader *GPENCIL_shader_fx_colorize_get(void);
+struct GPUShader *GPENCIL_shader_fx_composite_get(void);
+struct GPUShader *GPENCIL_shader_fx_transform_get(void);
+struct GPUShader *GPENCIL_shader_fx_glow_get(void);
+struct GPUShader *GPENCIL_shader_fx_pixelize_get(void);
+struct GPUShader *GPENCIL_shader_fx_rim_get(void);
+struct GPUShader *GPENCIL_shader_fx_shadow_get(void);
+
+void GPENCIL_shader_free(void);
+
+/* Antialiasing */
+void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata);
+void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata);
/* main functions */
void GPENCIL_engine_init(void *vedata);
@@ -493,43 +421,17 @@ void GPENCIL_draw_scene(void *vedata);
/* render */
void GPENCIL_render_init(struct GPENCIL_Data *ved,
struct RenderEngine *engine,
- struct Depsgraph *depsgraph);
+ struct RenderLayer *render_layer,
+ const struct Depsgraph *depsgraph,
+ const rcti *rect);
void GPENCIL_render_to_image(void *vedata,
struct RenderEngine *engine,
struct RenderLayer *render_layer,
const rcti *rect);
-/* TODO: GPXX workaround function to call free memory from draw manager while draw manager support
- * scene finish callback. */
-void DRW_gpencil_free_runtime_data(void *ved);
-
-/* Use of multisample framebuffers. */
-#define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) \
- { \
- if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \
- DRW_stats_query_start("GP Multisample Blit"); \
- GPU_framebuffer_bind(fbl->multisample_fb); \
- GPU_framebuffer_clear_color_depth_stencil( \
- fbl->multisample_fb, (const float[4]){0.0f}, 1.0f, 0x0); \
- DRW_stats_query_end(); \
- } \
- } \
- ((void)0)
-
-#define MULTISAMPLE_GP_SYNC_DISABLE(lvl, fbl, fb, txl) \
- { \
- if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \
- DRW_stats_query_start("GP Multisample Resolve"); \
- GPU_framebuffer_bind(fb); \
- DRW_stats_query_end(); \
- } \
- } \
- ((void)0)
-
-#define GPENCIL_3D_DRAWMODE(ob, gpd) \
- ((gpd) && (gpd->draw_mode == GP_DRAWMODE_3D) && ((ob->dtx & OB_DRAWXRAY) == 0))
-
-#define GPENCIL_USE_SOLID(stl) \
- ((stl) && ((stl->storage->is_render) || (stl->storage->is_mat_preview)))
+/* Draw Data. */
+void gpencil_light_pool_free(void *storage);
+void gpencil_material_pool_free(void *storage);
+GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void);
#endif /* __GPENCIL_ENGINE_H__ */
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 8c126310ea2..083b04c0600 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -33,66 +33,22 @@
#include "gpencil_engine.h"
-/* Get pixel size for render
- * This function uses the same calculation used for viewport, because if use
- * camera pixelsize, the result is not correct.
- */
-static float get_render_pixelsize(float persmat[4][4], int winx, int winy)
-{
- float v1[3], v2[3];
- float len_px, len_sc;
-
- v1[0] = persmat[0][0];
- v1[1] = persmat[1][0];
- v1[2] = persmat[2][0];
-
- v2[0] = persmat[0][1];
- v2[1] = persmat[1][1];
- v2[2] = persmat[2][1];
-
- len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
- len_sc = (float)MAX2(winx, winy);
-
- return len_px / len_sc;
-}
-
/* init render data */
-void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
+void GPENCIL_render_init(GPENCIL_Data *vedata,
+ RenderEngine *engine,
+ struct RenderLayer *render_layer,
+ const Depsgraph *depsgraph,
+ const rcti *rect)
{
- GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
- GPENCIL_StorageList *stl = vedata->stl;
GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_TextureList *txl = vedata->txl;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- /* In render mode the default framebuffer is not generated
- * because there is no viewport. So we need to manually create one
- * NOTE : use 32 bit format for precision in render mode.
- */
- /* create multisample framebuffer for AA */
- if (U.gpencil_multisamples > 0) {
- int rect_w = (int)viewport_size[0];
- int rect_h = (int)viewport_size[1];
- gpencil_multisample_ensure(vedata, rect_w, rect_h);
- }
-
- vedata->render_depth_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_gpencil_type);
- vedata->render_color_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA32F, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->main,
- {GPU_ATTACHMENT_TEXTURE(vedata->render_depth_tx),
- GPU_ATTACHMENT_TEXTURE(vedata->render_color_tx)});
-
- /* Alloc transient data. */
- if (!stl->g_data) {
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
-
/* Set the pers & view matrix. */
- float winmat[4][4], viewmat[4][4], viewinv[4][4], persmat[4][4];
+ float winmat[4][4], viewmat[4][4], viewinv[4][4];
struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
float frame = BKE_scene_frame_get(scene);
@@ -105,85 +61,101 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra
DRW_view_default_set(view);
DRW_view_set_active(view);
- DRW_view_persmat_get(NULL, persmat, false);
+ /* Create depth texture & color texture from render result. */
+ const char *viewname = RE_GetActiveRenderView(engine->re);
+ RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
+ RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
- /* calculate pixel size for render */
- stl->storage->render_pixsize = get_render_pixelsize(persmat, viewport_size[0], viewport_size[1]);
+ float *pix_z = (rpass_z_src) ? rpass_z_src->rect : NULL;
+ float *pix_col = (rpass_col_src) ? rpass_col_src->rect : NULL;
- /* INIT CACHE */
- GPENCIL_cache_init(vedata);
+ if (!pix_z || !pix_col) {
+ RE_engine_set_error_message(engine,
+ "Warning: To render grease pencil, enable Combined and Z passes.");
+ }
+
+ if (pix_z) {
+ /* Depth need to be remapped to [0..1] range. */
+ pix_z = MEM_dupallocN(pix_z);
+
+ int pix_ct = rpass_z_src->rectx * rpass_z_src->recty;
+
+ if (DRW_view_is_persp_get(view)) {
+ for (int i = 0; i < pix_ct; i++) {
+ pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2];
+ pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f);
+ }
+ }
+ else {
+ /* Keep in mind, near and far distance are negatives. */
+ float near = DRW_view_near_distance_get(view);
+ float far = DRW_view_far_distance_get(view);
+ float range_inv = 1.0f / fabsf(far - near);
+ for (int i = 0; i < pix_ct; i++) {
+ pix_z[i] = (pix_z[i] + near) * range_inv;
+ pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f);
+ }
+ }
+ }
+
+ const bool do_region = (scene->r.mode & R_BORDER) != 0;
+ const bool do_clear_z = !pix_z || do_region;
+ const bool do_clear_col = !pix_col || do_region;
+
+ /* FIXME(fclem): we have a precision loss in the depth buffer because of this reupload.
+ * Find where it comes from! */
+ txl->render_depth_tx = DRW_texture_create_2d(
+ size[0], size[1], GPU_DEPTH_COMPONENT24, 0, do_region ? NULL : pix_z);
+ txl->render_color_tx = DRW_texture_create_2d(
+ size[0], size[1], GPU_RGBA16F, 0, do_region ? NULL : pix_col);
+
+ GPU_framebuffer_ensure_config(&fbl->render_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->render_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->render_color_tx),
+ });
+
+ if (do_clear_z || do_clear_col) {
+ /* To avoid unpredictable result, clear buffers that have not be initialized. */
+ GPU_framebuffer_bind(fbl->render_fb);
+ if (do_clear_col) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_clear_color(fbl->render_fb, clear_col);
+ }
+ if (do_clear_z) {
+ GPU_framebuffer_clear_depth(fbl->render_fb, 1.0f);
+ }
+ }
+
+ if (do_region) {
+ int x = rect->xmin;
+ int y = rect->ymin;
+ int w = BLI_rcti_size_x(rect);
+ int h = BLI_rcti_size_y(rect);
+ if (pix_col) {
+ GPU_texture_update_sub(txl->render_color_tx, GPU_DATA_FLOAT, pix_col, x, y, 0, w, h, 0);
+ }
+ if (pix_z) {
+ GPU_texture_update_sub(txl->render_depth_tx, GPU_DATA_FLOAT, pix_z, x, y, 0, w, h, 0);
+ }
+ }
+
+ MEM_SAFE_FREE(pix_z);
}
/* render all objects and select only grease pencil */
static void GPENCIL_render_cache(void *vedata,
struct Object *ob,
struct RenderEngine *UNUSED(engine),
- struct Depsgraph *UNUSED(depsgraph))
+ Depsgraph *UNUSED(depsgraph))
{
- if (ob && ob->type == OB_GPENCIL) {
+ if (ob && ELEM(ob->type, OB_GPENCIL, OB_LAMP)) {
if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) {
GPENCIL_cache_populate(vedata, ob);
}
}
}
-/* TODO: Reuse Eevee code in shared module instead to duplicate here */
-static void GPENCIL_render_update_viewvecs(float invproj[4][4],
- const float winmat[4][4],
- float (*r_viewvecs)[4])
-{
- /* view vectors for the corners of the view frustum.
- * Can be used to recreate the world space position easily */
- float view_vecs[4][4] = {
- {-1.0f, -1.0f, -1.0f, 1.0f},
- {1.0f, -1.0f, -1.0f, 1.0f},
- {-1.0f, 1.0f, -1.0f, 1.0f},
- {-1.0f, -1.0f, 1.0f, 1.0f},
- };
-
- /* convert the view vectors to view space */
- const bool is_persp = (winmat[3][3] == 0.0f);
- for (int i = 0; i < 4; i++) {
- mul_project_m4_v3(invproj, view_vecs[i]);
- /* normalized trick see:
- * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
- if (is_persp) {
- /* Divide XY by Z. */
- mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]);
- }
- }
-
- /**
- * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
- * view_vecs[1] is the vector going from the near-bottom-left corner to
- * the far-top-right corner.
- * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
- * when Z = 1, and top-left corner if Z = 1.
- * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
- * distance from the near plane to the far clip plane.
- */
- copy_v4_v4(r_viewvecs[0], view_vecs[0]);
-
- /* we need to store the differences */
- r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0];
- r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
- r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
-}
-
-/* Update view_vecs */
-static void GPENCIL_render_update_vecs(GPENCIL_Data *vedata)
-{
- GPENCIL_StorageList *stl = vedata->stl;
-
- float invproj[4][4], winmat[4][4];
- DRW_view_winmat_get(NULL, winmat, false);
- DRW_view_winmat_get(NULL, invproj, true);
-
- /* this is separated to keep function equal to Eevee for future reuse of same code */
- GPENCIL_render_update_viewvecs(invproj, winmat, stl->storage->view_vecs);
-}
-
-/* read z-depth render result */
static void GPENCIL_render_result_z(struct RenderLayer *rl,
const char *viewname,
GPENCIL_Data *vedata,
@@ -191,45 +163,52 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
- GPENCIL_StorageList *stl = vedata->stl;
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
- GPU_framebuffer_read_depth(vedata->fbl->main,
+ GPU_framebuffer_read_depth(vedata->fbl->render_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
rp->rect);
- bool is_persp = DRW_view_is_persp_get(NULL);
-
- GPENCIL_render_update_vecs(vedata);
-
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
+ int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+
/* Convert ogl depth [0..1] to view Z [near..far] */
- for (int i = 0; i < BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); i++) {
- if (rp->rect[i] == 1.0f) {
- rp->rect[i] = 1e10f; /* Background */
- }
- else {
- if (is_persp) {
+ if (DRW_view_is_persp_get(NULL)) {
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
}
+ }
+ }
+ else {
+ /* Keep in mind, near and far distance are negatives. */
+ float near = DRW_view_near_distance_get(NULL);
+ float far = DRW_view_far_distance_get(NULL);
+ float range = fabsf(far - near);
+
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
else {
- rp->rect[i] = -stl->storage->view_vecs[0][2] +
- rp->rect[i] * -stl->storage->view_vecs[1][2];
+ rp->rect[i] = -rp->rect[i] * range + near;
}
}
}
}
}
-/* read combined render result */
static void GPENCIL_render_result_combined(struct RenderLayer *rl,
const char *viewname,
GPENCIL_Data *vedata,
@@ -238,8 +217,8 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl,
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- GPU_framebuffer_bind(fbl->main);
- GPU_framebuffer_read_color(vedata->fbl->main,
+ GPU_framebuffer_bind(fbl->render_fb);
+ GPU_framebuffer_read_color(vedata->fbl->render_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
@@ -249,135 +228,31 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl,
rp->rect);
}
-/* helper to blend pixels */
-static void blend_pixel(float top_color[4], float bottom_color[4], float dst_color[4])
-{
- float alpha = top_color[3];
-
- /* use blend: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA */
- dst_color[0] = (top_color[0] * alpha) + (bottom_color[0] * (1.0f - alpha));
- dst_color[1] = (top_color[1] * alpha) + (bottom_color[1] * (1.0f - alpha));
- dst_color[2] = (top_color[2] * alpha) + (bottom_color[2] * (1.0f - alpha));
-}
-
-/* render grease pencil to image */
-void GPENCIL_render_to_image(void *vedata,
+void GPENCIL_render_to_image(void *ved,
RenderEngine *engine,
struct RenderLayer *render_layer,
const rcti *rect)
{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
const char *viewname = RE_GetActiveRenderView(engine->re);
const DRWContextState *draw_ctx = DRW_context_state_get();
- int imgsize = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
-
- /* save previous render data */
- RenderPass *rpass_color_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
- RenderPass *rpass_depth_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
- float *src_rect_color_data = NULL;
- float *src_rect_depth_data = NULL;
- if ((rpass_color_src) && (rpass_depth_src) && (rpass_color_src->rect) &&
- (rpass_depth_src->rect)) {
- src_rect_color_data = MEM_dupallocN(rpass_color_src->rect);
- src_rect_depth_data = MEM_dupallocN(rpass_depth_src->rect);
- }
- else {
- /* TODO: put this message in a better place */
- printf("Warning: To render grease pencil, enable Combined and Z passes.\n");
- }
+ Depsgraph *depsgraph = draw_ctx->depsgraph;
+ GPENCIL_render_init(vedata, engine, render_layer, depsgraph, rect);
GPENCIL_engine_init(vedata);
- GPENCIL_render_init(vedata, engine, draw_ctx->depsgraph);
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- Object *camera = DEG_get_evaluated_object(draw_ctx->depsgraph, RE_GetCamera(engine->re));
- stl->storage->camera = camera; /* save current camera */
-
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- if (fbl->main) {
- GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx, 0, 0);
- GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx, 0, 0);
- /* clean first time the buffer */
- float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- GPU_framebuffer_bind(fbl->main);
- GPU_framebuffer_clear_color_depth(fbl->main, clearcol, 1.0f);
- }
-
- /* loop all objects and draw */
- DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
+ vedata->stl->pd->camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
+ /* Loop over all objects and create draw structure. */
+ GPENCIL_cache_init(vedata);
+ DRW_render_object_iter(vedata, engine, depsgraph, GPENCIL_render_cache);
GPENCIL_cache_finish(vedata);
DRW_render_instance_buffer_finish();
+ /* Render the gpencil object and merge the result to the underlying render. */
GPENCIL_draw_scene(vedata);
- /* combined data */
GPENCIL_render_result_combined(render_layer, viewname, vedata, rect);
- /* z-depth data */
GPENCIL_render_result_z(render_layer, viewname, vedata, rect);
-
- /* detach textures */
- if (fbl->main) {
- GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx);
- GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx);
- }
-
- /* merge previous render image with new GP image */
- if (src_rect_color_data) {
- RenderPass *rpass_color_gp = RE_pass_find_by_name(
- render_layer, RE_PASSNAME_COMBINED, viewname);
- RenderPass *rpass_depth_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
- float *gp_rect_color_data = rpass_color_gp->rect;
- float *gp_rect_depth_data = rpass_depth_gp->rect;
- float *gp_pixel_rgba;
- float *gp_pixel_depth;
- float *src_pixel_rgba;
- float *src_pixel_depth;
-
- for (int i = 0; i < imgsize; i++) {
- gp_pixel_rgba = &gp_rect_color_data[i * 4];
- gp_pixel_depth = &gp_rect_depth_data[i];
-
- src_pixel_rgba = &src_rect_color_data[i * 4];
- src_pixel_depth = &src_rect_depth_data[i];
-
- /* check grease pencil render transparency */
- if (gp_pixel_rgba[3] > 0.0f) {
- if (src_pixel_rgba[3] > 0.0f) {
- /* check z-depth */
- if (gp_pixel_depth[0] > src_pixel_depth[0]) {
- /* copy source z-depth */
- gp_pixel_depth[0] = src_pixel_depth[0];
- /* blend object on top */
- if (src_pixel_rgba[3] < 1.0f) {
- blend_pixel(src_pixel_rgba, gp_pixel_rgba, gp_pixel_rgba);
- }
- else {
- copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
- }
- }
- else {
- /* blend gp render */
- if (gp_pixel_rgba[3] < 1.0f) {
- /* premult alpha factor to remove double blend effects */
- mul_v3_fl(gp_pixel_rgba, 1.0f / gp_pixel_rgba[3]);
-
- blend_pixel(gp_pixel_rgba, src_pixel_rgba, gp_pixel_rgba);
-
- gp_pixel_rgba[3] = gp_pixel_rgba[3] > src_pixel_rgba[3] ? gp_pixel_rgba[3] :
- src_pixel_rgba[3];
- }
- }
- }
- }
- else {
- copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
- gp_pixel_depth[0] = src_pixel_depth[0];
- }
- }
-
- /* free memory */
- MEM_SAFE_FREE(src_rect_color_data);
- MEM_SAFE_FREE(src_rect_depth_data);
- }
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader.c b/source/blender/draw/engines/gpencil/gpencil_shader.c
new file mode 100644
index 00000000000..8c7ba42a70e
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_shader.c
@@ -0,0 +1,311 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+#include "DRW_render.h"
+
+#include "gpencil_engine.h"
+
+extern char datatoc_gpencil_common_lib_glsl[];
+extern char datatoc_gpencil_frag_glsl[];
+extern char datatoc_gpencil_vert_glsl[];
+extern char datatoc_gpencil_antialiasing_frag_glsl[];
+extern char datatoc_gpencil_antialiasing_vert_glsl[];
+extern char datatoc_gpencil_layer_blend_frag_glsl[];
+extern char datatoc_gpencil_mask_invert_frag_glsl[];
+extern char datatoc_gpencil_depth_merge_frag_glsl[];
+extern char datatoc_gpencil_depth_merge_vert_glsl[];
+extern char datatoc_gpencil_vfx_frag_glsl[];
+
+extern char datatoc_common_colormanagement_lib_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_common_smaa_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+static struct {
+ /* SMAA antialiasing */
+ GPUShader *antialiasing_sh[3];
+ /* GPencil Object rendering */
+ GPUShader *gpencil_sh;
+ /* Final Compositing over rendered background. */
+ GPUShader *composite_sh;
+ /* All layer blend types in one shader! */
+ GPUShader *layer_blend_sh;
+ /* Merge the final object depth to the depth buffer. */
+ GPUShader *depth_merge_sh;
+ /* Invert the content of the mask buffer. */
+ GPUShader *mask_invert_sh;
+ /* Effects. */
+ GPUShader *fx_composite_sh;
+ GPUShader *fx_colorize_sh;
+ GPUShader *fx_blur_sh;
+ GPUShader *fx_glow_sh;
+ GPUShader *fx_pixel_sh;
+ GPUShader *fx_rim_sh;
+ GPUShader *fx_shadow_sh;
+ GPUShader *fx_transform_sh;
+ /* general drawing shaders */
+ GPUShader *gpencil_fill_sh;
+ GPUShader *gpencil_stroke_sh;
+ GPUShader *gpencil_point_sh;
+ GPUShader *gpencil_edit_point_sh;
+ GPUShader *gpencil_line_sh;
+ GPUShader *gpencil_drawing_fill_sh;
+ GPUShader *gpencil_fullscreen_sh;
+ GPUShader *gpencil_simple_fullscreen_sh;
+ GPUShader *gpencil_blend_fullscreen_sh;
+ GPUShader *gpencil_background_sh;
+ GPUShader *gpencil_paper_sh;
+} g_shaders = {{NULL}};
+
+void GPENCIL_shader_free(void)
+{
+ GPUShader **sh_data_as_array = (GPUShader **)&g_shaders;
+ for (int i = 0; i < (sizeof(g_shaders) / sizeof(GPUShader *)); i++) {
+ DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
+ }
+}
+
+GPUShader *GPENCIL_shader_antialiasing(int stage)
+{
+ BLI_assert(stage < 3);
+
+ if (!g_shaders.antialiasing_sh[stage]) {
+ char stage_define[32];
+ BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
+
+ g_shaders.antialiasing_sh[stage] = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 1\n",
+ "#define SMAA_INCLUDE_PS 0\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_gpencil_antialiasing_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 0\n",
+ "#define SMAA_INCLUDE_PS 1\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_gpencil_antialiasing_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define SMAA_GLSL_3\n",
+ "#define SMAA_RT_METRICS viewportMetrics\n",
+ "#define SMAA_PRESET_HIGH\n",
+ "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 0.0)\n",
+ "#define SMAA_NO_DISCARD\n",
+ stage_define,
+ NULL,
+ },
+ });
+ }
+ return g_shaders.antialiasing_sh[stage];
+}
+
+GPUShader *GPENCIL_shader_geometry_get(void)
+{
+ if (!g_shaders.gpencil_sh) {
+ g_shaders.gpencil_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_view_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_common_colormanagement_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define GP_MATERIAL_BUFFER_LEN " STRINGIFY(GP_MATERIAL_BUFFER_LEN) "\n",
+ "#define GPENCIL_LIGHT_BUFFER_LEN " STRINGIFY(GPENCIL_LIGHT_BUFFER_LEN) "\n",
+ "#define UNIFORM_RESOURCE_ID\n",
+ NULL,
+ },
+ });
+ }
+ return g_shaders.gpencil_sh;
+}
+
+GPUShader *GPENCIL_shader_layer_blend_get(void)
+{
+ if (!g_shaders.layer_blend_sh) {
+ g_shaders.layer_blend_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_layer_blend_frag_glsl,
+ NULL,
+ },
+ });
+ }
+ return g_shaders.layer_blend_sh;
+}
+
+GPUShader *GPENCIL_shader_mask_invert_get(void)
+{
+ if (!g_shaders.mask_invert_sh) {
+ g_shaders.mask_invert_sh = DRW_shader_create_fullscreen(datatoc_gpencil_mask_invert_frag_glsl,
+ NULL);
+ }
+ return g_shaders.mask_invert_sh;
+}
+
+GPUShader *GPENCIL_shader_depth_merge_get(void)
+{
+ if (!g_shaders.depth_merge_sh) {
+ g_shaders.depth_merge_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_view_lib_glsl,
+ datatoc_gpencil_depth_merge_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_depth_merge_frag_glsl,
+ NULL,
+ },
+ });
+ }
+ return g_shaders.depth_merge_sh;
+}
+
+/* ------- FX Shaders --------- */
+
+GPUShader *GPENCIL_shader_fx_blur_get(void)
+{
+ if (!g_shaders.fx_blur_sh) {
+ g_shaders.fx_blur_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define BLUR\n");
+ }
+ return g_shaders.fx_blur_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_colorize_get(void)
+{
+ if (!g_shaders.fx_colorize_sh) {
+ g_shaders.fx_colorize_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define COLORIZE\n");
+ }
+ return g_shaders.fx_colorize_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_composite_get(void)
+{
+ if (!g_shaders.fx_composite_sh) {
+ g_shaders.fx_composite_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define COMPOSITE\n");
+ }
+ return g_shaders.fx_composite_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_glow_get(void)
+{
+ if (!g_shaders.fx_glow_sh) {
+ g_shaders.fx_glow_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_vfx_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define GLOW\n",
+ NULL,
+ },
+ });
+ }
+ return g_shaders.fx_glow_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_pixelize_get(void)
+{
+ if (!g_shaders.fx_pixel_sh) {
+ g_shaders.fx_pixel_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define PIXELIZE\n");
+ }
+ return g_shaders.fx_pixel_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_rim_get(void)
+{
+ if (!g_shaders.fx_rim_sh) {
+ g_shaders.fx_rim_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_vfx_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define RIM\n",
+ NULL,
+ },
+ });
+ }
+ return g_shaders.fx_rim_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_shadow_get(void)
+{
+ if (!g_shaders.fx_shadow_sh) {
+ g_shaders.fx_shadow_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define SHADOW\n");
+ }
+ return g_shaders.fx_shadow_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_transform_get(void)
+{
+ if (!g_shaders.fx_transform_sh) {
+ g_shaders.fx_transform_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define TRANSFORM\n");
+ }
+ return g_shaders.fx_transform_sh;
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index f6a62e0d472..9467efcd18c 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -26,28 +26,17 @@
#include "BKE_gpencil.h"
+#include "BLI_link_utils.h"
+#include "BLI_memblock.h"
+
#include "DRW_render.h"
#include "BKE_camera.h"
#include "gpencil_engine.h"
-extern char datatoc_gpencil_fx_blur_frag_glsl[];
-extern char datatoc_gpencil_fx_colorize_frag_glsl[];
-extern char datatoc_gpencil_fx_flip_frag_glsl[];
-extern char datatoc_gpencil_fx_light_frag_glsl[];
-extern char datatoc_gpencil_fx_pixel_frag_glsl[];
-extern char datatoc_gpencil_fx_rim_prepare_frag_glsl[];
-extern char datatoc_gpencil_fx_rim_resolve_frag_glsl[];
-extern char datatoc_gpencil_fx_shadow_prepare_frag_glsl[];
-extern char datatoc_gpencil_fx_shadow_resolve_frag_glsl[];
-extern char datatoc_gpencil_fx_glow_prepare_frag_glsl[];
-extern char datatoc_gpencil_fx_glow_resolve_frag_glsl[];
-extern char datatoc_gpencil_fx_swirl_frag_glsl[];
-extern char datatoc_gpencil_fx_wave_frag_glsl[];
-
/* verify if this fx is active */
-static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_render)
+static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_viewport)
{
if (fx == NULL) {
return false;
@@ -58,1007 +47,613 @@ static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_render)
}
bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
- if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit) && (!is_render)) {
+ if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit) && (is_viewport)) {
return false;
}
- if (((fx->mode & eShaderFxMode_Realtime) && (is_render == false)) ||
- ((fx->mode & eShaderFxMode_Render) && (is_render == true))) {
+ if (((fx->mode & eShaderFxMode_Realtime) && (is_viewport == true)) ||
+ ((fx->mode & eShaderFxMode_Render) && (is_viewport == false))) {
return true;
}
return false;
}
-/**
- * Get normal of draw using one stroke of visible layer
- * \param gpd: GP datablock
- * \param r_point: Point on plane
- * \param r_normal: Normal vector
- */
-static bool get_normal_vector(bGPdata *gpd, float r_point[3], float r_normal[3])
+typedef struct gpIterVfxData {
+ GPENCIL_PrivateData *pd;
+ GPENCIL_tObject *tgp_ob;
+ GPUFrameBuffer **target_fb;
+ GPUFrameBuffer **source_fb;
+ GPUTexture **target_color_tx;
+ GPUTexture **source_color_tx;
+ GPUTexture **target_reveal_tx;
+ GPUTexture **source_reveal_tx;
+} gpIterVfxData;
+
+static DRWShadingGroup *gpencil_vfx_pass_create(const char *name,
+ DRWState state,
+ gpIterVfxData *iter,
+ GPUShader *sh)
{
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
+ DRWPass *pass = DRW_pass_create(name, state);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuf", iter->source_color_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "revealBuf", iter->source_reveal_tx);
- /* get frame */
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (gps->totpoints >= 3) {
- bGPDspoint *pt = &gps->points[0];
- BKE_gpencil_stroke_normal(gps, r_normal);
- /* in some weird situations, the normal cannot be calculated, so try next stroke */
- if ((r_normal[0] != 0.0f) || (r_normal[1] != 0.0f) || (r_normal[2] != 0.0f)) {
- copy_v3_v3(r_point, &pt->x);
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-/* helper to get near and far depth of field values */
-static void GPENCIL_dof_nearfar(Object *camera, float coc, float nearfar[2])
-{
- if (camera == NULL) {
- return;
- }
- Camera *cam = camera->data;
+ GPENCIL_tVfx *tgp_vfx = BLI_memblock_alloc(iter->pd->gp_vfx_pool);
+ tgp_vfx->target_fb = iter->target_fb;
+ tgp_vfx->vfx_ps = pass;
- float fstop = cam->dof.aperture_fstop;
- float focus_dist = BKE_camera_object_dof_distance(camera);
- float focal_len = cam->lens;
+ SWAP(GPUFrameBuffer **, iter->target_fb, iter->source_fb);
+ SWAP(GPUTexture **, iter->target_color_tx, iter->source_color_tx);
+ SWAP(GPUTexture **, iter->target_reveal_tx, iter->source_reveal_tx);
- const float scale_camera = 0.001f;
- /* we want radius here for the aperture number */
- float aperture_scaled = 0.5f * scale_camera * focal_len / fstop;
- float focal_len_scaled = scale_camera * focal_len;
+ BLI_LINKS_APPEND(&iter->tgp_ob->vfx, tgp_vfx);
- float hyperfocal = (focal_len_scaled * focal_len_scaled) / (aperture_scaled * coc);
- nearfar[0] = (hyperfocal * focus_dist) / (hyperfocal + focal_len);
- nearfar[1] = (hyperfocal * focus_dist) / (hyperfocal - focal_len);
+ return grp;
}
-/* **************** Shader Effects ***************************** */
-
-/* Gaussian Blur FX
- * The effect is done using two shading groups because is faster to apply horizontal
- * and vertical in different operations.
- */
-static void gpencil_fx_blur(ShaderFxData *fx,
- int ob_idx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
+ if (fx->radius[0] == 0.0f && fx->radius[1] == 0.0f) {
return;
}
- BlurShaderFxData *fxd = (BlurShaderFxData *)fx;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- RegionView3D *rv3d = draw_ctx->rv3d;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- fxd->blur[0] = fxd->radius[0];
- fxd->blur[1] = fxd->radius[1];
-
- /* init weight */
- if (fxd->flag & FX_BLUR_DOF_MODE) {
- /* viewport and opengl render */
- Object *camera = NULL;
- if (rv3d) {
- if (rv3d->persp == RV3D_CAMOB) {
- camera = v3d->camera;
- }
- }
- else {
- camera = stl->storage->camera;
- }
-
- if (camera) {
- float nearfar[2];
- GPENCIL_dof_nearfar(camera, fxd->coc, nearfar);
- float zdepth = stl->g_data->gp_object_cache[ob_idx].zdepth;
- /* the object is on focus area */
- if ((zdepth >= nearfar[0]) && (zdepth <= nearfar[1])) {
- fxd->blur[0] = 0;
- fxd->blur[1] = 0;
- }
- else {
- float f;
- if (zdepth < nearfar[0]) {
- f = nearfar[0] - zdepth;
- }
- else {
- f = zdepth - nearfar[1];
- }
- fxd->blur[0] = f;
- fxd->blur[1] = f;
- CLAMP2(&fxd->blur[0], 0, fxd->radius[0]);
- }
- }
- else {
- /* if not camera view, the blur is disabled */
- fxd->blur[0] = 0;
- fxd->blur[1] = 0;
- }
- }
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ DRWShadingGroup *grp;
+ const float s = sin(fx->rotation);
+ const float c = cos(fx->rotation);
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-}
+ float winmat[4][4], persmat[4][4];
+ float blur_size[2] = {fx->radius[0], fx->radius[1]};
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
-/* Colorize FX */
-static void gpencil_fx_colorize(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
-{
- if (fx == NULL) {
- return;
+ if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) {
+ /* Compute circle of confusion size. */
+ float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1];
+ copy_v2_fl(blur_size, fabsf(coc));
+ }
+ else {
+ /* Modify by distance to camera and object scale. */
+ DRW_view_winmat_get(NULL, winmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w;
+ mul_v2_fl(blur_size, distance_factor);
+ }
+
+ GPUShader *sh = GPENCIL_shader_fx_blur_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ if (blur_size[0] > 0.0f) {
+ grp = gpencil_vfx_pass_create("Fx Blur H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){blur_size[0] * c, blur_size[0] * s});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0])));
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ if (blur_size[1] > 0.0f) {
+ grp = gpencil_vfx_pass_create("Fx Blur V", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){-blur_size[1] * s, blur_size[1] * c});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1])));
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_colorize_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec4(fx_shgrp, "low_color", &fxd->low_color[0], 1);
- DRW_shgroup_uniform_vec4(fx_shgrp, "high_color", &fxd->high_color[0], 1);
- DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "factor", &fxd->factor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
}
-/* Flip FX */
-static void gpencil_fx_flip(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+static void gpencil_vfx_colorize(ColorizeShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- FlipShaderFxData *fxd = (FlipShaderFxData *)fx;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- fxd->flipmode = 100;
- /* the number works as bit flag */
- if (fxd->flag & FX_FLIP_HORIZONTAL) {
- fxd->flipmode += 10;
- }
- if (fxd->flag & FX_FLIP_VERTICAL) {
- fxd->flipmode += 1;
- }
+ DRWShadingGroup *grp;
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_flip_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_int(fx_shgrp, "flipmode", &fxd->flipmode, 1);
+ GPUShader *sh = GPENCIL_shader_fx_colorize_get();
- DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Colorize", state, iter, sh);
+ DRW_shgroup_uniform_vec3_copy(grp, "lowColor", fx->low_color);
+ DRW_shgroup_uniform_vec3_copy(grp, "highColor", fx->high_color);
+ DRW_shgroup_uniform_float_copy(grp, "factor", fx->factor);
+ DRW_shgroup_uniform_int_copy(grp, "mode", fx->mode);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Light FX */
-static void gpencil_fx_light(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_flip(FlipShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- LightShaderFxData *fxd = (LightShaderFxData *)fx;
-
- if (fxd->object == NULL) {
- return;
- }
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_light_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
-
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
-
- /* location of the light using obj location as origin */
- copy_v3_v3(fxd->loc, fxd->object->obmat[3]);
-
- /* Calc distance to strokes plane
- * The w component of location is used to transfer the distance to drawing plane
- */
- float r_point[3], r_normal[3];
- float r_plane[4];
- bGPdata *gpd = cache->gpd;
- if (!get_normal_vector(gpd, r_point, r_normal)) {
- return;
- }
- mul_mat3_m4_v3(cache->obmat, r_normal); /* only rotation component */
- plane_from_point_normal_v3(r_plane, r_point, r_normal);
- float dt = dist_to_plane_v3(fxd->object->obmat[3], r_plane);
- fxd->loc[3] = dt; /* use last element to save it */
+ DRWShadingGroup *grp;
- DRW_shgroup_uniform_vec4(fx_shgrp, "loc", &fxd->loc[0], 1);
+ float axis_flip[2];
+ axis_flip[0] = (fx->flag & FX_FLIP_HORIZONTAL) ? -1.0f : 1.0f;
+ axis_flip[1] = (fx->flag & FX_FLIP_VERTICAL) ? -1.0f : 1.0f;
- DRW_shgroup_uniform_float(fx_shgrp, "energy", &fxd->energy, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "ambient", &fxd->ambient, 1);
+ GPUShader *sh = GPENCIL_shader_fx_transform_get();
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", axis_flip);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", (float[2]){0.0f, 0.0f});
+ DRW_shgroup_uniform_float_copy(grp, "swirlRadius", 0.0f);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Pixelate FX */
-static void gpencil_fx_pixel(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
+ DRWShadingGroup *grp;
+
+ float winmat[4][4], persmat[4][4];
+ float offset[2] = {fx->offset[0], fx->offset[1]};
+ float blur_size[2] = {fx->blur[0], fx->blur[1]};
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
+
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
+
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
+ mul_v2_fl(offset, distance_factor);
+ mul_v2_v2(offset, vp_size_inv);
+ mul_v2_fl(blur_size, distance_factor);
+
+ GPUShader *sh = GPENCIL_shader_fx_rim_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Rim H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", (float[2]){blur_size[0] * vp_size_inv[0], 0.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", offset);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0])));
+ DRW_shgroup_uniform_vec3_copy(grp, "maskColor", fx->mask_rgb);
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ switch (fx->mode) {
+ case eShaderFxRimMode_Normal:
+ state |= DRW_STATE_BLEND_ALPHA_PREMUL;
+ break;
+ case eShaderFxRimMode_Add:
+ state |= DRW_STATE_BLEND_ADD_FULL;
+ break;
+ case eShaderFxRimMode_Subtract:
+ state |= DRW_STATE_BLEND_SUB;
+ break;
+ case eShaderFxRimMode_Multiply:
+ case eShaderFxRimMode_Divide:
+ case eShaderFxRimMode_Overlay:
+ state |= DRW_STATE_BLEND_MUL;
+ break;
+ }
+
+ zero_v2(offset);
+
+ grp = gpencil_vfx_pass_create("Fx Rim V", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", (float[2]){0.0f, blur_size[1] * vp_size_inv[1]});
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", offset);
+ DRW_shgroup_uniform_vec3_copy(grp, "rimColor", fx->rim_rgb);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1])));
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", fx->mode);
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (fx->mode == eShaderFxRimMode_Overlay) {
+ /* We cannot do custom blending on MultiTarget framebuffers.
+ * Workaround by doing 2 passes. */
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", 999);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- fxd->size[2] = (int)fxd->flag & FX_PIXEL_USE_LINES;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_pixel_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_int(fx_shgrp, "size", &fxd->size[0], 3);
- DRW_shgroup_uniform_vec4(fx_shgrp, "color", &fxd->rgba[0], 1);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
}
-/* Rim FX */
-static void gpencil_fx_rim(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
+ DRWShadingGroup *grp;
+
+ float persmat[4][4], winmat[4][4], ob_center[3], pixsize_uniform[2];
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
+ float pixel_size[2] = {fx->size[0], fx->size[1]};
+ mul_v2_v2(pixel_size, vp_size_inv);
+
+ /* Fixed pixelisation center from object center. */
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
+ mul_v3_m4v3(ob_center, persmat, ob->obmat[3]);
+ mul_v3_fl(ob_center, 1.0f / w);
+
+ /* Convert to uvs. */
+ mul_v2_fl(ob_center, 0.5f);
+ add_v2_fl(ob_center, 0.5f);
+
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ mul_v2_fl(pixel_size, (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w);
+
+ /* Center to texel */
+ madd_v2_v2fl(ob_center, pixel_size, -0.5f);
+
+ GPUShader *sh = GPENCIL_shader_fx_pixelize_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+
+ /* Only if pixelated effect is bigger than 1px. */
+ if (pixel_size[0] > vp_size_inv[0]) {
+ copy_v2_fl2(pixsize_uniform, pixel_size[0], vp_size_inv[1]);
+ grp = gpencil_vfx_pass_create("Fx Pixelize X", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform);
+ DRW_shgroup_uniform_vec2_copy(grp, "targetPixelOffset", ob_center);
+ DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){pixel_size[0], 0.0f});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+
+ if (pixel_size[1] > vp_size_inv[1]) {
+ copy_v2_fl2(pixsize_uniform, vp_size_inv[0], pixel_size[1]);
+ grp = gpencil_vfx_pass_create("Fx Pixelize Y", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform);
+ DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){0.0f, pixel_size[1]});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- RimShaderFxData *fxd = (RimShaderFxData *)fx;
- bGPdata *gpd = cache->gpd;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- /* prepare pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_prepare_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
-
- DRW_shgroup_uniform_int(fx_shgrp, "offset", &fxd->offset[0], 2);
- DRW_shgroup_uniform_vec3(fx_shgrp, "rim_color", &fxd->rim_rgb[0], 1);
- DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-
- /* blur pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh_b = fx_shgrp;
-
- /* resolve pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_resolve_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeRim", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1);
- DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
-
- fxd->runtime.fx_sh_c = fx_shgrp;
}
-/* Shadow FX */
-static void gpencil_fx_shadow(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
- if ((!fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) {
- fxd->runtime.fx_sh = NULL;
- fxd->runtime.fx_sh_b = NULL;
- fxd->runtime.fx_sh_c = NULL;
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- /* prepare pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_shadow_prepare_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
-
- DRW_shgroup_uniform_int(fx_shgrp, "offset", &fxd->offset[0], 2);
- DRW_shgroup_uniform_float(fx_shgrp, "scale", &fxd->scale[0], 2);
- DRW_shgroup_uniform_float(fx_shgrp, "rotation", &fxd->rotation, 1);
- DRW_shgroup_uniform_vec4(fx_shgrp, "shadow_color", &fxd->shadow_rgba[0], 1);
-
- if ((fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) {
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->object->obmat[3], 1);
- }
- else {
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- }
-
- if (fxd->flag & FX_SHADOW_USE_WAVE) {
- DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1);
+ DRWShadingGroup *grp;
+
+ const bool use_obj_pivot = (fx->flag & FX_SHADOW_USE_OBJECT) != 0;
+ const bool use_wave = (fx->flag & FX_SHADOW_USE_WAVE) != 0;
+
+ float uv_mat[4][4], winmat[4][4], persmat[4][4], rot_center[3];
+ float wave_ofs[3], wave_dir[3], wave_phase, blur_dir[2], tmp[2];
+ float offset[2] = {fx->offset[0], fx->offset[1]};
+ float blur_size[2] = {fx->blur[0], fx->blur[1]};
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
+ const float ratio = vp_size_inv[1] / vp_size_inv[0];
+
+ copy_v3_v3(rot_center, (use_obj_pivot && fx->object) ? fx->object->obmat[3] : ob->obmat[3]);
+
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, rot_center));
+ mul_v3_m4v3(rot_center, persmat, rot_center);
+ mul_v3_fl(rot_center, 1.0f / w);
+
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
+ mul_v2_fl(offset, distance_factor);
+ mul_v2_v2(offset, vp_size_inv);
+ mul_v2_fl(blur_size, distance_factor);
+
+ rot_center[0] = rot_center[0] * 0.5f + 0.5f;
+ rot_center[1] = rot_center[1] * 0.5f + 0.5f;
+
+ /* UV transform matrix. (loc, rot, scale) Sent to shader as 2x3 matrix. */
+ unit_m4(uv_mat);
+ translate_m4(uv_mat, rot_center[0], rot_center[1], 0.0f);
+ rescale_m4(uv_mat, (float[3]){1.0f / fx->scale[0], 1.0f / fx->scale[1], 1.0f});
+ translate_m4(uv_mat, -offset[0], -offset[1], 0.0f);
+ rescale_m4(uv_mat, (float[3]){1.0f / ratio, 1.0f, 1.0f});
+ rotate_m4(uv_mat, 'Z', fx->rotation);
+ rescale_m4(uv_mat, (float[3]){ratio, 1.0f, 1.0f});
+ translate_m4(uv_mat, -rot_center[0], -rot_center[1], 0.0f);
+
+ if (use_wave) {
+ float dir[2];
+ if (fx->orientation == 0) {
+ /* Horizontal */
+ copy_v2_fl2(dir, 1.0f, 0.0f);
+ }
+ else {
+ /* Vertical */
+ copy_v2_fl2(dir, 0.0f, 1.0f);
+ }
+ /* This is applied after rotation. Counter the rotation to keep aligned with global axis. */
+ rotate_v2_v2fl(wave_dir, dir, fx->rotation);
+ /* Rotate 90°. */
+ copy_v2_v2(wave_ofs, wave_dir);
+ SWAP(float, wave_ofs[0], wave_ofs[1]);
+ wave_ofs[1] *= -1.0f;
+ /* Keep world space scalling and aspect ratio. */
+ mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
+ mul_v2_v2(wave_dir, vp_size);
+ mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
+ mul_v2_v2(wave_ofs, vp_size_inv);
+ /* Phase start at shadow center. */
+ wave_phase = fx->phase - dot_v2v2(rot_center, wave_dir);
}
else {
- DRW_shgroup_uniform_int_copy(fx_shgrp, "orientation", -1);
- }
- DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "period", &fxd->period, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "phase", &fxd->phase, 1);
-
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-
- /* blur pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh_b = fx_shgrp;
-
- /* resolve pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_shadow_resolve_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowDepth", &stl->g_data->temp_depth_tx_fx);
-
- fxd->runtime.fx_sh_c = fx_shgrp;
+ zero_v2(wave_dir);
+ zero_v2(wave_ofs);
+ wave_phase = 0.0f;
+ }
+
+ GPUShader *sh = GPENCIL_shader_fx_shadow_get();
+
+ copy_v2_fl2(blur_dir, blur_size[0] * vp_size_inv[0], 0.0f);
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Shadow H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", blur_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveDir", wave_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs);
+ DRW_shgroup_uniform_float_copy(grp, "wavePhase", wave_phase);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotX", uv_mat[0]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotY", uv_mat[1]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", uv_mat[3]);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0])));
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ unit_m4(uv_mat);
+ zero_v2(wave_ofs);
+
+ /* We reseted the uv_mat so we need to accound for the rotation in the */
+ copy_v2_fl2(tmp, 0.0f, blur_size[1]);
+ rotate_v2_v2fl(blur_dir, tmp, -fx->rotation);
+ mul_v2_v2(blur_dir, vp_size_inv);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
+ grp = gpencil_vfx_pass_create("Fx Shadow V", state, iter, sh);
+ DRW_shgroup_uniform_vec4_copy(grp, "shadowColor", fx->shadow_rgba);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", blur_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotX", uv_mat[0]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotY", uv_mat[1]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", uv_mat[3]);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1])));
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Glow FX */
-static void gpencil_fx_glow(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_glow(GlowShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- GlowShaderFxData *fxd = (GlowShaderFxData *)fx;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- /* prepare pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_glow_prepare_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "glow_color", &fxd->glow_color[0], 1);
- DRW_shgroup_uniform_vec3(fx_shgrp, "select_color", &fxd->select_color[0], 1);
- DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "threshold", &fxd->threshold, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-
- /* blur pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh_b = fx_shgrp;
-
- /* resolve pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_glow_resolve_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowDepth", &stl->g_data->temp_depth_tx_fx);
-
- /* reuse field */
- DRW_shgroup_uniform_int(fx_shgrp, "alpha_mode", &fxd->blur[1], 1);
-
- fxd->runtime.fx_sh_c = fx_shgrp;
-}
+ const bool use_glow_under = (fx->flag & FX_GLOW_USE_ALPHA) != 0;
+ DRWShadingGroup *grp;
+ const float s = sin(fx->rotation);
+ const float c = cos(fx->rotation);
-/* Swirl FX */
-static void gpencil_fx_swirl(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
-{
- if (fx == NULL) {
- return;
- }
- SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
- if (fxd->object == NULL) {
- return;
- }
+ GPUShader *sh = GPENCIL_shader_fx_glow_get();
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
+ float ref_col[3];
- fxd->transparent = (int)fxd->flag & FX_SWIRL_MAKE_TRANSPARENT;
+ if (fx->mode == eShaderFxGlowMode_Luminance) {
+ ref_col[0] = fx->threshold;
+ ref_col[1] = -1.0f;
+ ref_col[2] = -1.0f;
+ }
+ else {
+ copy_v3_v3(ref_col, fx->select_color);
+ }
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Glow H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){fx->blur[0] * c, fx->blur[0] * s});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, fx->blur[0])));
+ DRW_shgroup_uniform_vec3_copy(grp, "threshold", ref_col);
+ DRW_shgroup_uniform_vec4_copy(grp, "glowColor", fx->glow_color);
+ DRW_shgroup_uniform_bool_copy(grp, "glowUnder", use_glow_under);
+ DRW_shgroup_uniform_bool_copy(grp, "firstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ state = DRW_STATE_WRITE_COLOR;
+ /* Blending: Force blending. */
+ switch (fx->blend_mode) {
+ case eGplBlendMode_Regular:
+ state |= DRW_STATE_BLEND_ALPHA_PREMUL;
+ break;
+ case eGplBlendMode_Add:
+ state |= DRW_STATE_BLEND_ADD_FULL;
+ break;
+ case eGplBlendMode_Subtract:
+ state |= DRW_STATE_BLEND_SUB;
+ break;
+ case eGplBlendMode_Multiply:
+ case eGplBlendMode_Divide:
+ state |= DRW_STATE_BLEND_MUL;
+ break;
+ }
+
+ /* Small Hack: We ask for RGBA16F buffer if using use_glow_under to store original
+ * revealage in alpha channel. */
+ if (fx->blend_mode == eGplBlendMode_Subtract || use_glow_under) {
+ /* For this effect to propagate, we need a signed floating point buffer. */
+ iter->pd->use_signed_fb = true;
+ }
+
+ grp = gpencil_vfx_pass_create("Fx Glow V", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){-fx->blur[1] * s, fx->blur[1] * c});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, fx->blur[0])));
+ DRW_shgroup_uniform_vec3_copy(grp, "threshold", (float[3]){-1.0f, -1.0f, -1.0f});
+ DRW_shgroup_uniform_vec4_copy(grp, "glowColor", (float[4]){1.0f, 1.0f, 1.0f, fx->glow_color[3]});
+ DRW_shgroup_uniform_bool_copy(grp, "firstPass", false);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", fx->blend_mode);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+}
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_swirl_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
+static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *iter)
+{
+ DRWShadingGroup *grp;
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+ float winmat[4][4], persmat[4][4], wave_center[3];
+ float wave_ofs[3], wave_dir[3], wave_phase;
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->object->obmat[3], 1);
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
+ mul_v3_m4v3(wave_center, persmat, ob->obmat[3]);
+ mul_v3_fl(wave_center, 1.0f / w);
- DRW_shgroup_uniform_int(fx_shgrp, "radius", &fxd->radius, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "angle", &fxd->angle, 1);
- DRW_shgroup_uniform_int(fx_shgrp, "transparent", &fxd->transparent, 1);
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
+ wave_center[0] = wave_center[0] * 0.5f + 0.5f;
+ wave_center[1] = wave_center[1] * 0.5f + 0.5f;
- fxd->runtime.fx_sh = fx_shgrp;
+ if (fx->orientation == 0) {
+ /* Horizontal */
+ copy_v2_fl2(wave_dir, 1.0f, 0.0f);
+ }
+ else {
+ /* Vertical */
+ copy_v2_fl2(wave_dir, 0.0f, 1.0f);
+ }
+ /* Rotate 90°. */
+ copy_v2_v2(wave_ofs, wave_dir);
+ SWAP(float, wave_ofs[0], wave_ofs[1]);
+ wave_ofs[1] *= -1.0f;
+ /* Keep world space scalling and aspect ratio. */
+ mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
+ mul_v2_v2(wave_dir, vp_size);
+ mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
+ mul_v2_v2(wave_ofs, vp_size_inv);
+ /* Phase start at shadow center. */
+ wave_phase = fx->phase - dot_v2v2(wave_center, wave_dir);
+
+ GPUShader *sh = GPENCIL_shader_fx_transform_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Wave", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", (float[2]){1.0f, 1.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "waveDir", wave_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs);
+ DRW_shgroup_uniform_float_copy(grp, "wavePhase", wave_phase);
+ DRW_shgroup_uniform_float_copy(grp, "swirlRadius", 0.0f);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Wave Distortion FX */
-static void gpencil_fx_wave(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
+ DRWShadingGroup *grp;
+
+ if (fx->object == NULL) {
return;
}
- WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
-
- DRWShadingGroup *fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_wave_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "period", &fxd->period, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "phase", &fxd->phase, 1);
- DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1);
- DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1);
+ float winmat[4][4], persmat[4][4], swirl_center[3];
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
- fxd->runtime.fx_sh = fx_shgrp;
-}
-
-/* ************************************************************** */
+ copy_v3_v3(swirl_center, fx->object->obmat[3]);
-/* create all FX shaders */
-void GPENCIL_create_fx_shaders(GPENCIL_e_data *e_data)
-{
- /* fx shaders (all in screen space) */
- if (!e_data->gpencil_fx_blur_sh) {
- e_data->gpencil_fx_blur_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_blur_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_colorize_sh) {
- e_data->gpencil_fx_colorize_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_colorize_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_flip_sh) {
- e_data->gpencil_fx_flip_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_flip_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_light_sh) {
- e_data->gpencil_fx_light_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_light_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_pixel_sh) {
- e_data->gpencil_fx_pixel_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_pixel_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_rim_prepare_sh) {
- e_data->gpencil_fx_rim_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_rim_prepare_frag_glsl, NULL);
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, swirl_center));
+ mul_v3_m4v3(swirl_center, persmat, swirl_center);
+ mul_v3_fl(swirl_center, 1.0f / w);
- e_data->gpencil_fx_rim_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_rim_resolve_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_shadow_prepare_sh) {
- e_data->gpencil_fx_shadow_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_shadow_prepare_frag_glsl, NULL);
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(fx->object->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
- e_data->gpencil_fx_shadow_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_shadow_resolve_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_glow_prepare_sh) {
- e_data->gpencil_fx_glow_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_glow_prepare_frag_glsl, NULL);
+ mul_v2_fl(swirl_center, 0.5f);
+ add_v2_fl(swirl_center, 0.5f);
+ mul_v2_v2(swirl_center, vp_size);
- e_data->gpencil_fx_glow_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_glow_resolve_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_swirl_sh) {
- e_data->gpencil_fx_swirl_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_swirl_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_wave_sh) {
- e_data->gpencil_fx_wave_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_wave_frag_glsl,
- NULL);
+ float radius = fx->radius * distance_factor;
+ if (radius < 1.0f) {
+ return;
}
-}
-/* free FX shaders */
-void GPENCIL_delete_fx_shaders(GPENCIL_e_data *e_data)
-{
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_blur_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_colorize_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_flip_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_light_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_pixel_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_shadow_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_shadow_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_swirl_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_wave_sh);
-}
+ GPUShader *sh = GPENCIL_shader_fx_transform_get();
-/* create all passes used by FX */
-void GPENCIL_create_fx_passes(GPENCIL_PassList *psl)
-{
- psl->fx_shader_pass = DRW_pass_create("GPencil Shader FX Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS);
- psl->fx_shader_pass_blend = DRW_pass_create("GPencil Shader FX Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", (float[2]){1.0f, 1.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", (float[2]){0.0f, 0.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "swirlCenter", swirl_center);
+ DRW_shgroup_uniform_float_copy(grp, "swirlAngle", fx->angle);
+ DRW_shgroup_uniform_float_copy(grp, "swirlRadius", radius);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* prepare fx shading groups */
-void gpencil_fx_prepare(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache_ob)
+void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const bool wiremode = (bool)(cache_ob->shading_type[0] == OB_WIRE);
-
- int ob_idx = cache_ob->idx;
-
- if ((wiremode) || (cache_ob->shader_fx.first == NULL)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ /* If simplify enabled, nothing more to do. */
+ if (pd->simplify_fx) {
return;
}
- /* loop FX */
- for (ShaderFxData *fx = cache_ob->shader_fx.first; fx; fx = fx->next) {
- if (effect_is_active(cache_ob->gpd, fx, stl->storage->is_render)) {
+
+ /* These may not be allocated yet, use adress of future pointer. */
+ gpIterVfxData iter = {
+ .pd = pd,
+ .tgp_ob = tgp_ob,
+ .target_fb = &fbl->layer_fb,
+ .source_fb = &fbl->object_fb,
+ .target_color_tx = &pd->color_layer_tx,
+ .source_color_tx = &pd->color_object_tx,
+ .target_reveal_tx = &pd->reveal_layer_tx,
+ .source_reveal_tx = &pd->reveal_object_tx,
+ };
+
+ LISTBASE_FOREACH (ShaderFxData *, fx, &ob->shader_fx) {
+ if (effect_is_active(gpd, fx, pd->is_viewport)) {
switch (fx->type) {
case eShaderFxType_Blur:
- gpencil_fx_blur(fx, ob_idx, e_data, vedata, cache_ob);
+ gpencil_vfx_blur((BlurShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Colorize:
- gpencil_fx_colorize(fx, e_data, vedata);
+ gpencil_vfx_colorize((ColorizeShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Flip:
- gpencil_fx_flip(fx, e_data, vedata);
- break;
- case eShaderFxType_Light:
- gpencil_fx_light(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_flip((FlipShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Pixel:
- gpencil_fx_pixel(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_pixelize((PixelShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Rim:
- gpencil_fx_rim(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_rim((RimShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Shadow:
- gpencil_fx_shadow(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_shadow((ShadowShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Glow:
- gpencil_fx_glow(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_glow((GlowShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Swirl:
- gpencil_fx_swirl(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_swirl((SwirlShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Wave:
- gpencil_fx_wave(fx, e_data, vedata);
+ gpencil_vfx_wave((WaveShaderFxData *)fx, ob, &iter);
break;
default:
break;
}
}
}
-}
-
-/* helper to draw one FX pass and do ping-pong copy */
-static void gpencil_draw_fx_pass(GPENCIL_Data *vedata, DRWShadingGroup *shgrp, bool blend)
-{
- if (shgrp == NULL) {
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
-
- const float clearcol[4] = {0.0f};
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
-
- /* draw effect pass in temp texture (B) using as source the previous image
- * existing in the other temp texture (A) */
- if (!blend) {
- DRW_draw_pass_subset(psl->fx_shader_pass, shgrp, shgrp);
- }
- else {
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, shgrp, shgrp);
- }
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
-
- GPU_framebuffer_bind(fbl->temp_fb_a);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
- DRW_draw_pass(psl->mix_pass_noblend);
-}
-
-/* helper to manage gaussian blur passes */
-static void draw_gpencil_blur_passes(GPENCIL_Data *vedata, BlurShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh == NULL) {
- return;
- }
-
- DRWShadingGroup *shgrp = fxd->runtime.fx_sh;
- int samples = fxd->samples;
-
- float bx = fxd->blur[0];
- float by = fxd->blur[1];
-
- /* the blur is done in two steps (Hor/Ver) because is faster and
- * gets better result
- *
- * samples could be 0 and disable de blur effects because sometimes
- * is easier animate the number of samples only, instead to animate the
- * hide/unhide and the number of samples to make some effects.
- */
- for (int b = 0; b < samples; b++) {
- /* horizontal */
- if (bx > 0) {
- fxd->blur[0] = bx;
- fxd->blur[1] = 0;
- gpencil_draw_fx_pass(vedata, shgrp, true);
- }
- /* vertical */
- if (by > 0) {
- fxd->blur[0] = 0;
- fxd->blur[1] = by;
- gpencil_draw_fx_pass(vedata, shgrp, true);
- }
- }
-}
-
-/* blur intermediate pass */
-static void draw_gpencil_midpass_blur(GPENCIL_Data *vedata, ShaderFxData_Runtime *runtime)
-{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- const float clearcol[4] = {0.0f};
-
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, runtime->fx_sh_b, runtime->fx_sh_b);
-
- /* copy pass from b for ping-pong frame buffers */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass(psl->mix_pass_noblend);
-}
-
-/* do blur of mid passes */
-static void draw_gpencil_do_blur(
- GPENCIL_Data *vedata, ShaderFxData_Runtime *runtime, int samples, int bx, int by, int blur[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
+ if (tgp_ob->vfx.first != NULL) {
+ /* We need an extra pass to combine result to main buffer. */
+ iter.target_fb = &fbl->gpencil_fb;
- if ((samples > 0) && ((bx > 0) || (by > 0))) {
- for (int x = 0; x < samples; x++) {
+ GPUShader *sh = GPENCIL_shader_fx_composite_get();
- /* horizontal */
- blur[0] = bx;
- blur[1] = 0;
- draw_gpencil_midpass_blur(vedata, runtime);
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL;
+ DRWShadingGroup *grp = gpencil_vfx_pass_create("GPencil Object Compose", state, &iter, sh);
+ DRW_shgroup_uniform_int_copy(grp, "isFirstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
- /* Vertical */
- blur[0] = 0;
- blur[1] = by;
- draw_gpencil_midpass_blur(vedata, runtime);
-
- blur[0] = bx;
- blur[1] = by;
- }
- }
-}
-
-/* helper to draw RIM passes */
-static void draw_gpencil_rim_passes(GPENCIL_Data *vedata, RimShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh_b == NULL) {
- return;
- }
+ /* We cannot do custom blending on MultiTarget framebuffers.
+ * Workaround by doing 2 passes. */
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
+ DRW_shgroup_uniform_int_copy(grp, "isFirstPass", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
-
- const float clearcol[4] = {0.0f};
-
- /* prepare mask */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh);
-
- /* blur rim */
- draw_gpencil_do_blur(
- vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[1], &fxd->blur[0]);
-
- /* resolve */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
-
- GPU_framebuffer_bind(fbl->temp_fb_a);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
- DRW_draw_pass(psl->mix_pass_noblend);
-}
-
-/* helper to draw SHADOW passes */
-static void draw_gpencil_shadow_passes(GPENCIL_Data *vedata, ShadowShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh_b == NULL) {
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- const float clearcol[4] = {0.0f};
-
- /* prepare shadow */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh);
-
- /* blur shadow */
- draw_gpencil_do_blur(
- vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[1], &fxd->blur[0]);
-
- /* resolve */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
-
- GPU_framebuffer_bind(fbl->temp_fb_a);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
- DRW_draw_pass(psl->mix_pass_noblend);
-}
-
-/* helper to draw GLOW passes */
-static void draw_gpencil_glow_passes(GPENCIL_Data *vedata, GlowShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh_b == NULL) {
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
-
- const float clearcol[4] = {0.0f};
-
- /* prepare glow */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh);
-
- /* blur glow */
- draw_gpencil_do_blur(
- vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[0], &fxd->blur[0]);
-
- /* resolve */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
-
- /* reuses blur field to keep alpha mode */
- fxd->blur[1] = (fxd->flag & FX_GLOW_USE_ALPHA) ? 1 : 0;
-
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
-
- GPU_framebuffer_bind(fbl->temp_fb_a);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
- DRW_draw_pass(psl->mix_pass_noblend);
-}
-
-/* apply all object fx effects */
-void gpencil_fx_draw(GPENCIL_e_data *UNUSED(e_data),
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache_ob)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-
- /* loop FX modifiers */
- for (ShaderFxData *fx = cache_ob->shader_fx.first; fx; fx = fx->next) {
- if (effect_is_active(cache_ob->gpd, fx, stl->storage->is_render)) {
- switch (fx->type) {
-
- case eShaderFxType_Blur: {
- BlurShaderFxData *fxd = (BlurShaderFxData *)fx;
- draw_gpencil_blur_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Colorize: {
- ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Flip: {
- FlipShaderFxData *fxd = (FlipShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Light: {
- LightShaderFxData *fxd = (LightShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Pixel: {
- PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Rim: {
- RimShaderFxData *fxd = (RimShaderFxData *)fx;
- draw_gpencil_rim_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Shadow: {
- ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
- draw_gpencil_shadow_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Glow: {
- GlowShaderFxData *fxd = (GlowShaderFxData *)fx;
- draw_gpencil_glow_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Swirl: {
- SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Wave: {
- WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- default:
- break;
- }
- }
+ pd->use_object_fb = true;
+ pd->use_layer_fb = true;
}
}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl
deleted file mode 100644
index 0f64f54c67b..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl
+++ /dev/null
@@ -1,85 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-
-uniform int blur[2];
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 noffset = vec2(blur[0], blur[1]);
-
-out vec4 FragColor;
-
-float get_zdepth(ivec2 poxy)
-{
- /* if outside viewport set as infinite depth */
- if ((poxy.x < 0) || (poxy.x > Viewport.x)) {
- return 1.0f;
- }
- if ((poxy.y < 0) || (poxy.y > Viewport.y)) {
- return 1.0f;
- }
-
- float zdepth = texelFetch(strokeDepth, poxy, 0).r;
- return zdepth;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) :
- (noffset[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) :
- (noffset[1] / defaultpixsize);
-
- /* round to avoid shift when add more samples */
- dx = floor(dx) + 1.0;
- dy = floor(dy) + 1.0;
-
- /* apply blurring, using a 9-tap filter with predefined gaussian weights */
- /* depth (get the value of the surrounding pixels) */
- float outdepth = get_zdepth(ivec2(uv.x, uv.y));
- for (int x = -1; x < 2; x++) {
- for (int y = -1; y < 2; y++) {
- float depth = get_zdepth(ivec2(uv.x + x * dx, uv.y + y * dy));
- if (depth < outdepth) {
- outdepth = depth;
- break;
- }
- }
- }
- gl_FragDepth = outdepth;
-
- /* color */
- vec4 outcolor = vec4(0.0);
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416;
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy), 0) * 0.118318;
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416;
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318;
-
- outcolor += texelFetch(strokeColor, ivec2(uv.x, uv.y), 0) * 0.147761;
-
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318;
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416;
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 0.0 * dx, uv.y - 1.0 * dy), 0) * 0.118318;
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416;
-
- FragColor = clamp(outcolor, 0, 1.0);
-
- /* discar extreme values */
- if (outcolor.a < 0.02f) {
- discard;
- }
- if ((outdepth <= 0.000001) || (outdepth >= 0.999999)) {
- discard;
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl
deleted file mode 100644
index 52f42d30d06..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl
+++ /dev/null
@@ -1,82 +0,0 @@
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform vec4 low_color;
-uniform vec4 high_color;
-uniform int mode;
-uniform float factor;
-
-out vec4 FragColor;
-
-#define MODE_GRAYSCALE 0
-#define MODE_SEPIA 1
-#define MODE_DUOTONE 2
-#define MODE_CUSTOM 3
-#define MODE_TRANSPARENT 4
-
-float get_luminance(vec4 color)
-{
- float lum = (color.r * 0.2126) + (color.g * 0.7152) + (color.b * 0.723);
- return lum;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- vec4 src_pixel = texelFetch(strokeColor, uv.xy, 0);
- float luminance = get_luminance(src_pixel);
- vec4 outcolor;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
-
- switch (mode) {
- case MODE_GRAYSCALE: {
- outcolor = vec4(luminance, luminance, luminance, src_pixel.a);
- break;
- }
- case MODE_SEPIA: {
- float Red = (src_pixel.r * 0.393) + (src_pixel.g * 0.769) + (src_pixel.b * 0.189);
- float Green = (src_pixel.r * 0.349) + (src_pixel.g * 0.686) + (src_pixel.b * 0.168);
- float Blue = (src_pixel.r * 0.272) + (src_pixel.g * 0.534) + (src_pixel.b * 0.131);
- outcolor = vec4(Red, Green, Blue, src_pixel.a);
- break;
- }
- case MODE_DUOTONE: {
- if (luminance <= factor) {
- outcolor = low_color;
- }
- else {
- outcolor = high_color;
- }
- break;
- }
- case MODE_CUSTOM: {
- /* if below umbral, force custom color */
- if (luminance <= factor) {
- outcolor = low_color;
- }
- else {
- outcolor = vec4(luminance * low_color.r,
- luminance * low_color.b,
- luminance * low_color.b,
- src_pixel.a);
- }
- break;
- }
- case MODE_TRANSPARENT: {
- outcolor = vec4(src_pixel.rgb, src_pixel.a * factor);
- break;
- }
- default: {
- outcolor = src_pixel;
- }
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl
deleted file mode 100644
index 2cd77007b36..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl
+++ /dev/null
@@ -1,37 +0,0 @@
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 wsize;
-uniform int flipmode;
-
-void main()
-{
- vec2 mode = vec2(0, 0);
- /* horz. */
- if (flipmode >= 110) {
- mode[0] = 1;
- }
- /* vert. */
- if ((flipmode == 101) || (flipmode == 111)) {
- mode[1] = 1;
- }
-
- vec2 uv = vec2(gl_FragCoord.xy);
- float stroke_depth;
- vec4 outcolor;
-
- if (mode[0] > 0) {
- uv.x = wsize.x - uv.x;
- }
- if (mode[1] > 0) {
- uv.y = wsize.y - uv.y;
- }
-
- ivec2 iuv = ivec2(uv.x, uv.y);
- stroke_depth = texelFetch(strokeDepth, iuv, 0).r;
- outcolor = texelFetch(strokeColor, iuv, 0);
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl
deleted file mode 100644
index 676b9b05db9..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl
+++ /dev/null
@@ -1,68 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-/* ******************************************************************* */
-/* create glow mask */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform vec3 glow_color;
-uniform vec3 select_color;
-uniform float threshold;
-uniform int mode;
-
-out vec4 FragColor;
-
-#define MODE_LUMINANCE 0
-#define MODE_COLOR 1
-
-/* calc luminance */
-float luma(vec3 color)
-{
- /* the color is linear, so do not apply tonemapping */
- return (color.r + color.g + color.b) / 3.0;
-}
-
-bool check_color(vec3 color_a, vec3 color_b)
-{
- /* need round the number to avoid precision errors */
- if ((floor(color_a.r * 100) == floor(color_b.r * 100)) &&
- (floor(color_a.g * 100) == floor(color_b.g * 100)) &&
- (floor(color_a.b * 100) == floor(color_b.b * 100))) {
- return true;
- }
-
- return false;
-}
-
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r;
- vec4 src_pixel = texelFetch(strokeColor, ivec2(uv.xy), 0);
- vec4 outcolor;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
-
- if (mode == MODE_LUMINANCE) {
- if (luma(src_pixel.rgb) < threshold) {
- discard;
- }
- }
- else if (mode == MODE_COLOR) {
- if (!check_color(src_pixel.rgb, select_color.rgb)) {
- discard;
- }
- }
- else {
- discard;
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = vec4(glow_color.rgb, 1.0);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl
deleted file mode 100644
index e2aceb9eefe..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ******************************************************************* */
-/* Resolve GLOW pass */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D glowColor;
-uniform sampler2D glowDepth;
-uniform int alpha_mode;
-
-out vec4 FragColor;
-
-void main()
-{
- vec4 outcolor;
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- vec4 src_pixel = texelFetch(strokeColor, uv.xy, 0);
- vec4 glow_pixel = texelFetch(glowColor, uv.xy, 0);
- float glow_depth = texelFetch(glowDepth, uv.xy, 0).r;
-
- if (alpha_mode == 0) {
- outcolor = src_pixel + glow_pixel;
- }
- else {
- if ((src_pixel.a < 0.1) || (glow_pixel.a < 0.1)) {
- outcolor = src_pixel + glow_pixel;
- }
- else {
- outcolor = src_pixel;
- }
- }
-
- if (src_pixel.a < glow_pixel.a) {
- gl_FragDepth = glow_depth;
- }
- else {
- gl_FragDepth = stroke_depth;
- }
-
- if (outcolor.a < 0.001) {
- discard;
- }
-
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
deleted file mode 100644
index a5c321c20c1..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
+++ /dev/null
@@ -1,70 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-uniform vec4 loc;
-uniform float energy;
-uniform float ambient;
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-out vec4 FragColor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-#define height loc.w
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- /* need to calculate ndc because this is not done by vertex shader */
- vec3 ndc = vec3(vertex).xyz / vertex.w;
-
- vec2 sc;
- sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
- sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
-
- return sc;
-}
-
-void main()
-{
- float stroke_depth;
- vec4 objcolor;
-
- vec4 light_loc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
- vec2 light2d = toScreenSpace(light_loc);
-
- /* calc pixel scale */
- float pxscale = (ProjectionMatrix[3][3] == 0.0) ? (10.0 / (light_loc.z * defaultpixsize)) :
- (10.0 / defaultpixsize);
- pxscale = max(pxscale, 0.000001);
-
- /* the height over plane is received in the w component of the loc
- * and needs a factor to adapt to pixels
- */
- float peak = height * 10.0 * pxscale;
- vec3 light3d = vec3(light2d.x, light2d.y, peak);
-
- vec2 uv = vec2(gl_FragCoord.xy);
- vec3 frag_loc = vec3(uv.x, uv.y, 0);
- vec3 norm = vec3(0, 0, 1.0); /* always z-up */
-
- ivec2 iuv = ivec2(uv.x, uv.y);
- stroke_depth = texelFetch(strokeDepth, iuv, 0).r;
- objcolor = texelFetch(strokeColor, iuv, 0);
-
- /* diffuse light */
- vec3 lightdir = normalize(light3d - frag_loc);
- float diff = max(dot(norm, lightdir), 0.0);
- float dist = length(light3d - frag_loc) / pxscale;
- float factor = diff * ((energy * 100.0) / (dist * dist));
-
- vec3 result = factor * max(ambient, 0.1) * vec3(objcolor);
-
- gl_FragDepth = stroke_depth;
- FragColor = vec4(result.r, result.g, result.b, objcolor.a);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl
deleted file mode 100644
index 46b3c4286b4..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform int size[3];
-uniform vec4 color;
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-out vec4 FragColor;
-
-int uselines = size[2];
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 nsize = max(vec2(size[0], size[1]), 3.0);
-
-/* This pixelation shader is a modified version of original Geeks3d.com code */
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (nsize[0] / (nloc.z * defaultpixsize)) :
- (nsize[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (nsize[1] / (nloc.z * defaultpixsize)) :
- (nsize[1] / defaultpixsize);
-
- dx = max(abs(dx), 3.0);
- dy = max(abs(dy), 3.0);
-
- vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));
-
- float stroke_depth = texelFetch(strokeDepth, ivec2(coord), 0).r;
- vec4 outcolor = texelFetch(strokeColor, ivec2(coord), 0);
-
- if (uselines == 1) {
- float difx = uv.x - (floor(uv.x / nsize[0]) * nsize[0]);
- if ((difx == 0.5) && (outcolor.a > 0)) {
- outcolor = color;
- }
- float dify = uv.y - (floor(uv.y / nsize[1]) * nsize[1]);
- if ((dify == 0.5) && (outcolor.a > 0)) {
- outcolor = color;
- }
- }
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl
deleted file mode 100644
index 2a17e573978..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl
+++ /dev/null
@@ -1,65 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-/* ******************************************************************* */
-/* create rim and mask */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-
-uniform int offset[2];
-uniform vec3 rim_color;
-uniform vec3 mask_color;
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 noffset = vec2(offset[0], offset[1]);
-
-out vec4 FragColor;
-
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) :
- (noffset[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) :
- (noffset[1] / defaultpixsize);
-
- float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r;
- vec4 src_pixel = texelFetch(strokeColor, ivec2(uv.xy), 0);
- vec4 offset_pixel = texelFetch(strokeColor, ivec2(uv.x - dx, uv.y - dy), 0);
- vec4 outcolor;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
- /* check inside viewport */
- else if ((uv.x - dx < 0) || (uv.x - dx > Viewport[0])) {
- discard;
- }
- else if ((uv.y - dy < 0) || (uv.y - dy > Viewport[1])) {
- discard;
- }
- /* pixel is equal to mask color, keep */
- else if (src_pixel.rgb == mask_color.rgb) {
- discard;
- }
- else {
- if ((src_pixel.a > 0) && (offset_pixel.a > 0)) {
- discard;
- }
- else {
- outcolor = vec4(rim_color, 1.0);
- }
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl
deleted file mode 100644
index fa010baa32f..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-/* ******************************************************************* */
-/* Resolve RIM pass and add blur if needed */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D strokeRim;
-
-uniform vec3 mask_color;
-uniform int mode;
-
-out vec4 FragColor;
-
-#define MODE_NORMAL 0
-#define MODE_OVERLAY 1
-#define MODE_ADD 2
-#define MODE_SUB 3
-#define MODE_MULTIPLY 4
-#define MODE_DIVIDE 5
-
-float overlay_color(float a, float b)
-{
- float rtn;
- if (a < 0.5) {
- rtn = 2.0 * a * b;
- }
- else {
- rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);
- }
-
- return rtn;
-}
-
-vec4 get_blend_color(int mode, vec4 src_color, vec4 mix_color)
-{
- vec4 outcolor;
- if (mode == MODE_NORMAL) {
- outcolor = mix_color;
- }
- else if (mode == MODE_OVERLAY) {
- outcolor.r = overlay_color(src_color.r, mix_color.r);
- outcolor.g = overlay_color(src_color.g, mix_color.g);
- outcolor.b = overlay_color(src_color.b, mix_color.b);
- }
- else if (mode == MODE_ADD) {
- outcolor = src_color + mix_color;
- }
- else if (mode == MODE_SUB) {
- outcolor = src_color - mix_color;
- }
- else if (mode == MODE_MULTIPLY) {
- outcolor = src_color * mix_color;
- }
- else if (mode == MODE_DIVIDE) {
- outcolor = src_color / mix_color;
- }
- else {
- outcolor = mix_color;
- }
-
- /* use always the alpha of source color */
-
- outcolor.a = src_color.a;
- /* use alpha to calculate the weight of the mixed color */
- outcolor = mix(src_color, outcolor, mix_color.a);
-
- return outcolor;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- vec4 src_pixel = texelFetch(strokeColor, uv.xy, 0);
- vec4 rim_pixel = texelFetch(strokeRim, uv.xy, 0);
-
- vec4 outcolor = src_pixel;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
- /* pixel is equal to mask color, keep */
- else if (src_pixel.rgb == mask_color.rgb) {
- outcolor = src_pixel;
- }
- else {
- if (rim_pixel.a == 0.0f) {
- outcolor = src_pixel;
- }
- else {
- outcolor = get_blend_color(mode, src_pixel, rim_pixel);
- }
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl
deleted file mode 100644
index d2e20feae18..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-/* ******************************************************************* */
-/* create shadow */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-
-uniform int offset[2];
-uniform float scale[2];
-uniform float rotation;
-uniform vec4 shadow_color;
-
-uniform float amplitude;
-uniform float period;
-uniform float phase;
-uniform int orientation;
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-#define M_PI 3.1415926535897932384626433832795
-
-#define HORIZONTAL 0
-#define VERTICAL 1
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 noffset = vec2(offset[0], offset[1]);
-float cosv = cos(rotation);
-float sinv = sin(rotation);
-
-out vec4 FragColor;
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- /* need to calculate ndc because this is not done by vertex shader */
- vec3 ndc = vec3(vertex).xyz / vertex.w;
-
- vec2 sc;
- sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
- sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
-
- return sc;
-}
-
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
- vec2 loc2d = toScreenSpace(nloc);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) :
- (noffset[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) :
- (noffset[1] / defaultpixsize);
-
- /* move point to new coords system */
- vec2 tpos = vec2(uv.x, uv.y) - loc2d;
-
- /* rotation */
- if (rotation != 0) {
- vec2 rotpoint = vec2((tpos.x * cosv) - (tpos.y * sinv), (tpos.x * sinv) + (tpos.y * cosv));
- tpos = rotpoint;
- }
-
- /* apply offset */
- tpos = vec2(tpos.x - dx, tpos.y - dy);
-
- /* apply scale */
- tpos.x *= 1.0 / scale[0];
- tpos.y *= 1.0 / scale[1];
-
- /* back to original coords system */
- vec2 texpos = tpos + loc2d;
-
- /* wave */
- if (orientation == HORIZONTAL) {
- float pval = (uv.x * M_PI) / Viewport[0];
- texpos.y += amplitude * sin((period * pval) + phase);
- }
- else if (orientation == VERTICAL) {
- float pval = (uv.y * M_PI) / Viewport[1];
- texpos.x += amplitude * sin((period * pval) + phase);
- }
-
- vec4 src_pixel = texelFetch(strokeColor, ivec2(texpos.x, texpos.y), 0);
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
-
- gl_FragDepth = texelFetch(strokeDepth, ivec2(texpos.x, texpos.y), 0).r;
- FragColor = shadow_color;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl
deleted file mode 100644
index 3ef11008adf..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-/* ******************************************************************* */
-/* Resolve Shadow pass */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D shadowColor;
-uniform sampler2D shadowDepth;
-
-out vec4 FragColor;
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- float shadow_depth = texelFetch(shadowDepth, uv.xy, 0).r;
- vec4 stroke_pixel = texelFetch(strokeColor, uv.xy, 0);
- vec4 shadow_pixel = texelFetch(shadowColor, uv.xy, 0);
-
- /* copy original pixel */
- vec4 outcolor = stroke_pixel;
- float outdepth = stroke_depth;
-
- /* if stroke is not on top, copy shadow */
- if ((stroke_pixel.a <= 0.2) && (shadow_pixel.a > 0.0)) {
- outcolor = shadow_pixel;
- outdepth = shadow_depth;
- }
-
- gl_FragDepth = outdepth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
deleted file mode 100644
index 01d4fe40195..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
+++ /dev/null
@@ -1,74 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform vec2 Viewport;
-uniform vec3 loc;
-uniform int radius;
-uniform float angle;
-uniform int transparent;
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-out vec4 FragColor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- /* need to calculate ndc because this is not done by vertex shader */
- vec3 ndc = vec3(vertex).xyz / vertex.w;
-
- vec2 sc;
- sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
- sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
-
- return sc;
-}
-
-/* This swirl shader is a modified version of original Geeks3d.com code */
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- float stroke_depth;
- vec4 outcolor;
-
- vec4 center3d = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
- vec2 center = toScreenSpace(center3d);
- vec2 tc = uv - center;
-
- float dist = length(tc);
- float locpixsize = abs((loc.z * defaultpixsize));
- if (locpixsize == 0) {
- locpixsize = 1;
- }
- float pxradius = (ProjectionMatrix[3][3] == 0.0) ? (radius / locpixsize) :
- (radius / defaultpixsize);
- pxradius = max(pxradius, 1);
-
- if (dist <= pxradius) {
- float percent = (pxradius - dist) / pxradius;
- float theta = percent * percent * angle * 8.0;
- float s = sin(theta);
- float c = cos(theta);
- tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
- tc += center;
-
- stroke_depth = texelFetch(strokeDepth, ivec2(tc), 0).r;
- outcolor = texelFetch(strokeColor, ivec2(tc), 0);
- }
- else {
- if (transparent == 1) {
- discard;
- }
- stroke_depth = texelFetch(strokeDepth, ivec2(uv), 0).r;
- outcolor = texelFetch(strokeColor, ivec2(uv), 0);
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl
deleted file mode 100644
index 0a5df9f6d77..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform float amplitude;
-uniform float period;
-uniform float phase;
-uniform int orientation;
-uniform vec2 wsize;
-
-#define M_PI 3.1415926535897932384626433832795
-
-#define HORIZONTAL 0
-#define VERTICAL 1
-
-void main()
-{
- vec4 outcolor;
- ivec2 uv = ivec2(gl_FragCoord.xy);
- float stroke_depth;
-
- float value;
- if (orientation == HORIZONTAL) {
- float pval = (uv.x * M_PI) / wsize[0];
- value = amplitude * sin((period * pval) + phase);
- outcolor = texelFetch(strokeColor, ivec2(uv.x, uv.y + value), 0);
- stroke_depth = texelFetch(strokeDepth, ivec2(uv.x, uv.y + value), 0).r;
- }
- else {
- float pval = (uv.y * M_PI) / wsize[1];
- value = amplitude * sin((period * pval) + phase);
- outcolor = texelFetch(strokeColor, ivec2(uv.x + value, uv.y), 0);
- stroke_depth = texelFetch(strokeDepth, ivec2(uv.x + value, uv.y), 0).r;
- }
-
- FragColor = outcolor;
- gl_FragDepth = stroke_depth;
-
- if (outcolor.a < 0.02f) {
- discard;
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
new file mode 100644
index 00000000000..b512b54e392
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
@@ -0,0 +1,64 @@
+
+uniform sampler2D edgesTex;
+uniform sampler2D areaTex;
+uniform sampler2D searchTex;
+uniform sampler2D blendTex;
+uniform sampler2D colorTex;
+uniform sampler2D revealTex;
+uniform bool onlyAlpha;
+uniform bool doAntiAliasing;
+
+in vec2 uvs;
+in vec2 pixcoord;
+in vec4 offset[3];
+
+#if SMAA_STAGE == 0
+out vec2 fragColor;
+#elif SMAA_STAGE == 1
+out vec4 fragColor;
+#elif SMAA_STAGE == 2
+/* Reminder: Blending func is fragRevealage * DST + fragColor .*/
+layout(location = 0, index = 0) out vec4 outColor;
+layout(location = 0, index = 1) out vec4 outReveal;
+#endif
+
+void main()
+{
+#if SMAA_STAGE == 0
+ /* Detect edges in color and revealage buffer. */
+ fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
+ fragColor = max(fragColor, SMAALumaEdgeDetectionPS(uvs, offset, revealTex));
+ /* Discard if there is no edge. */
+ if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
+ discard;
+ }
+
+#elif SMAA_STAGE == 1
+ fragColor = SMAABlendingWeightCalculationPS(
+ uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
+
+#elif SMAA_STAGE == 2
+ /* Resolve both buffers. */
+ if (doAntiAliasing) {
+ outColor = SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex);
+ outReveal = SMAANeighborhoodBlendingPS(uvs, offset[0], revealTex, blendTex);
+ }
+ else {
+ outColor = texture(colorTex, uvs);
+ outReveal = texture(revealTex, uvs);
+ }
+
+ /* Revealage, how much light passes through. */
+ /* Average for alpha channel. */
+ outReveal.a = clamp(dot(outReveal.rgb, vec3(0.333334)), 0.0, 1.0);
+ /* Color buf is already premultiplied. Just add it to the color. */
+ /* Add the alpha. */
+ outColor.a = 1.0 - outReveal.a;
+
+ if (onlyAlpha) {
+ /* Special case in wireframe xray mode. */
+ outColor = vec4(0.0);
+ outReveal.rgb = outReveal.aaa;
+ }
+#endif
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
new file mode 100644
index 00000000000..07734d19972
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
@@ -0,0 +1,21 @@
+
+out vec2 uvs;
+out vec2 pixcoord;
+out vec4 offset[3];
+
+void main()
+{
+ int v = gl_VertexID % 3;
+ float x = -1.0 + float((v & 1) << 2);
+ float y = -1.0 + float((v & 2) << 1);
+ gl_Position = vec4(x, y, 1.0, 1.0);
+ uvs = (gl_Position.xy + 1.0) * 0.5;
+
+#if SMAA_STAGE == 0
+ SMAAEdgeDetectionVS(uvs, offset);
+#elif SMAA_STAGE == 1
+ SMAABlendingWeightCalculationVS(uvs, pixcoord, offset);
+#elif SMAA_STAGE == 2
+ SMAANeighborhoodBlendingVS(uvs, offset[0]);
+#endif
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
deleted file mode 100644
index 18803bfa3fa..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
+++ /dev/null
@@ -1,12 +0,0 @@
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- gl_FragDepth = texelFetch(strokeDepth, uv, 0).r;
- FragColor = texelFetch(strokeColor, uv, 0);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
deleted file mode 100644
index 85dee4390a5..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
+++ /dev/null
@@ -1,157 +0,0 @@
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D blendColor;
-uniform sampler2D blendDepth;
-uniform int mode;
-uniform int mask_layer;
-uniform int tonemapping;
-
-#define ON 1
-#define OFF 0
-
-#define MODE_REGULAR 0
-#define MODE_OVERLAY 1
-#define MODE_ADD 2
-#define MODE_SUB 3
-#define MODE_MULTIPLY 4
-#define MODE_DIVIDE 5
-
-float overlay_color(float a, float b)
-{
- float rtn;
- if (a < 0.5) {
- rtn = 2.0 * a * b;
- }
- else {
- rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);
- }
-
- return rtn;
-}
-
-vec4 get_blend_color(int mode, vec4 src_color, vec4 mix_color)
-{
- vec4 outcolor;
-
- if (mix_color.a == 0) {
- return src_color;
- }
-
- switch (mode) {
- case MODE_REGULAR: {
- /* premult */
- src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a);
- mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
-
- outcolor = vec4(mix(src_color.rgb, mix_color.rgb, mix_color.a), src_color.a);
- break;
- }
- case MODE_OVERLAY: {
- src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a);
- mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
-
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor.r = overlay_color(src_color.r, mix_color.r);
- outcolor.g = overlay_color(src_color.g, mix_color.g);
- outcolor.b = overlay_color(src_color.b, mix_color.b);
- outcolor.a = src_color.a;
- break;
- }
- case MODE_ADD: {
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color + mix_color;
- outcolor.a = src_color.a;
- break;
- }
- case MODE_SUB: {
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color - mix_color;
- outcolor.a = clamp(src_color.a - mix_color.a, 0.0, 1.0);
- break;
- }
- case MODE_MULTIPLY: {
- src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a);
- mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
-
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color * mix_color;
- outcolor.a = src_color.a;
- break;
- }
- case MODE_DIVIDE: {
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color / mix_color;
- outcolor.a = src_color.a;
- break;
- }
- default: {
- outcolor = mix_color;
- outcolor.a = src_color.a;
- break;
- }
- }
- return clamp(outcolor, 0.0, 1.0);
-}
-
-float linearrgb_to_srgb(float c)
-{
- if (c < 0.0031308) {
- return (c < 0.0) ? 0.0 : c * 12.92;
- }
- else {
- return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
- }
-}
-
-vec4 tone(vec4 stroke_color)
-{
- if (tonemapping == 1) {
- vec4 color = vec4(0, 0, 0, stroke_color.a);
- color.r = linearrgb_to_srgb(stroke_color.r);
- color.g = linearrgb_to_srgb(stroke_color.g);
- color.b = linearrgb_to_srgb(stroke_color.b);
- return color;
- }
- else {
- return stroke_color;
- }
-}
-
-void main()
-{
- vec4 outcolor;
- ivec2 uv = ivec2(gl_FragCoord.xy);
- vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
- float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
-
- vec4 mix_color = texelFetch(blendColor, uv, 0).rgba;
- float mix_depth = texelFetch(blendDepth, uv, 0).r;
-
- if (stroke_color.a > 0) {
- if (mix_color.a > 0) {
- /* apply blend mode */
- FragColor = get_blend_color(mode, stroke_color, mix_color);
- }
- else {
- FragColor = stroke_color;
- }
- gl_FragDepth = min(stroke_depth, mix_depth);
- }
- else {
- if (mask_layer == ON) {
- discard;
- }
- else {
- /* if not using mask, return mix color */
- FragColor = mix_color;
- gl_FragDepth = mix_depth;
- }
- }
-
- /* apply tone mapping */
- FragColor = tone(FragColor);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
new file mode 100644
index 00000000000..8774b633467
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -0,0 +1,593 @@
+
+/* Must match C declaration. */
+struct gpMaterial {
+ vec4 stroke_color;
+ vec4 fill_color;
+ vec4 fill_mix_color;
+ vec4 fill_uv_rot_scale;
+ vec4 fill_uv_offset;
+ /* Put float/int at the end to avoid padding error */
+ float stroke_texture_mix;
+ float stroke_u_scale;
+ float fill_texture_mix;
+ int flag;
+ /* Please ensure 16 byte alignment (multiple of vec4). */
+};
+
+/* flag */
+#define GP_STROKE_ALIGNMENT_STROKE 1
+#define GP_STROKE_ALIGNMENT_OBJECT 2
+#define GP_STROKE_ALIGNMENT_FIXED 3
+#define GP_STROKE_ALIGNMENT 0x3
+#define GP_STROKE_OVERLAP (1 << 2)
+#define GP_STROKE_TEXTURE_USE (1 << 3)
+#define GP_STROKE_TEXTURE_STENCIL (1 << 4)
+#define GP_STROKE_TEXTURE_PREMUL (1 << 5)
+#define GP_STROKE_DOTS (1 << 6)
+#define GP_FILL_TEXTURE_USE (1 << 10)
+#define GP_FILL_TEXTURE_PREMUL (1 << 11)
+#define GP_FILL_TEXTURE_CLIP (1 << 12)
+#define GP_FILL_GRADIENT_USE (1 << 13)
+#define GP_FILL_GRADIENT_RADIAL (1 << 14)
+/* High bits are used to pass material ID to fragment shader. */
+#define GP_MATID_SHIFT 16
+
+/* Multiline defines can crash blender with certain GPU drivers. */
+/* clang-format off */
+#define GP_FILL_FLAGS (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP | GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL)
+/* clang-format on */
+
+#define GP_FLAG_TEST(flag, val) (((flag) & (val)) != 0)
+
+/* Must match C declaration. */
+struct gpLight {
+ vec4 color_type;
+ vec4 right;
+ vec4 up;
+ vec4 forward;
+ vec4 position;
+ /* Please ensure 16 byte alignment (multiple of vec4). */
+};
+
+#define spot_size right.w
+#define spot_blend up.w
+
+#define GP_LIGHT_TYPE_POINT 0.0
+#define GP_LIGHT_TYPE_SPOT 1.0
+#define GP_LIGHT_TYPE_SUN 2.0
+#define GP_LIGHT_TYPE_AMBIENT 3.0
+
+#ifdef GP_MATERIAL_BUFFER_LEN
+
+layout(std140) uniform gpMaterialBlock
+{
+ gpMaterial materials[GP_MATERIAL_BUFFER_LEN];
+};
+
+#endif
+
+#ifdef GPENCIL_LIGHT_BUFFER_LEN
+
+layout(std140) uniform gpLightBlock
+{
+ gpLight lights[GPENCIL_LIGHT_BUFFER_LEN];
+};
+
+#endif
+
+/* Must match eGPLayerBlendModes */
+#define MODE_REGULAR 0
+#define MODE_OVERLAY 1
+#define MODE_ADD 2
+#define MODE_SUB 3
+#define MODE_MULTIPLY 4
+#define MODE_DIVIDE 5
+#define MODE_OVERLAY_SECOND_PASS 999
+
+void blend_mode_output(
+ int blend_mode, vec4 color, float opacity, out vec4 frag_color, out vec4 frag_revealage)
+{
+ switch (blend_mode) {
+ case MODE_REGULAR:
+ /* Reminder: Blending func is premult alpha blend (dst.rgba * (1 - src.a) + src.rgb).*/
+ color *= opacity;
+ frag_color = color;
+ frag_revealage = vec4(0.0, 0.0, 0.0, color.a);
+ break;
+ case MODE_MULTIPLY:
+ /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/
+ color.a *= opacity;
+ frag_revealage = frag_color = (1.0 - color.a) + color.a * color;
+ break;
+ case MODE_DIVIDE:
+ /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/
+ color.a *= opacity;
+ frag_revealage = frag_color = clamp(1.0 / max(vec4(1e-6), 1.0 - color * color.a), 0.0, 1e18);
+ break;
+ case MODE_OVERLAY:
+ /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/
+ /**
+ * We need to separate the overlay equation into 2 term (one mul and one add).
+ * This is the standard overlay equation (per channel):
+ * rtn = (src < 0.5) ? (2.0 * src * dst) : (1.0 - 2.0 * (1.0 - src) * (1.0 - dst));
+ * We rewrite the second branch like this:
+ * rtn = 1 - 2 * (1 - src) * (1 - dst);
+ * rtn = 1 - 2 (1 - dst + src * dst - src);
+ * rtn = 1 - 2 (1 - dst * (1 - src) - src);
+ * rtn = 1 - 2 + dst * (2 - 2 * src) + 2 * src;
+ * rtn = (- 1 + 2 * src) + dst * (2 - 2 * src);
+ **/
+ color = mix(vec4(0.5), color, color.a * opacity);
+ vec4 s = step(-0.5, -color);
+ frag_revealage = frag_color = 2.0 * s + 2.0 * color * (1.0 - s * 2.0);
+ break;
+ case MODE_OVERLAY_SECOND_PASS:
+ /* Reminder: Blending func is additive blend (dst.rgba + src.rgba).*/
+ color = mix(vec4(0.5), color, color.a * opacity);
+ frag_revealage = frag_color = (-1.0 + 2.0 * color) * step(-0.5, -color);
+ break;
+ case MODE_SUB:
+ case MODE_ADD:
+ /* Reminder: Blending func is additive / subtractive blend (dst.rgba +/- src.rgba).*/
+ frag_color = color * color.a * opacity;
+ frag_revealage = vec4(0.0);
+ break;
+ }
+}
+
+#ifdef GPU_VERTEX_SHADER
+# define IN_OUT out
+#else
+# define IN_OUT in
+#endif
+
+/* Shader interface. */
+IN_OUT vec4 finalColorMul;
+IN_OUT vec4 finalColorAdd;
+IN_OUT vec3 finalPos;
+IN_OUT vec2 finalUvs;
+noperspective IN_OUT float strokeThickness;
+noperspective IN_OUT float strokeHardeness;
+flat IN_OUT vec2 strokeAspect;
+flat IN_OUT vec2 strokePt1;
+flat IN_OUT vec2 strokePt2;
+flat IN_OUT int matFlag;
+flat IN_OUT float depth;
+
+#ifdef GPU_FRAGMENT_SHADER
+
+# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
+
+float stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac)
+{
+ /* We create our own uv space to avoid issues with triangulation and linear
+ * interpolation artifacts. */
+ vec2 line = p2.xy - p1.xy;
+ vec2 pos = gl_FragCoord.xy - p1.xy;
+ float line_len = length(line);
+ float half_line_len = line_len * 0.5;
+ /* Normalize */
+ line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0);
+ /* Create a uv space that englobe the whole segment into a capsule. */
+ vec2 uv_end;
+ uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0);
+ uv_end.y = dot(vec2(-line.y, line.x), pos);
+ /* Divide by stroke radius. */
+ uv_end /= thickness;
+ uv_end *= aspect;
+
+ float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0);
+ if (hardfac > 0.999) {
+ return step(1e-8, dist);
+ }
+ else {
+ /* Modulate the falloff profile */
+ float hardness = 1.0 - hardfac;
+ dist = pow(dist, mix(0.01, 10.0, hardness));
+ return smoothstep(0.0, 1.0, dist);
+ }
+}
+
+#endif
+
+uniform vec2 sizeViewport;
+uniform vec2 sizeViewportInv;
+
+/* Per Object */
+uniform bool strokeOrder3d;
+uniform int gpMaterialOffset;
+uniform float thicknessScale;
+uniform float thicknessWorldScale;
+#define thicknessIsScreenSpace (thicknessWorldScale < 0.0)
+#define MATERIAL(m) materials[m + gpMaterialOffset]
+
+#ifdef GPU_VERTEX_SHADER
+
+/* Per Layer */
+uniform float thicknessOffset;
+uniform float vertexColorOpacity;
+uniform vec4 layerTint;
+uniform float layerOpacity; /* Used for onion skin. */
+uniform float strokeIndexOffset = 0.0;
+
+/* All of these attribs are quad loaded the same way
+ * as GL_LINES_ADJACENCY would feed a geometry shader:
+ * - ma reference the previous adjacency point.
+ * - ma1 reference the current line first point.
+ * - ma2 reference the current line second point.
+ * - ma3 reference the next adjacency point.
+ * Note that we are rendering quad instances and not using any index buffer (except for fills).
+ */
+in vec4 ma;
+in vec4 ma1;
+in vec4 ma2;
+in vec4 ma3;
+# define strength1 ma1.y
+# define strength2 ma2.y
+# define stroke_id1 ma1.z
+# define point_id1 ma1.w
+/* Position contains thickness in 4th component. */
+in vec4 pos; /* Prev adj vert */
+in vec4 pos1; /* Current edge */
+in vec4 pos2; /* Current edge */
+in vec4 pos3; /* Next adj vert */
+# define thickness1 pos1.w
+# define thickness2 pos2.w
+/* xy is UV for fills, z is U of stroke, w is cosine of UV angle with sign of sine. */
+in vec4 uv1;
+in vec4 uv2;
+
+in vec4 col1;
+in vec4 col2;
+
+in vec4 fcol1;
+
+/* hard.x is aspect. */
+in vec2 hard1;
+in vec2 hard2;
+# define aspect1 hard1.x
+# define aspect2 hard2.x
+
+void discard_vert()
+{
+ /* We set the vertex at the camera origin to generate 0 fragments. */
+ gl_Position = vec4(0.0, 0.0, -3e36, 0.0);
+}
+
+vec2 project_to_screenspace(vec4 v)
+{
+ return ((v.xy / v.w) * 0.5 + 0.5) * sizeViewport;
+}
+
+vec2 rotate_90deg(vec2 v)
+{
+ /* Counter Clock-Wise. */
+ return vec2(-v.y, v.x);
+}
+
+mat4 model_matrix_get()
+{
+ return ModelMatrix;
+}
+
+vec3 transform_point(mat4 m, vec3 v)
+{
+ return (m * vec4(v, 1.0)).xyz;
+}
+
+vec2 safe_normalize(vec2 v)
+{
+ float len_sqr = dot(v, v);
+ if (len_sqr > 0.0) {
+ return v / sqrt(len_sqr);
+ }
+ else {
+ return vec2(1.0, 0.0);
+ }
+}
+
+vec2 safe_normalize_len(vec2 v, out float len)
+{
+ len = sqrt(dot(v, v));
+ if (len > 0.0) {
+ return v / len;
+ }
+ else {
+ return vec2(1.0, 0.0);
+ }
+}
+
+float stroke_thickness_modulate(float thickness)
+{
+ /* Modify stroke thickness by object and layer factors.-*/
+ thickness *= thicknessScale;
+ thickness += thicknessOffset;
+ thickness = max(1.0, thickness);
+
+ if (thicknessIsScreenSpace) {
+ /* Multiply offset by view Z so that offset is constant in screenspace.
+ * (e.i: does not change with the distance to camera) */
+ thickness *= gl_Position.w;
+ }
+ else {
+ /* World space point size. */
+ thickness *= thicknessWorldScale * ProjectionMatrix[1][1] * sizeViewport.y;
+ }
+ return thickness;
+}
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+void color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex)
+{
+ /* Mix stroke with other colors. */
+ vec4 mixed_col = stroke_col;
+ mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a * vertexColorOpacity);
+ mixed_col.rgb = mix(mixed_col.rgb, layerTint.rgb, layerTint.a);
+ mixed_col.a *= vert_strength * layerOpacity;
+ /**
+ * This is what the fragment shader looks like.
+ * out = col * finalColorMul + col.a * finalColorAdd.
+ * finalColorMul is how much of the texture color to keep.
+ * finalColorAdd is how much of the mixed color to add.
+ * Note that we never add alpha. This is to keep the texture act as a stencil.
+ * We do however, modulate the alpha (reduce it).
+ **/
+ /* We add the mixed color. This is 100% mix (no texture visible). */
+ finalColorMul = vec4(mixed_col.aaa, mixed_col.a);
+ finalColorAdd = vec4(mixed_col.rgb * mixed_col.a, 0.0);
+ /* Then we blend according to the texture mix factor.
+ * Note that we keep the alpha modulation. */
+ finalColorMul.rgb *= mix_tex;
+ finalColorAdd.rgb *= 1.0 - mix_tex;
+}
+# endif
+
+void stroke_vertex()
+{
+ int m = int(ma1.x);
+ bool is_dot = false;
+ bool is_squares = false;
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+ if (m != -1.0) {
+ is_dot = GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_ALIGNMENT);
+ is_squares = !GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_DOTS);
+ }
+# endif
+
+ /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */
+ if (!is_dot && ma.x == -1.0 && ma2.x == -1.0) {
+ is_dot = true;
+ is_squares = false;
+ }
+
+ /* Enpoints, we discard the vertices. */
+ if (ma1.x == -1.0 || (!is_dot && ma2.x == -1.0)) {
+ discard_vert();
+ return;
+ }
+
+ mat4 model_mat = model_matrix_get();
+
+ /* Avoid using a vertex attrib for quad positioning. */
+ float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */
+ float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */
+
+ bool use_curr = is_dot || (x == -1.0);
+
+ vec3 wpos_adj = transform_point(model_mat, (use_curr) ? pos.xyz : pos3.xyz);
+ vec3 wpos1 = transform_point(model_mat, pos1.xyz);
+ vec3 wpos2 = transform_point(model_mat, pos2.xyz);
+
+ vec4 ndc_adj = point_world_to_ndc(wpos_adj);
+ vec4 ndc1 = point_world_to_ndc(wpos1);
+ vec4 ndc2 = point_world_to_ndc(wpos2);
+
+ gl_Position = (use_curr) ? ndc1 : ndc2;
+ finalPos = (use_curr) ? wpos1 : wpos2;
+
+ vec2 ss_adj = project_to_screenspace(ndc_adj);
+ vec2 ss1 = project_to_screenspace(ndc1);
+ vec2 ss2 = project_to_screenspace(ndc2);
+ /* Screenspace Lines tangents. */
+ float line_len;
+ vec2 line = safe_normalize_len(ss2 - ss1, line_len);
+ vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2));
+
+ float thickness = abs((use_curr) ? thickness1 : thickness2);
+ thickness = stroke_thickness_modulate(thickness);
+
+ finalUvs = vec2(x, y) * 0.5 + 0.5;
+ strokeHardeness = (use_curr) ? hard1.y : hard2.y;
+
+ if (is_dot) {
+# ifdef GP_MATERIAL_BUFFER_LEN
+ int alignement = MATERIAL(m).flag & GP_STROKE_ALIGNMENT;
+# endif
+
+ vec2 x_axis;
+# ifdef GP_MATERIAL_BUFFER_LEN
+ if (alignement == GP_STROKE_ALIGNMENT_STROKE) {
+ x_axis = (ma2.x == -1.0) ? line_adj : line;
+ }
+ else if (alignement == GP_STROKE_ALIGNMENT_FIXED) {
+ /* Default for no-material drawing. */
+ x_axis = vec2(1.0, 0.0);
+ }
+ else
+# endif
+ { /* GP_STROKE_ALIGNMENT_OBJECT */
+ vec4 ndc_x = point_world_to_ndc(wpos1 + model_mat[0].xyz);
+ vec2 ss_x = project_to_screenspace(ndc_x);
+ x_axis = safe_normalize(ss_x - ss1);
+ }
+
+ /* Rotation: Encoded as Cos + Sin sign. */
+ float rot_sin = sqrt(1.0 - uv1.w * uv1.w) * sign(uv1.w);
+ float rot_cos = abs(uv1.w);
+ x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis;
+
+ vec2 y_axis = rotate_90deg(x_axis);
+
+ strokeAspect.x = aspect1;
+
+ if (strokeAspect.x > 1.0) {
+ strokeAspect.y = strokeAspect.x;
+ strokeAspect.x = 1.0;
+ }
+ else {
+ strokeAspect.x = 1.0 / strokeAspect.x;
+ strokeAspect.y = 1.0;
+ }
+
+ x /= strokeAspect.x;
+ y /= strokeAspect.y;
+
+ gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * thickness;
+
+ strokePt1 = ss1;
+ strokePt2 = ss1 + x_axis * 0.5;
+ strokeThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w);
+ }
+ else {
+ bool is_stroke_start = (ma.x == -1.0 && x == -1.0);
+ bool is_stroke_end = (ma3.x == -1.0 && x == 1.0);
+
+ /* Mitter tangent vector. */
+ vec2 miter_tan = safe_normalize(line_adj + line);
+ float miter_dot = dot(miter_tan, line_adj);
+ /* Break corners after a certain angle to avoid really thick corners. */
+ const float miter_limit = 0.5; /* cos(60°) */
+ bool miter_break = (miter_dot < miter_limit) || is_stroke_start || is_stroke_end;
+ miter_tan = (miter_break) ? line : (miter_tan / miter_dot);
+
+ vec2 miter = rotate_90deg(miter_tan);
+
+ strokePt1.xy = ss1;
+ strokePt2.xy = ss2;
+ strokeThickness = thickness / gl_Position.w;
+ strokeAspect = vec2(1.0);
+
+ vec2 screen_ofs = miter * y;
+
+ /* Reminder: we packed the cap flag into the sign of stength and thickness sign. */
+ if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) ||
+ miter_break) {
+ screen_ofs += line * x;
+ }
+
+ gl_Position.xy += screen_ofs * sizeViewportInv.xy * thickness;
+
+ finalUvs.x = (use_curr) ? uv1.z : uv2.z;
+# ifdef GP_MATERIAL_BUFFER_LEN
+ finalUvs.x *= MATERIAL(m).stroke_u_scale;
+# endif
+ }
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+ vec4 vert_col = (use_curr) ? col1 : col2;
+ float vert_strength = abs((use_curr) ? strength1 : strength2);
+ vec4 stroke_col = MATERIAL(m).stroke_color;
+ float mix_tex = MATERIAL(m).stroke_texture_mix;
+
+ color_output(stroke_col, vert_col, vert_strength, mix_tex);
+
+ matFlag = MATERIAL(m).flag & ~GP_FILL_FLAGS;
+# endif
+
+ if (strokeOrder3d) {
+ /* Use the fragment depth (see fragment shader). */
+ depth = -1.0;
+ }
+# ifdef GP_MATERIAL_BUFFER_LEN
+ else if (GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_OVERLAP)) {
+ /* Use the index of the point as depth.
+ * This means the stroke can overlap itself. */
+ depth = (point_id1 + strokeIndexOffset + 1.0) * 0.0000002;
+ }
+# endif
+ else {
+ /* Use the index of first point of the stroke as depth.
+ * We render using a greater depth test this means the stroke
+ * cannot overlap itself.
+ * We offset by one so that the fill can be overlapped by its stroke.
+ * The offset is ok since we pad the strokes data because of adjacency infos. */
+ depth = (stroke_id1 + strokeIndexOffset + 1.0) * 0.0000002;
+ }
+}
+
+void fill_vertex()
+{
+ mat4 model_mat = model_matrix_get();
+
+ vec3 wpos = transform_point(model_mat, pos1.xyz);
+ gl_Position = point_world_to_ndc(wpos);
+ finalPos = wpos;
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+ int m = int(ma1.x);
+
+ vec4 fill_col = MATERIAL(m).fill_color;
+ float mix_tex = MATERIAL(m).fill_texture_mix;
+
+ /* Special case: We don't modulate alpha in gradient mode. */
+ if (GP_FLAG_TEST(MATERIAL(m).flag, GP_FILL_GRADIENT_USE)) {
+ fill_col.a = 1.0;
+ }
+
+ /* Decode fill opacity. */
+ vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0));
+ float fill_opacity = fcol1.a - (fcol_decode.a * 10);
+ fcol_decode.a /= 10000.0f;
+
+ /* Apply opacity. */
+ fill_col.a *= fill_opacity;
+ /* If factor is > 1 force opacity. */
+ if (fill_opacity > 1.0) {
+ fill_col.a += fill_opacity - 1.0f;
+ }
+
+ fill_col.a = clamp(fill_col.a, 0.0, 1.0);
+
+ color_output(fill_col, fcol_decode, 1.0, mix_tex);
+
+ matFlag = MATERIAL(m).flag & GP_FILL_FLAGS;
+ matFlag |= m << GP_MATID_SHIFT;
+
+ vec2 loc = MATERIAL(m).fill_uv_offset.xy;
+ mat2x2 rot_scale = mat2x2(MATERIAL(m).fill_uv_rot_scale.xy, MATERIAL(m).fill_uv_rot_scale.zw);
+ finalUvs = rot_scale * uv1.xy + loc;
+# endif
+
+ strokeThickness = 1e18;
+ strokeAspect = vec2(1.0);
+ strokePt1 = strokePt2 = vec2(0.0);
+
+ if (strokeOrder3d) {
+ /* Use the fragment depth (see fragment shader). */
+ depth = -1.0;
+ /* We still offset the fills a little to avoid overlaps */
+ gl_Position.z += 0.000002;
+ }
+ else {
+ /* Use the index of first point of the stroke as depth. */
+ depth = (stroke_id1 + strokeIndexOffset) * 0.0000002;
+ }
+}
+
+void gpencil_vertex()
+{
+ /* Trick to detect if a drawcall is stroke or fill.
+ * This does mean that we need to draw an empty stroke segment before starting
+ * to draw the real stroke segments. */
+ bool is_fill = (gl_InstanceID == 0);
+
+ if (!is_fill) {
+ stroke_vertex();
+ }
+ else {
+ fill_vertex();
+ }
+}
+
+#endif
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
new file mode 100644
index 00000000000..71597197bd8
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
@@ -0,0 +1,17 @@
+
+uniform sampler2D depthBuf;
+uniform float strokeDepth2d;
+uniform bool strokeOrder3d;
+
+noperspective in vec4 uvcoordsvar;
+
+void main()
+{
+ float depth = textureLod(depthBuf, uvcoordsvar.xy, 0).r;
+ if (strokeOrder3d) {
+ gl_FragDepth = depth;
+ }
+ else {
+ gl_FragDepth = (depth != 0.0) ? gl_FragCoord.z : 1.0;
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
new file mode 100644
index 00000000000..1e5a900f486
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
@@ -0,0 +1,14 @@
+
+uniform vec4 gpModelMatrix[4];
+
+noperspective out vec4 uvcoordsvar;
+
+void main()
+{
+ mat4 model_matrix = mat4(gpModelMatrix[0], gpModelMatrix[1], gpModelMatrix[2], gpModelMatrix[3]);
+ int v = gl_VertexID % 3;
+ float x = -1.0 + float((v & 1) << 2);
+ float y = -1.0 + float((v & 2) << 1);
+ gl_Position = ViewProjectionMatrix * (model_matrix * vec4(x, y, 0.0, 1.0));
+ uvcoordsvar = vec4((gl_Position.xy / gl_Position.w + 1.0) * 0.5, 0.0, 0.0);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
deleted file mode 100644
index 6a2a4f68dc9..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-in vec4 mColor;
-in vec2 mTexCoord;
-out vec4 fragColor;
-
-void main()
-{
- vec2 centered = mTexCoord - vec2(0.5);
- float dist_squared = dot(centered, centered);
- const float rad_squared = 0.25;
-
- // round point with jaggy edges
- if (dist_squared > rad_squared) {
- discard;
- }
-
- fragColor = mColor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl
deleted file mode 100644
index e0634a7d1a7..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl
+++ /dev/null
@@ -1,53 +0,0 @@
-uniform vec2 Viewport;
-
-layout(points) in;
-layout(triangle_strip, max_vertices = 4) out;
-
-in vec4 finalColor[1];
-in float finalThickness[1];
-
-out vec4 mColor;
-out vec2 mTexCoord;
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- return vec2(vertex.xy / vertex.w) * Viewport;
-}
-
-/* get zdepth value */
-float getZdepth(vec4 point)
-{
- return min(-0.05, (point.z / point.w));
-}
-
-void main(void)
-{
- vec4 P0 = gl_in[0].gl_Position;
- vec2 sp0 = toScreenSpace(P0);
-
- float size = finalThickness[0];
-
- /* generate the triangle strip */
- mTexCoord = vec2(0, 1);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x - size, sp0.y + size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x - size, sp0.y - size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(1, 1);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x + size, sp0.y + size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(1, 0);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x + size, sp0.y - size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
deleted file mode 100644
index 57908f3251b..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in float size;
-
-out vec4 finalColor;
-out float finalThickness;
-
-void main()
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalColor = color;
- finalThickness = size;
-
- /* Dirty fix waiting for new GPencil engine. */
- finalColor.rgb = pow(finalColor.rgb, vec3(2.2));
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
deleted file mode 100644
index 8285541e0b4..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
+++ /dev/null
@@ -1,234 +0,0 @@
-uniform vec4 color2;
-uniform int fill_type;
-uniform float mix_factor;
-
-uniform float gradient_angle;
-uniform float gradient_radius;
-uniform float pattern_gridsize;
-uniform vec2 gradient_scale;
-uniform vec2 gradient_shift;
-
-uniform float texture_angle;
-uniform vec2 texture_scale;
-uniform vec2 texture_offset;
-uniform int texture_mix;
-uniform int texture_flip;
-uniform float texture_opacity;
-uniform int xraymode;
-uniform int drawmode;
-uniform float layer_opacity;
-
-uniform sampler2D myTexture;
-uniform bool myTexturePremultiplied;
-uniform int texture_clamp;
-
-uniform int viewport_xray;
-uniform int shading_type[2];
-uniform vec4 wire_color;
-
-uniform int fade_layer;
-uniform float fade_layer_factor;
-uniform bool fade_ob;
-uniform vec3 fade_color;
-uniform float fade_ob_factor;
-
-/* keep this list synchronized with list in gpencil_draw_utils.c */
-#define SOLID 0
-#define GRADIENT 1
-#define RADIAL 2
-#define CHECKER 3
-#define TEXTURE 4
-#define PATTERN 5
-
-#define GP_XRAY_FRONT 0
-#define GP_XRAY_3DSPACE 1
-
-#define GP_DRAWMODE_2D 0
-#define GP_DRAWMODE_3D 1
-
-#define OB_WIRE 2
-#define OB_SOLID 3
-
-#define V3D_SHADING_MATERIAL_COLOR 0
-#define V3D_SHADING_TEXTURE_COLOR 3
-#define V3D_SHADING_VERTEX_COLOR 5
-
-in vec4 finalColor;
-in vec2 texCoord_interp;
-out vec4 fragColor;
-#define texture2D texture
-
-void set_color(in vec4 color,
- in vec4 color2,
- in vec4 tcolor,
- in float mixv,
- in float factor,
- in int tmix,
- in int flip,
- out vec4 ocolor)
-{
- /* full color A */
- if (mixv == 1.0) {
- if (tmix == 1) {
- ocolor = (flip == 0) ? color : tcolor;
- }
- else {
- ocolor = (flip == 0) ? color : color2;
- }
- }
- /* full color B */
- else if (mixv == 0.0) {
- if (tmix == 1) {
- ocolor = (flip == 0) ? tcolor : color;
- }
- else {
- ocolor = (flip == 0) ? color2 : color;
- }
- }
- /* mix of colors */
- else {
- if (tmix == 1) {
- ocolor = (flip == 0) ? mix(color, tcolor, factor) : mix(tcolor, color, factor);
- }
- else {
- ocolor = (flip == 0) ? mix(color, color2, factor) : mix(color2, color, factor);
- }
- }
- ocolor.a *= layer_opacity;
-}
-
-void main()
-{
- vec2 t_center = vec2(0.5, 0.5);
- mat2 matrot_tex = mat2(
- cos(texture_angle), -sin(texture_angle), sin(texture_angle), cos(texture_angle));
- vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + texture_offset;
- vec4 tmp_color;
- tmp_color = (texture_clamp == 0) ?
- texture_read_as_srgb(
- myTexture, myTexturePremultiplied, rot_tex * texture_scale) :
- texture_read_as_srgb(
- myTexture, myTexturePremultiplied, clamp(rot_tex * texture_scale, 0.0, 1.0));
- vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * texture_opacity);
- vec4 checker_color;
-
- /* wireframe with x-ray discard */
- if ((viewport_xray == 1) && (shading_type[0] == OB_WIRE)) {
- discard;
- }
-
- /* solid fill */
- if (fill_type == SOLID) {
- fragColor = finalColor;
- }
- else {
- vec2 center = vec2(0.5, 0.5) + gradient_shift;
- mat2 matrot = mat2(
- cos(gradient_angle), -sin(gradient_angle), sin(gradient_angle), cos(gradient_angle));
- vec2 rot = (((matrot * (texCoord_interp - center)) + center) * gradient_scale) +
- gradient_shift;
- /* gradient */
- if (fill_type == GRADIENT) {
- set_color(finalColor,
- color2,
- text_color,
- mix_factor,
- rot.x - mix_factor + 0.5,
- texture_mix,
- texture_flip,
- fragColor);
- }
- /* radial gradient */
- if (fill_type == RADIAL) {
- float in_rad = gradient_radius * mix_factor;
- float ex_rad = gradient_radius - in_rad;
- float intensity = 0;
- float distance = length((center - texCoord_interp) * gradient_scale);
- if (distance > gradient_radius) {
- discard;
- }
- if (distance > in_rad) {
- intensity = clamp(((distance - in_rad) / ex_rad), 0.0, 1.0);
- }
- set_color(finalColor,
- color2,
- text_color,
- mix_factor,
- intensity,
- texture_mix,
- texture_flip,
- fragColor);
- }
- /* Checkerboard */
- if (fill_type == CHECKER) {
- vec2 pos = rot / pattern_gridsize;
- if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) ||
- (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) {
- checker_color = (texture_flip == 0) ? finalColor : color2;
- }
- else {
- checker_color = (texture_flip == 0) ? color2 : finalColor;
- }
- /* mix with texture */
- fragColor = (texture_mix == 1) ? mix(checker_color, text_color, mix_factor) : checker_color;
- fragColor.a *= layer_opacity;
- }
- /* texture */
- if (fill_type == TEXTURE) {
- fragColor = (texture_mix == 1) ? mix(text_color, finalColor, mix_factor) : text_color;
- fragColor.a *= layer_opacity;
- }
- /* pattern */
- if (fill_type == PATTERN) {
- fragColor = finalColor;
- fragColor.a = min(text_color.a, finalColor.a) * layer_opacity;
- }
- }
-
- /* set zdepth */
- if (xraymode == GP_XRAY_FRONT) {
- gl_FragDepth = min(-0.05, (gl_FragCoord.z / gl_FragCoord.w));
- }
- else if (xraymode == GP_XRAY_3DSPACE) {
- /* if 3D mode, move slightly the fill to avoid z-fighting between stroke and fill on same
- * stroke */
- if (drawmode == GP_DRAWMODE_3D) {
- gl_FragDepth = gl_FragCoord.z * 1.0001;
- }
- else {
- gl_FragDepth = gl_FragCoord.z;
- }
- }
- else {
- gl_FragDepth = 0.000001;
- }
-
- /* if wireframe override colors */
- if (shading_type[0] == OB_WIRE) {
- fragColor = wire_color;
- }
-
- /* for solid override color */
- if (shading_type[0] == OB_SOLID) {
- if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
- (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
- fragColor = wire_color;
- }
- if (viewport_xray == 1) {
- fragColor.a *= 0.5;
- }
- }
- /* Apply paper opacity */
- if (fade_layer == 1) {
- /* Layer is below, mix with background. */
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
- }
- else if (fade_layer == 2) {
- /* Layer is above, change opacity. */
- fragColor.a *= fade_layer_factor;
- }
- else if (fade_ob == true) {
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
deleted file mode 100644
index 263dc570423..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in vec2 texCoord;
-
-out vec4 finalColor;
-out vec2 texCoord_interp;
-
-void main(void)
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalColor = color;
- texCoord_interp = texCoord;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
new file mode 100644
index 00000000000..8c2032f834a
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
@@ -0,0 +1,126 @@
+
+uniform sampler2D gpFillTexture;
+uniform sampler2D gpStrokeTexture;
+uniform sampler2D gpSceneDepthTexture;
+uniform sampler2D gpMaskTexture;
+uniform vec3 gpNormal;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 revealColor;
+
+float length_squared(vec2 v)
+{
+ return dot(v, v);
+}
+float length_squared(vec3 v)
+{
+ return dot(v, v);
+}
+
+vec3 gpencil_lighting(void)
+{
+ vec3 light_accum = vec3(0.0);
+ for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) {
+ if (lights[i].color_type.x == -1.0) {
+ break;
+ }
+ vec3 L = lights[i].position.xyz - finalPos;
+ float vis = 1.0;
+ /* Spot Attenuation. */
+ if (lights[i].color_type.w == GP_LIGHT_TYPE_SPOT) {
+ mat3 rot_scale = mat3(lights[i].right.xyz, lights[i].up.xyz, lights[i].forward.xyz);
+ vec3 local_L = rot_scale * L;
+ local_L /= abs(local_L.z);
+ float ellipse = inversesqrt(length_squared(local_L));
+ vis *= smoothstep(0.0, 1.0, (ellipse - lights[i].spot_size) / lights[i].spot_blend);
+ /* Also mask +Z cone. */
+ vis *= step(0.0, local_L.z);
+ }
+ /* Inverse square decay. Skip for suns. */
+ float L_len_sqr = length_squared(L);
+ if (lights[i].color_type.w < GP_LIGHT_TYPE_SUN) {
+ vis /= L_len_sqr;
+ }
+ else {
+ L = lights[i].forward.xyz;
+ L_len_sqr = 1.0;
+ }
+ /* Lambertian falloff */
+ if (lights[i].color_type.w != GP_LIGHT_TYPE_AMBIENT) {
+ L /= sqrt(L_len_sqr);
+ vis *= clamp(dot(gpNormal, L), 0.0, 1.0);
+ }
+ light_accum += vis * lights[i].color_type.rgb;
+ }
+ /* Clamp to avoid NaNs. */
+ return clamp(light_accum, 0.0, 1e10);
+}
+
+void main()
+{
+ vec4 col;
+ if (GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_USE)) {
+ bool premul = GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_PREMUL);
+ col = texture_read_as_linearrgb(gpStrokeTexture, premul, finalUvs);
+ }
+ else if (GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_USE)) {
+ bool use_clip = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_CLIP);
+ vec2 uvs = (use_clip) ? clamp(finalUvs, 0.0, 1.0) : finalUvs;
+ bool premul = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_PREMUL);
+ col = texture_read_as_linearrgb(gpFillTexture, premul, uvs);
+ }
+ else if (GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_USE)) {
+ bool radial = GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_RADIAL);
+ float fac = clamp(radial ? length(finalUvs * 2.0 - 1.0) : finalUvs.x, 0.0, 1.0);
+ int matid = matFlag >> GP_MATID_SHIFT;
+ col = mix(MATERIAL(matid).fill_color, MATERIAL(matid).fill_mix_color, fac);
+ }
+ else /* SOLID */ {
+ col = vec4(1.0);
+ }
+ col.rgb *= col.a;
+
+ /* Composite all other colors on top of texture color.
+ * Everything is premult by col.a to have the stencil effect. */
+ fragColor = col * finalColorMul + col.a * finalColorAdd;
+
+ fragColor.rgb *= gpencil_lighting();
+
+ fragColor *= stroke_round_cap_mask(
+ strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness);
+
+ /* For compatibility with colored alpha buffer.
+ * Note that we are limited to mono-chromatic alpha blending here
+ * because of the blend equation and the limit of 1 color target
+ * when using custom color blending. */
+ revealColor = vec4(0.0, 0.0, 0.0, fragColor.a);
+
+ if (fragColor.a < 0.001) {
+ discard;
+ }
+
+ /* Manual depth test */
+ vec2 uvs = gl_FragCoord.xy / vec2(textureSize(gpSceneDepthTexture, 0).xy);
+ float scene_depth = texture(gpSceneDepthTexture, uvs).r;
+ if (gl_FragCoord.z > scene_depth) {
+ discard;
+ }
+
+ /* FIXME(fclem) Grrr. This is bad for performance but it's the easiest way to not get
+ * depth written where the mask obliterate the layer. */
+ float mask = texture(gpMaskTexture, uvs).r;
+ if (mask < 0.001) {
+ discard;
+ }
+
+ /* We override the fragment depth using the fragment shader to ensure a constant value.
+ * This has a cost as the depth test cannot happen early.
+ * We could do this in the vertex shader but then perspective interpolation of uvs and
+ * fragment clipping gets really complicated. */
+ if (depth >= 0.0) {
+ gl_FragDepth = depth;
+ }
+ else {
+ gl_FragDepth = gl_FragCoord.z;
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
new file mode 100644
index 00000000000..6fbc7f47dac
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
@@ -0,0 +1,31 @@
+
+uniform sampler2D colorBuf;
+uniform sampler2D revealBuf;
+uniform sampler2D maskBuf;
+uniform int blendMode;
+uniform float blendOpacity;
+
+in vec4 uvcoordsvar;
+
+/* Reminder: This is considered SRC color in blend equations.
+ * Same operation on all buffers. */
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 fragRevealage;
+
+void main()
+{
+ vec4 color;
+
+ /* Remember, this is associated alpha (aka. premult). */
+ color.rgb = textureLod(colorBuf, uvcoordsvar.xy, 0).rgb;
+ /* Stroke only render mono-chromatic revealage. We convert to alpha. */
+ color.a = 1.0 - textureLod(revealBuf, uvcoordsvar.xy, 0).r;
+
+ float mask = textureLod(maskBuf, uvcoordsvar.xy, 0).r;
+ mask *= blendOpacity;
+
+ fragColor = vec4(1.0, 0.0, 1.0, 1.0);
+ fragRevealage = vec4(1.0, 0.0, 1.0, 1.0);
+
+ blend_mode_output(blendMode, color, mask, fragColor, fragRevealage);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
new file mode 100644
index 00000000000..b21b4147087
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
@@ -0,0 +1,11 @@
+
+in vec4 uvcoordsvar;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 fragRevealage;
+
+void main()
+{
+ /* Blend mode does the inversion. */
+ fragRevealage = fragColor = vec4(1.0);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
deleted file mode 100644
index 1d1cd6349dc..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform vec3 color;
-uniform float opacity;
-
-out vec4 FragColor;
-
-void main()
-{
- FragColor = vec4(color, 1.0 - opacity);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
deleted file mode 100644
index d79b8fb4d8a..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
+++ /dev/null
@@ -1,126 +0,0 @@
-uniform int color_type;
-uniform int mode;
-uniform sampler2D myTexture;
-uniform bool myTexturePremultiplied;
-
-uniform float gradient_f;
-uniform vec2 gradient_s;
-
-uniform vec4 colormix;
-uniform float mix_stroke_factor;
-uniform int shading_type[2];
-
-in vec4 mColor;
-in vec2 mTexCoord;
-out vec4 fragColor;
-
-uniform int fade_layer;
-uniform float fade_layer_factor;
-uniform bool fade_ob;
-uniform vec3 fade_color;
-uniform float fade_ob_factor;
-
-#define texture2D texture
-
-#define GPENCIL_MODE_LINE 0
-#define GPENCIL_MODE_DOTS 1
-#define GPENCIL_MODE_BOX 2
-
-/* keep this list synchronized with list in gpencil_engine.h */
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-#define OB_SOLID 3
-#define V3D_SHADING_TEXTURE_COLOR 3
-
-bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR);
-
-/* Function to check the point inside ellipse */
-float check_ellipse_point(vec2 pt, vec2 radius)
-{
- float p = (pow(pt.x, 2) / pow(radius.x, 2)) + (pow(pt.y, 2) / pow(radius.y, 2));
-
- return p;
-}
-
-/* Function to check the point inside box */
-vec2 check_box_point(vec2 pt, vec2 radius)
-{
- vec2 rtn;
- rtn.x = abs(pt.x) / radius.x;
- rtn.y = abs(pt.y) / radius.y;
-
- return rtn;
-}
-
-void main()
-{
- vec2 centered = mTexCoord - vec2(0.5);
- float ellip = check_ellipse_point(centered, vec2(gradient_s / 2.0));
- vec2 box;
-
- if (mode != GPENCIL_MODE_BOX) {
- if (ellip > 1.0) {
- discard;
- }
- }
- else {
- box = check_box_point(centered, vec2(gradient_s / 2.0));
- if ((box.x > 1.0) || (box.y > 1.0)) {
- discard;
- }
- }
-
- /* Solid */
- if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) {
- fragColor = mColor;
- }
- /* texture */
- if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) {
- vec4 text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord);
- if (mix_stroke_factor > 0.0) {
- fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor);
- fragColor.a = text_color.a;
- }
- else {
- fragColor = text_color;
- }
-
- /* mult both alpha factor to use strength factor with texture */
- fragColor.a = min(fragColor.a * mColor.a, fragColor.a);
- }
- /* pattern */
- if ((color_type == GPENCIL_COLOR_PATTERN) && (!no_texture)) {
- vec4 text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord);
- fragColor = mColor;
- /* mult both alpha factor to use strength factor with color alpha limit */
- fragColor.a = min(text_color.a * mColor.a, mColor.a);
- }
-
- if (gradient_f < 1.0) {
- float dist = length(centered) * 2.0;
- float decay = dist * (1.0 - gradient_f) * fragColor.a;
- fragColor.a = clamp(fragColor.a - decay, 0.0, 1.0);
- if (mode == GPENCIL_MODE_DOTS) {
- fragColor.a = fragColor.a * (1.0 - ellip);
- }
- }
-
- if (fragColor.a < 0.0035) {
- discard;
- }
-
- /* Apply paper opacity */
- if (fade_layer == 1) {
- /* Layer is below, mix with background. */
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
- }
- else if (fade_layer == 2) {
- /* Layer is above, change opacity. */
- fragColor.a *= fade_layer_factor;
- }
- else if (fade_ob == true) {
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
deleted file mode 100644
index a2f4c1f9b15..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
+++ /dev/null
@@ -1,142 +0,0 @@
-uniform vec2 Viewport;
-uniform int xraymode;
-uniform int alignment_mode;
-
-layout(points) in;
-layout(triangle_strip, max_vertices = 4) out;
-
-in vec4 finalColor[1];
-in float finalThickness[1];
-in vec2 finaluvdata[1];
-in vec4 finalprev_pos[1];
-
-out vec4 mColor;
-out vec2 mTexCoord;
-
-#define GP_XRAY_FRONT 0
-#define GP_XRAY_3DSPACE 1
-
-#define M_PI 3.14159265358979323846 /* pi */
-#define M_2PI 6.28318530717958647692 /* 2*pi */
-#define FALSE 0
-
-/* keep this definition equals to GP_STYLE_FOLLOW_FIXED value */
-#define FIXED 2
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- return vec2(vertex.xy / vertex.w) * Viewport;
-}
-
-/* get zdepth value */
-float getZdepth(vec4 point)
-{
- if (xraymode == GP_XRAY_FRONT) {
- return min(-0.05, (point.z / point.w));
- }
- if (xraymode == GP_XRAY_3DSPACE) {
- return (point.z / point.w);
- }
-
- /* in front by default */
- return 0.000001;
-}
-
-vec2 rotateUV(vec2 uv, float angle)
-{
- /* translate center of rotation to the center of texture */
- vec2 new_uv = uv - vec2(0.5f, 0.5f);
- vec2 rot_uv;
- rot_uv.x = new_uv.x * cos(angle) - new_uv.y * sin(angle);
- rot_uv.y = new_uv.y * cos(angle) + new_uv.x * sin(angle);
- return rot_uv + vec2(0.5f, 0.5f);
-}
-
-vec2 rotatePoint(vec2 center, vec2 point, float angle)
-{
- /* translate center of rotation to the center */
- vec2 new_point = point - center;
- vec2 rot_point;
- rot_point.x = new_point.x * cos(angle) - new_point.y * sin(angle);
- rot_point.y = new_point.y * cos(angle) + new_point.x * sin(angle);
- return rot_point + center;
-}
-
-/* Calculate angle of the stroke using previous point as reference.
- * The angle is calculated using the x axis (1, 0) as 0 degrees */
-float getAngle(vec2 pt0, vec2 pt1)
-{
- /* do not rotate one point only (no reference to rotate) */
- if (pt0 == pt1) {
- return 0.0;
- }
-
- if (alignment_mode == FIXED) {
- return 0.0;
- }
-
- /* default horizontal line (x-axis) in screen space */
- vec2 v0 = vec2(1.0, 0.0);
-
- /* vector of direction */
- vec2 vn = vec2(normalize(pt1 - pt0));
-
- /* angle signed (function ported from angle_signed_v2v2) */
- float perp_dot = (v0[1] * vn[0]) - (v0[0] * vn[1]);
- float angle = atan(perp_dot, dot(v0, vn));
-
- /* get full circle rotation */
- if (angle > 0.0) {
- angle = M_PI + (M_PI - angle);
- }
- else {
- angle *= -1.0;
- }
-
- return angle;
-}
-
-void main(void)
-{
- /* receive points */
- vec4 P0 = gl_in[0].gl_Position;
- vec2 sp0 = toScreenSpace(P0);
-
- vec4 P1 = finalprev_pos[0];
- vec2 sp1 = toScreenSpace(P1);
- vec2 point;
-
- float size = finalThickness[0];
- vec2 center = vec2(sp0.x, sp0.y);
-
- /* get angle of stroke to rotate texture */
- float angle = getAngle(sp0, sp1);
-
- /* generate the triangle strip */
- mTexCoord = rotateUV(vec2(0, 1), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x - size, sp0.y + size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = rotateUV(vec2(0, 0), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x - size, sp0.y - size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = rotateUV(vec2(1, 1), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x + size, sp0.y + size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = rotateUV(vec2(1, 0), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x + size, sp0.y - size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
deleted file mode 100644
index 33d7d714231..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
+++ /dev/null
@@ -1,66 +0,0 @@
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform int keep_size;
-uniform float objscale;
-uniform float pixfactor;
-uniform int viewport_xray;
-uniform int shading_type[2];
-uniform vec4 wire_color;
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in float thickness;
-in vec2 uvdata;
-in vec3 prev_pos;
-
-out vec4 finalColor;
-out float finalThickness;
-out vec2 finaluvdata;
-out vec4 finalprev_pos;
-
-#define TRUE 1
-
-#define OB_WIRE 2
-#define OB_SOLID 3
-
-#define V3D_SHADING_MATERIAL_COLOR 0
-#define V3D_SHADING_TEXTURE_COLOR 3
-#define V3D_SHADING_VERTEX_COLOR 5
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-void main()
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz);
- finalColor = color;
-
- if (keep_size == TRUE) {
- finalThickness = thickness;
- }
- else {
- float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) :
- (thickness / defaultpixsize);
- finalThickness = max(size * objscale, 0.5); /* set a minimum size */
- }
-
- /* for wireframe override size and color */
- if (shading_type[0] == OB_WIRE) {
- finalThickness = 2.0;
- finalColor = wire_color;
- }
- /* for solid override color */
- if (shading_type[0] == OB_SOLID) {
- if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
- (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
- finalColor = wire_color;
- }
- if (viewport_xray == 1) {
- finalColor.a *= 0.5;
- }
- }
-
- finaluvdata = uvdata;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl
deleted file mode 100644
index 2f4429a858f..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
- float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
- vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
-
- FragColor = stroke_color;
- gl_FragDepth = stroke_depth;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
deleted file mode 100644
index 0f1665b73c2..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
+++ /dev/null
@@ -1,110 +0,0 @@
-uniform int color_type;
-uniform sampler2D myTexture;
-uniform bool myTexturePremultiplied;
-
-uniform float gradient_f;
-
-uniform vec4 colormix;
-uniform float mix_stroke_factor;
-uniform int shading_type[2];
-
-uniform int fade_layer;
-uniform float fade_layer_factor;
-uniform bool fade_ob;
-uniform vec3 fade_color;
-uniform float fade_ob_factor;
-
-in vec4 mColor;
-in vec2 mTexCoord;
-in vec2 uvfac;
-
-out vec4 fragColor;
-
-#define texture2D texture
-
-/* keep this list synchronized with list in gpencil_engine.h */
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-#define ENDCAP 1.0
-
-#define OB_SOLID 3
-#define V3D_SHADING_TEXTURE_COLOR 3
-
-bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR);
-
-void main()
-{
-
- vec4 tColor = vec4(mColor);
- /* if uvfac[1] == 1, then encap */
- if (uvfac[1] == ENDCAP) {
- vec2 center = vec2(uvfac[0], 0.5);
- float dist = length(mTexCoord - center);
- if (dist > 0.50) {
- discard;
- }
- }
-
- if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) {
- fragColor = tColor;
- }
-
- /* texture for endcaps */
- vec4 text_color;
- if (uvfac[1] == ENDCAP) {
- text_color = texture_read_as_srgb(
- myTexture, myTexturePremultiplied, vec2(mTexCoord.x, mTexCoord.y));
- }
- else {
- text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord);
- }
-
- /* texture */
- if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) {
- if (mix_stroke_factor > 0.0) {
- fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor);
- fragColor.a = text_color.a;
- }
- else {
- fragColor = text_color;
- }
-
- /* mult both alpha factor to use strength factor */
- fragColor.a = min(fragColor.a * tColor.a, fragColor.a);
- }
- /* pattern */
- if ((color_type == GPENCIL_COLOR_PATTERN) && (!no_texture)) {
- fragColor = tColor;
- /* mult both alpha factor to use strength factor with color alpha limit */
- fragColor.a = min(text_color.a * tColor.a, tColor.a);
- }
-
- /* gradient */
- /* keep this disabled while the line glitch bug exists
- if (gradient_f < 1.0) {
- float d = abs(mTexCoord.y - 0.5) * (1.1 - gradient_f);
- float alpha = 1.0 - clamp((fragColor.a - (d * 2.0)), 0.03, 1.0);
- fragColor.a = smoothstep(fragColor.a, 0.0, alpha);
-
- }
- */
-
- if (fragColor.a < 0.0035) {
- discard;
- }
-
- /* Apply paper opacity */
- if (fade_layer == 1) {
- /* Layer is below, mix with background. */
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
- }
- else if (fade_layer == 2) {
- /* Layer is above, change opacity. */
- fragColor.a *= fade_layer_factor;
- }
- else if (fade_ob == true) {
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
deleted file mode 100644
index 3300514dd13..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
+++ /dev/null
@@ -1,264 +0,0 @@
-uniform vec2 Viewport;
-uniform int xraymode;
-uniform int color_type;
-uniform int caps_mode[2];
-
-layout(lines_adjacency) in;
-layout(triangle_strip, max_vertices = 13) out;
-
-in vec4 finalColor[4];
-in float finalThickness[4];
-in vec2 finaluvdata[4];
-
-out vec4 mColor;
-out vec2 mTexCoord;
-out vec2 uvfac;
-
-#define GP_XRAY_FRONT 0
-#define GP_XRAY_3DSPACE 1
-
-/* keep this list synchronized with list in gpencil_engine.h */
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-#define GPENCIL_FLATCAP 1
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- return vec2(vertex.xy / vertex.w) * Viewport;
-}
-
-/* get zdepth value */
-float getZdepth(vec4 point)
-{
- if (xraymode == GP_XRAY_FRONT) {
- return min(-0.05, (point.z / point.w));
- }
- if (xraymode == GP_XRAY_3DSPACE) {
- return (point.z / point.w);
- }
-
- /* in front by default */
- return 0.000001;
-}
-
-/* check equality but with a small tolerance */
-bool is_equal(vec4 p1, vec4 p2)
-{
- float limit = 0.0001;
- float x = abs(p1.x - p2.x);
- float y = abs(p1.y - p2.y);
- float z = abs(p1.z - p2.z);
-
- if ((x < limit) && (y < limit) && (z < limit)) {
- return true;
- }
-
- return false;
-}
-
-void main(void)
-{
- float MiterLimit = 0.75;
- uvfac = vec2(0.0, 0.0);
-
- /* receive 4 points */
- vec4 P0 = gl_in[0].gl_Position;
- vec4 P1 = gl_in[1].gl_Position;
- vec4 P2 = gl_in[2].gl_Position;
- vec4 P3 = gl_in[3].gl_Position;
-
- /* get the four vertices passed to the shader */
- vec2 sp0 = toScreenSpace(P0); // start of previous segment
- vec2 sp1 = toScreenSpace(P1); // end of previous segment, start of current segment
- vec2 sp2 = toScreenSpace(P2); // end of current segment, start of next segment
- vec2 sp3 = toScreenSpace(P3); // end of next segment
-
- /* culling outside viewport */
- vec2 area = Viewport * 4.0;
- if (sp1.x < -area.x || sp1.x > area.x) {
- return;
- }
- if (sp1.y < -area.y || sp1.y > area.y) {
- return;
- }
- if (sp2.x < -area.x || sp2.x > area.x) {
- return;
- }
- if (sp2.y < -area.y || sp2.y > area.y) {
- return;
- }
-
- /* culling behind camera */
- if (P1.w < 0 || P2.w < 0) {
- return;
- }
-
- /* determine the direction of each of the 3 segments (previous, current, next) */
- vec2 v0 = normalize(sp1 - sp0);
- vec2 v1 = normalize(sp2 - sp1);
- vec2 v2 = normalize(sp3 - sp2);
-
- /* determine the normal of each of the 3 segments (previous, current, next) */
- vec2 n0 = vec2(-v0.y, v0.x);
- vec2 n1 = vec2(-v1.y, v1.x);
- vec2 n2 = vec2(-v2.y, v2.x);
-
- /* determine miter lines by averaging the normals of the 2 segments */
- vec2 miter_a = normalize(n0 + n1); // miter at start of current segment
- vec2 miter_b = normalize(n1 + n2); // miter at end of current segment
-
- /* determine the length of the miter by projecting it onto normal and then inverse it */
- float an1 = dot(miter_a, n1);
- float bn1 = dot(miter_b, n2);
- if (an1 == 0) {
- an1 = 1;
- }
- if (bn1 == 0) {
- bn1 = 1;
- }
- float length_a = finalThickness[1] / an1;
- float length_b = finalThickness[2] / bn1;
- if (length_a <= 0.0) {
- length_a = 0.01;
- }
- if (length_b <= 0.0) {
- length_b = 0.01;
- }
-
- /* prevent excessively long miters at sharp corners */
- if (dot(v0, v1) < -MiterLimit) {
- miter_a = n1;
- length_a = finalThickness[1];
-
- /* close the gap */
- if (dot(v0, n1) > 0) {
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- EndPrimitive();
- }
- else {
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- EndPrimitive();
- }
- }
-
- if (dot(v1, v2) < -MiterLimit) {
- miter_b = n1;
- length_b = finalThickness[2];
- }
-
- /* generate the start endcap */
- if ((caps_mode[0] != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
- vec4 cap_color = finalColor[1];
-
- mTexCoord = vec2(2.0, 0.5);
- mColor = cap_color;
- vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0;
- uvfac = vec2(0.0, 1.0);
- gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0.0, -0.5);
- mColor = cap_color;
- uvfac = vec2(0.0, 1.0);
- gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0.0, 1.5);
- mColor = cap_color;
- uvfac = vec2(0.0, 1.0);
- gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
- }
-
- float y_a = 0.0;
- float y_b = 1.0;
-
- /* invert uv (vertical) */
- if (finaluvdata[2].x > 1.0) {
- if ((finaluvdata[1].y != 0.0) && (finaluvdata[2].y != 0.0)) {
- float d = ceil(finaluvdata[2].x) - 1.0;
- if (floor(d / 2.0) == (d / 2.0)) {
- y_a = 1.0;
- y_b = 0.0;
- }
- }
- }
- /* generate the triangle strip */
- uvfac = vec2(0.0, 0.0);
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 0) : vec2(finaluvdata[1].x, y_a);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 1) : vec2(finaluvdata[1].x, y_b);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 0) : vec2(finaluvdata[2].x, y_a);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 1) : vec2(finaluvdata[2].x, y_b);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- /* generate the end endcap */
- if ((caps_mode[1] != GPENCIL_FLATCAP) && is_equal(P1, P3) && (finaluvdata[2].x > 0)) {
- vec4 cap_color = finalColor[2];
-
- mTexCoord = vec2(finaluvdata[2].x, 1.5);
- mColor = cap_color;
- uvfac = vec2(finaluvdata[2].x, 1.0);
- gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(finaluvdata[2].x, -0.5);
- mColor = cap_color;
- uvfac = vec2(finaluvdata[2].x, 1.0);
- gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(finaluvdata[2].x + 2, 0.5);
- mColor = cap_color;
- uvfac = vec2(finaluvdata[2].x, 1.0);
- vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0;
- gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
- }
-
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
deleted file mode 100644
index 8df08f0bf68..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
+++ /dev/null
@@ -1,63 +0,0 @@
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform int keep_size;
-uniform float objscale;
-uniform float pixfactor;
-uniform int viewport_xray;
-uniform int shading_type[2];
-uniform vec4 wire_color;
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in float thickness;
-in vec2 uvdata;
-
-out vec4 finalColor;
-out float finalThickness;
-out vec2 finaluvdata;
-
-#define TRUE 1
-
-#define OB_WIRE 2
-#define OB_SOLID 3
-
-#define V3D_SHADING_MATERIAL_COLOR 0
-#define V3D_SHADING_TEXTURE_COLOR 3
-#define V3D_SHADING_VERTEX_COLOR 5
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-void main(void)
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalColor = color;
-
- if (keep_size == TRUE) {
- finalThickness = thickness;
- }
- else {
- float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) :
- (thickness / defaultpixsize);
- finalThickness = max(size * objscale, 1.0);
- }
-
- /* for wireframe override size and color */
- if (shading_type[0] == OB_WIRE) {
- finalThickness = 1.0;
- finalColor = wire_color;
- }
- /* for solid override color */
- if (shading_type[0] == OB_SOLID) {
- if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
- (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
- finalColor = wire_color;
- }
- if (viewport_xray == 1) {
- finalColor.a *= 0.5;
- }
- }
-
- finaluvdata = uvdata;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
new file mode 100644
index 00000000000..c6cfee5ef2d
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -0,0 +1,5 @@
+
+void main()
+{
+ gpencil_vertex();
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
new file mode 100644
index 00000000000..503248558ad
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
@@ -0,0 +1,354 @@
+
+uniform sampler2D colorBuf;
+uniform sampler2D revealBuf;
+
+in vec4 uvcoordsvar;
+
+/* Reminder: This is considered SRC color in blend equations.
+ * Same operation on all buffers. */
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 fragRevealage;
+
+float gaussian_weight(float x)
+{
+ return exp(-x * x / (2.0 * 0.35 * 0.35));
+}
+
+#if defined(COMPOSITE)
+
+uniform bool isFirstPass;
+
+void main()
+{
+ if (isFirstPass) {
+ /* Blend mode is multiply. */
+ fragColor.rgb = fragRevealage.rgb = texture(revealBuf, uvcoordsvar.xy).rgb;
+ fragColor.a = fragRevealage.a = 1.0;
+ }
+ else {
+ /* Blend mode is additive. */
+ fragRevealage = vec4(0.0);
+ fragColor.rgb = texture(colorBuf, uvcoordsvar.xy).rgb;
+ fragColor.a = 0.0;
+ }
+}
+
+#elif defined(COLORIZE)
+
+uniform vec3 lowColor;
+uniform vec3 highColor;
+uniform float factor;
+uniform int mode;
+
+const mat3 sepia_mat = mat3(
+ vec3(0.393, 0.349, 0.272), vec3(0.769, 0.686, 0.534), vec3(0.189, 0.168, 0.131));
+
+# define MODE_GRAYSCALE 0
+# define MODE_SEPIA 1
+# define MODE_DUOTONE 2
+# define MODE_CUSTOM 3
+# define MODE_TRANSPARENT 4
+
+void main()
+{
+ fragColor = texture(colorBuf, uvcoordsvar.xy);
+ fragRevealage = texture(revealBuf, uvcoordsvar.xy);
+
+ float luma = dot(fragColor.rgb, vec3(0.2126, 0.7152, 0.723));
+
+ /* No blending. */
+ switch (mode) {
+ case MODE_GRAYSCALE:
+ fragColor.rgb = mix(fragColor.rgb, vec3(luma), factor);
+ break;
+ case MODE_SEPIA:
+ fragColor.rgb = mix(fragColor.rgb, sepia_mat * fragColor.rgb, factor);
+ break;
+ case MODE_DUOTONE:
+ fragColor.rgb = luma * ((luma <= factor) ? lowColor : highColor);
+ break;
+ case MODE_CUSTOM:
+ fragColor.rgb = mix(fragColor.rgb, luma * lowColor, factor);
+ break;
+ case MODE_TRANSPARENT:
+ default:
+ fragColor.rgb *= factor;
+ fragRevealage.rgb = mix(vec3(1.0), fragRevealage.rgb, factor);
+ break;
+ }
+}
+
+#elif defined(BLUR)
+
+uniform vec2 offset;
+uniform int sampCount;
+
+void main()
+{
+ vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy);
+ vec2 ofs = offset * pixel_size;
+
+ fragColor = vec4(0.0);
+ fragRevealage = vec4(0.0);
+
+ /* No blending. */
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = uvcoordsvar.xy + ofs * x;
+ fragColor.rgb += texture(colorBuf, uv).rgb * weight;
+ fragRevealage.rgb += texture(revealBuf, uv).rgb * weight;
+ }
+
+ fragColor /= weight_accum;
+ fragRevealage /= weight_accum;
+}
+
+#elif defined(TRANSFORM)
+
+uniform vec2 axisFlip = vec2(1.0);
+uniform vec2 waveDir = vec2(0.0);
+uniform vec2 waveOffset = vec2(0.0);
+uniform float wavePhase = 0.0;
+uniform vec2 swirlCenter = vec2(0.0);
+uniform float swirlAngle = 0.0;
+uniform float swirlRadius = 0.0;
+
+void main()
+{
+ vec2 uv = (uvcoordsvar.xy - 0.5) * axisFlip + 0.5;
+
+ /* Wave deform. */
+ float wave_time = dot(uv, waveDir.xy);
+ uv += sin(wave_time + wavePhase) * waveOffset;
+ /* Swirl deform. */
+ if (swirlRadius > 0.0) {
+ vec2 tex_size = vec2(textureSize(colorBuf, 0).xy);
+ vec2 pix_coord = uv * tex_size - swirlCenter;
+ float dist = length(pix_coord);
+ float percent = clamp((swirlRadius - dist) / swirlRadius, 0.0, 1.0);
+ float theta = percent * percent * swirlAngle;
+ float s = sin(theta);
+ float c = cos(theta);
+ mat2 rot = mat2(vec2(c, -s), vec2(s, c));
+ uv = (rot * pix_coord + swirlCenter) / tex_size;
+ }
+
+ fragColor = texture(colorBuf, uv);
+ fragRevealage = texture(revealBuf, uv);
+}
+
+#elif defined(GLOW)
+
+uniform vec4 glowColor;
+uniform vec2 offset;
+uniform int sampCount;
+uniform vec3 threshold;
+uniform bool firstPass;
+uniform bool glowUnder;
+uniform int blendMode;
+
+void main()
+{
+ vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy);
+ vec2 ofs = offset * pixel_size;
+
+ fragColor = vec4(0.0);
+ fragRevealage = vec4(0.0);
+
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = uvcoordsvar.xy + ofs * x;
+ vec3 col = texture(colorBuf, uv).rgb;
+ vec3 rev = texture(revealBuf, uv).rgb;
+ if (threshold.x > -1.0) {
+ if (threshold.y > -1.0) {
+ if (all(lessThan(abs(col - threshold), vec3(0.05)))) {
+ weight = 0.0;
+ }
+ }
+ else {
+ if (dot(col, vec3(1.0 / 3.0)) < threshold.x) {
+ weight = 0.0;
+ }
+ }
+ }
+ fragColor.rgb += col * weight;
+ fragRevealage.rgb += (1.0 - rev) * weight;
+ }
+
+ if (weight_accum > 0.0) {
+ fragColor *= glowColor.rgbb / weight_accum;
+ fragRevealage = fragRevealage / weight_accum;
+ }
+ fragRevealage = 1.0 - fragRevealage;
+
+ if (glowUnder) {
+ if (firstPass) {
+ /* In first pass we copy the revealage buffer in the alpha channel.
+ * This let us do the alpha under in second pass. */
+ vec3 original_revealage = texture(revealBuf, uvcoordsvar.xy).rgb;
+ fragRevealage.a = clamp(dot(original_revealage.rgb, vec3(0.333334)), 0.0, 1.0);
+ }
+ else {
+ /* Recover original revealage. */
+ fragRevealage.a = texture(revealBuf, uvcoordsvar.xy).a;
+ }
+ }
+
+ if (!firstPass) {
+ fragColor.a = clamp(1.0 - dot(fragRevealage.rgb, vec3(0.333334)), 0.0, 1.0);
+ fragRevealage.a *= glowColor.a;
+ blend_mode_output(blendMode, fragColor, fragRevealage.a, fragColor, fragRevealage);
+ }
+}
+
+#elif defined(RIM)
+
+uniform vec2 blurDir;
+uniform vec2 uvOffset;
+uniform vec3 rimColor;
+uniform vec3 maskColor;
+uniform int sampCount;
+uniform int blendMode;
+uniform bool isFirstPass;
+
+void main()
+{
+ /* Blur revealage buffer. */
+ fragRevealage = vec4(0.0);
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = uvcoordsvar.xy + blurDir * x + uvOffset;
+ vec3 col = texture(revealBuf, uv).rgb;
+ if (any(not(equal(vec2(0.0), floor(uv))))) {
+ col = vec3(0.0);
+ }
+ fragRevealage.rgb += col * weight;
+ }
+ fragRevealage /= weight_accum;
+
+ if (isFirstPass) {
+ /* In first pass we copy the reveal buffer. This let us do alpha masking in second pass. */
+ fragColor = texture(revealBuf, uvcoordsvar.xy);
+ /* Also add the masked color to the reveal buffer. */
+ vec3 col = texture(colorBuf, uvcoordsvar.xy).rgb;
+ if (all(lessThan(abs(col - maskColor), vec3(0.05)))) {
+ fragColor = vec4(1.0);
+ }
+ }
+ else {
+ /* Premult by foreground alpha (alpha mask). */
+ float mask = 1.0 - clamp(dot(vec3(0.333334), texture(colorBuf, uvcoordsvar.xy).rgb), 0.0, 1.0);
+
+ /* fragRevealage is blurred shadow. */
+ float rim = clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0);
+
+ vec4 color = vec4(rimColor, 1.0);
+
+ blend_mode_output(blendMode, color, rim * mask, fragColor, fragRevealage);
+ }
+}
+
+#elif defined(SHADOW)
+
+uniform vec4 shadowColor;
+uniform vec2 uvRotX;
+uniform vec2 uvRotY;
+uniform vec2 uvOffset;
+uniform vec2 blurDir;
+uniform vec2 waveDir;
+uniform vec2 waveOffset;
+uniform float wavePhase;
+uniform int sampCount;
+uniform bool isFirstPass;
+
+vec2 compute_uvs(float x)
+{
+ vec2 uv = uvcoordsvar.xy;
+ /* Tranform UV (loc, rot, scale) */
+ uv = uv.x * uvRotX + uv.y * uvRotY + uvOffset;
+ uv += blurDir * x;
+ /* Wave deform. */
+ float wave_time = dot(uv, waveDir.xy);
+ uv += sin(wave_time + wavePhase) * waveOffset;
+ return uv;
+}
+
+void main()
+{
+ /* Blur revealage buffer. */
+ fragRevealage = vec4(0.0);
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = compute_uvs(x);
+ vec3 col = texture(revealBuf, uv).rgb;
+ if (any(not(equal(vec2(0.0), floor(uv))))) {
+ col = vec3(1.0);
+ }
+ fragRevealage.rgb += col * weight;
+ }
+ fragRevealage /= weight_accum;
+
+ /* No blending in first pass, alpha over premult in second pass. */
+ if (isFirstPass) {
+ /* In first pass we copy the reveal buffer. This let us do alpha under in second pass. */
+ fragColor = texture(revealBuf, uvcoordsvar.xy);
+ }
+ else {
+ /* fragRevealage is blurred shadow. */
+ float shadow_fac = 1.0 - clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0);
+ /* Premult by foreground revealage (alpha under). */
+ vec3 original_revealage = texture(colorBuf, uvcoordsvar.xy).rgb;
+ shadow_fac *= clamp(dot(vec3(0.333334), original_revealage), 0.0, 1.0);
+ /* Modulate by opacity */
+ shadow_fac *= shadowColor.a;
+ /* Apply shadow color. */
+ fragColor.rgb = mix(vec3(0.0), shadowColor.rgb, shadow_fac);
+ /* Alpha over (mask behind the shadow). */
+ fragColor.a = shadow_fac;
+
+ fragRevealage.rgb = original_revealage * (1.0 - shadow_fac);
+ /* Replace the whole revealage buffer. */
+ fragRevealage.a = 1.0;
+ }
+}
+
+#elif defined(PIXELIZE)
+
+uniform vec2 targetPixelSize;
+uniform vec2 targetPixelOffset;
+uniform vec2 accumOffset;
+uniform int sampCount;
+
+void main()
+{
+ vec2 pixel = floor((uvcoordsvar.xy - targetPixelOffset) / targetPixelSize);
+ vec2 uv = (pixel + 0.5) * targetPixelSize + targetPixelOffset;
+
+ fragColor = vec4(0.0);
+ fragRevealage = vec4(0.0);
+
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount + 1);
+ vec2 uv_ofs = uv + accumOffset * 0.5 * x;
+ fragColor += texture(colorBuf, uv_ofs);
+ fragRevealage += texture(revealBuf, uv_ofs);
+ }
+
+ fragColor /= float(sampCount) * 2.0 + 1.0;
+ fragRevealage /= float(sampCount) * 2.0 + 1.0;
+}
+
+#endif
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl
deleted file mode 100644
index 926b11e4083..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl
+++ /dev/null
@@ -1,76 +0,0 @@
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform int tonemapping;
-uniform vec4 select_color;
-uniform int do_select;
-
-float srgb_to_linearrgb(float c)
-{
- if (c < 0.04045) {
- return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
- }
- else {
- return pow((c + 0.055) * (1.0 / 1.055), 2.4);
- }
-}
-
-float linearrgb_to_srgb(float c)
-{
- if (c < 0.0031308) {
- return (c < 0.0) ? 0.0 : c * 12.92;
- }
- else {
- return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
- }
-}
-
-bool check_borders(ivec2 uv, int size)
-{
- for (int x = -size; x <= size; x++) {
- for (int y = -size; y <= size; y++) {
- vec4 stroke_color = texelFetch(strokeColor, ivec2(uv.x + x, uv.y + y), 0).rgba;
- if (stroke_color.a > 0) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
- float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
- vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
-
- /* premult alpha factor to remove double blend effects */
- if (stroke_color.a > 0) {
- stroke_color = vec4(vec3(stroke_color.rgb / stroke_color.a), stroke_color.a);
- }
-
- /* apply color correction for render only */
- if (tonemapping == 1) {
- stroke_color.r = srgb_to_linearrgb(stroke_color.r);
- stroke_color.g = srgb_to_linearrgb(stroke_color.g);
- stroke_color.b = srgb_to_linearrgb(stroke_color.b);
- }
-
- FragColor = clamp(stroke_color, 0.0, 1.0);
- gl_FragDepth = clamp(stroke_depth, 0.0, 1.0);
-
- if (do_select == 1) {
- if (stroke_color.a == 0) {
- if (check_borders(uv, 2)) {
- FragColor = select_color;
- gl_FragDepth = 0.000001;
- /* Dirty fix waiting for new GPencil engine. */
- FragColor.rgb = pow(FragColor.rgb, vec3(2.2));
- }
- }
- }
-}
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index a8d2c4c6cf0..cfa0fa9eb1a 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -25,6 +25,8 @@
#include "DRW_engine.h"
#include "DRW_render.h"
+#include "DEG_depsgraph_query.h"
+
#include "ED_view3d.h"
#include "BKE_object.h"
@@ -79,6 +81,7 @@ static void OVERLAY_engine_init(void *vedata)
pd->xray_enabled = XRAY_ACTIVE(v3d);
pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE;
pd->clear_in_front = (v3d->shading.type != OB_SOLID);
+ pd->cfra = DEG_get_ctime(draw_ctx->depsgraph);
OVERLAY_antialiasing_init(vedata);
@@ -133,11 +136,14 @@ static void OVERLAY_cache_init(void *vedata)
case CTX_MODE_SCULPT:
OVERLAY_sculpt_cache_init(vedata);
break;
- case CTX_MODE_OBJECT:
- case CTX_MODE_PAINT_GPENCIL:
case CTX_MODE_EDIT_GPENCIL:
+ case CTX_MODE_PAINT_GPENCIL:
case CTX_MODE_SCULPT_GPENCIL:
+ case CTX_MODE_VERTEX_GPENCIL:
case CTX_MODE_WEIGHT_GPENCIL:
+ OVERLAY_edit_gpencil_cache_init(vedata);
+ break;
+ case CTX_MODE_OBJECT:
break;
default:
BLI_assert(!"Draw mode invalid");
@@ -148,6 +154,7 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_background_cache_init(vedata);
OVERLAY_extra_cache_init(vedata);
OVERLAY_facing_cache_init(vedata);
+ OVERLAY_gpencil_cache_init(vedata);
OVERLAY_grid_cache_init(vedata);
OVERLAY_image_cache_init(vedata);
OVERLAY_metaball_cache_init(vedata);
@@ -216,8 +223,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
const bool in_paint_mode = (ob == draw_ctx->obact) &&
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL);
- const bool has_surface = ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT);
- const bool draw_surface = !((ob->dt < OB_WIRE) || (!renderable && (ob->dt != OB_WIRE)));
+ const bool has_surface = ELEM(
+ ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT, OB_GPENCIL);
+ const bool draw_surface = (ob->dt >= OB_WIRE) && (renderable || (ob->dt == OB_WIRE));
const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION);
const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
const bool draw_wires = draw_surface && has_surface &&
@@ -429,6 +437,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_armature_draw(vedata);
OVERLAY_particle_draw(vedata);
OVERLAY_metaball_draw(vedata);
+ OVERLAY_gpencil_draw(vedata);
OVERLAY_extra_draw(vedata);
if (DRW_state_is_fbo()) {
@@ -491,6 +500,13 @@ static void OVERLAY_draw_scene(void *vedata)
case CTX_MODE_SCULPT:
OVERLAY_sculpt_draw(vedata);
break;
+ case CTX_MODE_EDIT_GPENCIL:
+ case CTX_MODE_PAINT_GPENCIL:
+ case CTX_MODE_SCULPT_GPENCIL:
+ case CTX_MODE_VERTEX_GPENCIL:
+ case CTX_MODE_WEIGHT_GPENCIL:
+ OVERLAY_edit_gpencil_draw(vedata);
+ break;
default:
break;
}
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index b40e95d538c..49f266291da 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -38,7 +38,7 @@
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_gpencil_types.h"
+#include "DNA_curve_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
@@ -1331,89 +1331,6 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name GPencil.
- * \{ */
-
-static void OVERLAY_gpencil_color_names(Object *ob)
-{
- if (ob->mode != OB_MODE_EDIT_GPENCIL) {
- return;
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
- if (gpd == NULL) {
- return;
- }
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- uchar color[4];
- /* Color Management: Exception here as texts are drawn in sRGB space directly. */
- UI_GetThemeColor3ubv(theme_id, color);
- color[3] = 255;
- struct DRWTextStore *dt = DRW_text_cache_ensure();
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
- if (ma == NULL) {
- continue;
- }
-
- MaterialGPencilStyle *gp_style = ma->gp_style;
- /* skip stroke if it doesn't have any valid data */
- if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
- continue;
- }
- /* check if the color is visible */
- if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
- continue;
- }
-
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- float fpt[3];
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if (pt->flag & GP_SPOINT_SELECT) {
- mul_v3_m4v3(fpt, ob->obmat, &pt->x);
- DRW_text_cache_add(dt,
- fpt,
- ma->id.name + 2,
- strlen(ma->id.name + 2),
- 10,
- 0,
- DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
- color);
- break;
- }
- }
- }
- }
- }
-}
-
-void OVERLAY_gpencil_cache_populate(OVERLAY_Data *UNUSED(vedata), Object *ob)
-{
- /* don't show object extras in set's */
- if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
- if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
- OVERLAY_gpencil_color_names(ob);
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Volumetric / Smoke sim
* \{ */
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
new file mode 100644
index 00000000000..c96c448c63b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -0,0 +1,391 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_gpencil.h"
+
+#include "UI_resources.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "overlay_private.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ /* Default: Display nothing. */
+ pd->edit_gpencil_points_grp = NULL;
+ pd->edit_gpencil_wires_grp = NULL;
+ psl->edit_gpencil_ps = NULL;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+
+ if (gpd == NULL || ob->type != OB_GPENCIL) {
+ return;
+ }
+
+ /* For sculpt show only if mask mode, and only points if not stroke mode. */
+ const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) &&
+ GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt));
+ const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) &&
+ (ts->gpencil_selectmode_sculpt &
+ (GP_SCULPT_MASK_SELECTMODE_POINT |
+ GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
+
+ /* For vertex paint show only if mask mode, and only points if not stroke mode. */
+ bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) &&
+ GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex));
+ const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) &&
+ (ts->gpencil_selectmode_vertex &
+ (GP_VERTEX_MASK_SELECTMODE_POINT |
+ GP_VERTEX_MASK_SELECTMODE_SEGMENT)));
+
+ /* If Sculpt or Vertex mode and the mask is disabled, the select must be hidden. */
+ const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) ||
+ (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask));
+
+ const bool do_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool show_multi_edit_lines = (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
+
+ const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) || show_multi_edit_lines;
+
+ const bool hide_lines = !GPENCIL_EDIT_MODE(gpd) && !GPENCIL_WEIGHT_MODE(gpd) &&
+ !use_sculpt_mask && !use_vertex_mask && !show_lines;
+
+ /* Special case when vertex paint and multiedit lines. */
+ if (do_multiedit && show_multi_edit_lines && GPENCIL_VERTEX_MODE(gpd)) {
+ use_vertex_mask = true;
+ }
+
+ const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ /* Show Edit points if:
+ * Edit mode: Not in Stroke selection mode
+ * Sculpt mode: If use Mask and not Stroke mode
+ * Weight mode: Always
+ * Vertex mode: If use Mask and not Stroke mode
+ */
+ const bool show_points = show_sculpt_points || is_weight_paint || show_vertex_points ||
+ (GPENCIL_EDIT_MODE(gpd) &&
+ (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
+
+ if ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state);
+
+ if (show_lines && !hide_lines) {
+ sh = OVERLAY_shader_edit_gpencil_wire();
+ pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines);
+ DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint);
+ DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select);
+ DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+ }
+
+ if (show_points && !hide_select) {
+ sh = OVERLAY_shader_edit_gpencil_point();
+ pd->edit_gpencil_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", do_multiedit);
+ DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint);
+ DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+ }
+ }
+
+ /* control points for primitives and speed guide */
+ const bool is_cppoint = (gpd->runtime.tot_cp_points > 0);
+ const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide &&
+ (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL));
+ const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) &&
+ ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0));
+
+ if ((is_cppoint || is_speed_guide) && (is_show_gizmo)) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->edit_gpencil_gizmos_ps, state);
+
+ sh = OVERLAY_shader_edit_gpencil_guide_point();
+ grp = DRW_shgroup_create(sh, psl->edit_gpencil_gizmos_ps);
+
+ if (gpd->runtime.cp_points != NULL) {
+ for (int i = 0; i < gpd->runtime.tot_cp_points; i++) {
+ bGPDcontrolpoint *cp = &gpd->runtime.cp_points[i];
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", &cp->x);
+ DRW_shgroup_uniform_float_copy(grp, "pSize", cp->size * 0.8f * G_draw.block.sizePixel);
+ DRW_shgroup_uniform_vec4_copy(grp, "pColor", cp->color);
+ DRW_shgroup_call_procedural_points(grp, NULL, 1);
+ }
+ }
+
+ if (ts->gp_sculpt.guide.use_guide) {
+ float color[4];
+ if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) {
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.location);
+ }
+ else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT &&
+ ts->gp_sculpt.guide.reference_object != NULL) {
+ UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.reference_object->loc);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", scene->cursor.location);
+ }
+ DRW_shgroup_uniform_vec4_copy(grp, "pColor", color);
+ DRW_shgroup_uniform_float_copy(grp, "pSize", 8.0f * G_draw.block.sizePixel);
+ DRW_shgroup_call_procedural_points(grp, NULL, 1);
+ }
+ }
+}
+
+void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ /* Default: Display nothing. */
+ psl->gpencil_canvas_ps = NULL;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+ const View3DCursor *cursor = &scene->cursor;
+
+ if (gpd == NULL || ob->type != OB_GPENCIL) {
+ return;
+ }
+
+ const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
+ const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0;
+
+ if (show_grid && show_overlays) {
+ const char *grid_unit = NULL;
+ float mat[4][4];
+ float col_grid[4];
+ float size[2];
+
+ /* set color */
+ copy_v3_v3(col_grid, gpd->grid.color);
+ col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f);
+
+ copy_m4_m4(mat, ob->obmat);
+
+ float viewinv[4][4];
+ /* Set the grid in the selected axis */
+ switch (ts->gp_sculpt.lock_axis) {
+ case GP_LOCKAXIS_X:
+ swap_v4_v4(mat[0], mat[2]);
+ break;
+ case GP_LOCKAXIS_Y:
+ swap_v4_v4(mat[1], mat[2]);
+ break;
+ case GP_LOCKAXIS_Z:
+ /* Default. */
+ break;
+ case GP_LOCKAXIS_CURSOR:
+ loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, (float[3]){1, 1, 1});
+ break;
+ case GP_LOCKAXIS_VIEW:
+ /* view aligned */
+ DRW_view_viewmat_get(NULL, viewinv, true);
+ copy_v3_v3(mat[0], viewinv[0]);
+ copy_v3_v3(mat[1], viewinv[1]);
+ break;
+ }
+
+ translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f);
+ mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit));
+ rescale_m4(mat, (float[3]){size[0], size[1], 0.0f});
+
+ const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
+ int line_ct = gridlines * 4 + 2;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->gpencil_canvas_ps, state);
+
+ sh = OVERLAY_shader_gpencil_canvas();
+ grp = DRW_shgroup_create(sh, psl->gpencil_canvas_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", col_grid);
+ DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]);
+ DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2);
+ DRW_shgroup_call_procedural_lines(grp, NULL, line_ct);
+ }
+}
+
+static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ if (pd->edit_gpencil_wires_grp) {
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp);
+ DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color);
+
+ struct GPUBatch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra);
+ DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob);
+ }
+
+ if (pd->edit_gpencil_points_grp) {
+ const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0;
+
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp);
+ DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction);
+
+ struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra);
+ DRW_shgroup_call_no_cull(grp, geom, ob);
+ }
+}
+
+static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl),
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ void *thunk)
+{
+ Object *ob = (Object *)thunk;
+ Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
+ if (ma == NULL) {
+ return;
+ }
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
+ return;
+ }
+ /* check if the color is visible */
+ if (gp_style->flag & GP_MATERIAL_HIDE) {
+ return;
+ }
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ /* Draw name at the first selected point. */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ uchar color[4];
+ UI_GetThemeColor4ubv(theme_id, color);
+
+ float fpt[3];
+ mul_v3_m4v3(fpt, ob->obmat, &pt->x);
+
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ DRW_text_cache_add(dt,
+ fpt,
+ ma->id.name + 2,
+ strlen(ma->id.name + 2),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+ break;
+ }
+ }
+ }
+}
+
+static void OVERLAY_gpencil_color_names(Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ int cfra = DEG_get_ctime(draw_ctx->depsgraph);
+
+ BKE_gpencil_visible_stroke_iter(
+ ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra);
+}
+
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd == NULL) {
+ return;
+ }
+
+ if (GPENCIL_ANY_MODE(gpd)) {
+ OVERLAY_edit_gpencil_cache_populate(vedata, ob);
+ }
+
+ /* don't show object extras in set's */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+ if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL) &&
+ DRW_state_show_text()) {
+ OVERLAY_gpencil_color_names(ob);
+ }
+ }
+}
+
+void OVERLAY_gpencil_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->gpencil_canvas_ps) {
+ DRW_draw_pass(psl->gpencil_canvas_ps);
+ }
+}
+
+void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->edit_gpencil_gizmos_ps) {
+ DRW_draw_pass(psl->edit_gpencil_gizmos_ps);
+ }
+
+ if (psl->edit_gpencil_ps) {
+ DRW_draw_pass(psl->edit_gpencil_ps);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c
index 555e0084c49..29eb4fd12a4 100644
--- a/source/blender/draw/engines/overlay/overlay_motion_path.c
+++ b/source/blender/draw/engines/overlay/overlay_motion_path.c
@@ -155,7 +155,7 @@ static void motion_path_cache(OVERLAY_Data *vedata,
DRW_shgroup_uniform_bool_copy(grp, "selected", selected);
DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
/* Only draw the required range. */
- DRW_shgroup_call_range(grp, mpath_batch_line_get(mpath), start_index, len);
+ DRW_shgroup_call_range(grp, NULL, mpath_batch_line_get(mpath), start_index, len);
}
/* Draw points. */
@@ -167,7 +167,7 @@ static void motion_path_cache(OVERLAY_Data *vedata,
DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes);
DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
/* Only draw the required range. */
- DRW_shgroup_call_range(grp, mpath_batch_points_get(mpath), start_index, len);
+ DRW_shgroup_call_range(grp, NULL, mpath_batch_points_get(mpath), start_index, len);
}
/* Draw frame numbers at each frame-step value. */
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index 63738b3c214..e77a0a143a9 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -23,13 +23,67 @@
#include "DRW_render.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
-#include "DNA_lightprobe_types.h"
+#include "BKE_object.h"
+
+#include "DNA_gpencil_types.h"
#include "UI_resources.h"
#include "overlay_private.h"
+/* Returns the normal plane in ndc space. */
+static void gpencil_depth_plane(Object *ob, float r_plane[4])
+{
+ /* TODO put that into private data. */
+ float viewinv[4][4];
+ DRW_view_viewmat_get(NULL, viewinv, true);
+ float *camera_z_axis = viewinv[2];
+ float *camera_pos = viewinv[3];
+
+ /* Find the normal most likely to represent the gpObject. */
+ /* TODO: This does not work quite well if you use
+ * strokes not aligned with the object axes. Maybe we could try to
+ * compute the minimum axis of all strokes. But this would be more
+ * computationaly heavy and should go into the GPData evaluation. */
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ /* Convert bbox to matrix */
+ float mat[4][4], size[3], center[3];
+ BKE_boundbox_calc_size_aabb(bbox, size);
+ BKE_boundbox_calc_center_aabb(bbox, center);
+ unit_m4(mat);
+ copy_v3_v3(mat[3], center);
+ /* Avoid division by 0.0 later. */
+ add_v3_fl(size, 1e-8f);
+ rescale_m4(mat, size);
+ /* BBox space to World. */
+ mul_m4_m4m4(mat, ob->obmat, mat);
+ /* BBox center in world space. */
+ copy_v3_v3(center, mat[3]);
+ /* View Vector. */
+ if (DRW_view_is_persp_get(NULL)) {
+ /* BBox center to camera vector. */
+ sub_v3_v3v3(r_plane, camera_pos, mat[3]);
+ }
+ else {
+ copy_v3_v3(r_plane, camera_z_axis);
+ }
+ /* World to BBox space. */
+ invert_m4(mat);
+ /* Normalize the vector in BBox space. */
+ mul_mat3_m4_v3(mat, r_plane);
+ normalize_v3(r_plane);
+
+ transpose_m4(mat);
+ /* mat is now a "normal" matrix which will transform
+ * BBox space normal to world space. */
+ mul_mat3_m4_v3(mat, r_plane);
+ normalize_v3(r_plane);
+
+ plane_from_point_normal_v3(r_plane, center, r_plane);
+}
+
void OVERLAY_outline_init(OVERLAY_Data *vedata)
{
OVERLAY_FramebufferList *fbl = vedata->fbl;
@@ -79,6 +133,11 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
+
+ GPUShader *sh_gpencil = OVERLAY_shader_outline_prepass_gpencil();
+
+ pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps);
+ DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
}
/* outlines_prepass_ps is still needed for selection of probes. */
@@ -107,6 +166,98 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
}
}
+typedef struct iterData {
+ Object *ob;
+ DRWShadingGroup *stroke_grp;
+ DRWShadingGroup *fill_grp;
+ int cfra;
+ float plane[4];
+} iterData;
+
+static void gp_layer_cache_populate(bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *UNUSED(gps),
+ void *thunk)
+{
+ iterData *iter = (iterData *)thunk;
+ bGPdata *gpd = (bGPdata *)iter->ob->data;
+
+ const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
+ const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
+
+ float object_scale = mat4_to_scale(iter->ob->obmat);
+ /* Negate thickness sign to tag that strokes are in screen space.
+ * Convert to world units (by default, 1 meter = 2000 px). */
+ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f);
+
+ DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp);
+ DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", is_stroke_order_3d);
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get());
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get());
+ DRW_shgroup_uniform_float_copy(grp, "thicknessScale", object_scale);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
+ DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane);
+}
+
+static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ void *thunk)
+{
+ iterData *iter = (iterData *)thunk;
+
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
+
+ bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
+ bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
+ // TODO: What about simplify Fill?
+ bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
+
+ if (hide_material) {
+ return;
+ }
+
+ if (show_fill) {
+ struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra);
+ int vfirst = gps->runtime.fill_start * 3;
+ int vcount = gps->tot_triangles * 3;
+ DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount);
+ }
+
+ if (show_stroke) {
+ struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra);
+ /* Start one vert before to have gl_InstanceID > 0 (see shader). */
+ int vfirst = gps->runtime.stroke_start - 1;
+ /* Include "potential" cyclic vertex and start adj vertex (see shader). */
+ int vcount = gps->totpoints + 1 + 1;
+ DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
+ }
+}
+
+static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
+{
+ /* No outlines in edit mode. */
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd && GPENCIL_ANY_MODE(gpd)) {
+ return;
+ }
+
+ iterData iter = {
+ .ob = ob,
+ .stroke_grp = pd->outlines_gpencil_grp,
+ .fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp),
+ .cfra = pd->cfra,
+ };
+
+ if (gpd->draw_mode == GP_DRAWMODE_2D) {
+ gpencil_depth_plane(ob, iter.plane);
+ }
+
+ BKE_gpencil_visible_stroke_iter(
+ ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra);
+}
+
void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
Object *ob,
OVERLAY_DupliData *dupli,
@@ -123,6 +274,11 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
return;
}
+ if (ob->type == OB_GPENCIL) {
+ OVERLAY_outline_gpencil(pd, ob);
+ return;
+ }
+
if (dupli && !init_dupli) {
geom = dupli->outline_geom;
shgroup = dupli->outline_shgrp;
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index 185df723301..167a8e940df 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -60,6 +60,8 @@ typedef struct OVERLAY_PassList {
DRWPass *clipping_frustum_ps;
DRWPass *edit_curve_wire_ps[2];
DRWPass *edit_curve_handle_ps;
+ DRWPass *edit_gpencil_ps;
+ DRWPass *edit_gpencil_gizmos_ps;
DRWPass *edit_lattice_ps;
DRWPass *edit_mesh_depth_ps[2];
DRWPass *edit_mesh_verts_ps[2];
@@ -76,6 +78,7 @@ typedef struct OVERLAY_PassList {
DRWPass *extra_blend_ps;
DRWPass *extra_centers_ps;
DRWPass *extra_grid_ps;
+ DRWPass *gpencil_canvas_ps;
DRWPass *facing_ps;
DRWPass *grid_ps;
DRWPass *image_background_ps;
@@ -219,6 +222,8 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *edit_curve_points_grp;
DRWShadingGroup *edit_lattice_points_grp;
DRWShadingGroup *edit_lattice_wires_grp;
+ DRWShadingGroup *edit_gpencil_points_grp;
+ DRWShadingGroup *edit_gpencil_wires_grp;
DRWShadingGroup *edit_mesh_depth_grp[2];
DRWShadingGroup *edit_mesh_faces_grp[2];
DRWShadingGroup *edit_mesh_faces_cage_grp[2];
@@ -238,6 +243,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *motion_path_lines_grp;
DRWShadingGroup *motion_path_points_grp;
DRWShadingGroup *outlines_grp;
+ DRWShadingGroup *outlines_gpencil_grp;
DRWShadingGroup *paint_surf_grp;
DRWShadingGroup *paint_wire_grp;
DRWShadingGroup *paint_wire_selected_grp;
@@ -277,6 +283,7 @@ typedef struct OVERLAY_PrivateData {
float xray_opacity;
short v3d_flag; /* TODO move to View3DOverlay */
short v3d_gridflag; /* TODO move to View3DOverlay */
+ int cfra;
DRWState clipping_state;
OVERLAY_ShadingData shdata;
@@ -419,6 +426,12 @@ void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata);
+void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_gpencil_draw(OVERLAY_Data *vedata);
+void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata);
+
void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata);
void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
@@ -446,7 +459,6 @@ void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata);
void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
-void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob);
@@ -547,6 +559,9 @@ GPUShader *OVERLAY_shader_depth_only(void);
GPUShader *OVERLAY_shader_edit_curve_handle(void);
GPUShader *OVERLAY_shader_edit_curve_point(void);
GPUShader *OVERLAY_shader_edit_curve_wire(void);
+GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void);
+GPUShader *OVERLAY_shader_edit_gpencil_point(void);
+GPUShader *OVERLAY_shader_edit_gpencil_wire(void);
GPUShader *OVERLAY_shader_edit_lattice_point(void);
GPUShader *OVERLAY_shader_edit_lattice_wire(void);
GPUShader *OVERLAY_shader_edit_mesh_analysis(void);
@@ -564,12 +579,14 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object);
GPUShader *OVERLAY_shader_extra_loose_point(void);
GPUShader *OVERLAY_shader_extra_point(void);
GPUShader *OVERLAY_shader_facing(void);
+GPUShader *OVERLAY_shader_gpencil_canvas(void);
GPUShader *OVERLAY_shader_grid(void);
GPUShader *OVERLAY_shader_image(void);
GPUShader *OVERLAY_shader_motion_path_line(void);
GPUShader *OVERLAY_shader_motion_path_vert(void);
GPUShader *OVERLAY_shader_uniform_color(void);
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
+GPUShader *OVERLAY_shader_outline_prepass_gpencil(void);
GPUShader *OVERLAY_shader_extra_grid(void);
GPUShader *OVERLAY_shader_outline_detect(void);
GPUShader *OVERLAY_shader_paint_face(void);
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index d33ef239198..86d5f58957e 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -54,6 +54,9 @@ extern char datatoc_edit_curve_handle_geom_glsl[];
extern char datatoc_edit_curve_handle_vert_glsl[];
extern char datatoc_edit_curve_point_vert_glsl[];
extern char datatoc_edit_curve_wire_vert_glsl[];
+extern char datatoc_edit_gpencil_canvas_vert_glsl[];
+extern char datatoc_edit_gpencil_guide_vert_glsl[];
+extern char datatoc_edit_gpencil_vert_glsl[];
extern char datatoc_edit_lattice_point_vert_glsl[];
extern char datatoc_edit_lattice_wire_vert_glsl[];
extern char datatoc_edit_mesh_common_lib_glsl[];
@@ -113,6 +116,8 @@ extern char datatoc_gpu_shader_flat_color_frag_glsl[];
extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[];
extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+extern char datatoc_gpencil_common_lib_glsl[];
+
extern char datatoc_common_colormanagement_lib_glsl[];
extern char datatoc_common_fullscreen_vert_glsl[];
extern char datatoc_common_fxaa_lib_glsl[];
@@ -138,6 +143,9 @@ typedef struct OVERLAY_Shaders {
GPUShader *edit_curve_handle;
GPUShader *edit_curve_point;
GPUShader *edit_curve_wire;
+ GPUShader *edit_gpencil_guide_point;
+ GPUShader *edit_gpencil_point;
+ GPUShader *edit_gpencil_wire;
GPUShader *edit_lattice_point;
GPUShader *edit_lattice_wire;
GPUShader *edit_mesh_vert;
@@ -159,11 +167,13 @@ typedef struct OVERLAY_Shaders {
GPUShader *extra_lightprobe_grid;
GPUShader *extra_loose_point;
GPUShader *facing;
+ GPUShader *gpencil_canvas;
GPUShader *grid;
GPUShader *image;
GPUShader *motion_path_line;
GPUShader *motion_path_vert;
GPUShader *outline_prepass;
+ GPUShader *outline_prepass_gpencil;
GPUShader *outline_prepass_wire;
GPUShader *outline_detect;
GPUShader *paint_face;
@@ -557,6 +567,58 @@ GPUShader *OVERLAY_shader_edit_curve_wire(void)
return sh_data->edit_curve_wire;
}
+GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->edit_gpencil_guide_point) {
+ sh_data->edit_gpencil_guide_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_guide_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ });
+ }
+ return sh_data->edit_gpencil_guide_point;
+}
+
+GPUShader *OVERLAY_shader_edit_gpencil_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_gpencil_point) {
+ sh_data->edit_gpencil_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define USE_POINTS\n", NULL},
+ });
+ }
+ return sh_data->edit_gpencil_point;
+}
+
+GPUShader *OVERLAY_shader_edit_gpencil_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_gpencil_wire) {
+ sh_data->edit_gpencil_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_gpencil_wire;
+}
+
GPUShader *OVERLAY_shader_edit_lattice_point(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -883,6 +945,21 @@ GPUShader *OVERLAY_shader_facing(void)
return sh_data->facing;
}
+GPUShader *OVERLAY_shader_gpencil_canvas(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->gpencil_canvas) {
+ sh_data->gpencil_canvas = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_canvas_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL},
+ });
+ }
+ return sh_data->gpencil_canvas;
+}
+
GPUShader *OVERLAY_shader_grid(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
@@ -998,6 +1075,32 @@ GPUShader *OVERLAY_shader_outline_prepass(bool use_wire)
return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass;
}
+GPUShader *OVERLAY_shader_outline_prepass_gpencil(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->outline_prepass_gpencil) {
+ sh_data->outline_prepass_gpencil = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_outline_prepass_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_outline_prepass_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def,
+ "#define USE_GPENCIL\n",
+ "#define UNIFORM_RESOURCE_ID\n",
+ NULL},
+ });
+ }
+ return sh_data->outline_prepass_gpencil;
+}
+
GPUShader *OVERLAY_shader_outline_detect(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index 5dbdc71dae1..4df9faace18 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -201,7 +201,11 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
shgrp = pd->wires_grp[is_xray][use_coloring];
}
- if (use_sculpt_pbvh) {
+ if (ob->type == OB_GPENCIL) {
+ /* TODO (fclem) Make GPencil objects have correct boundbox. */
+ DRW_shgroup_call_no_cull(shgrp, geom, ob);
+ }
+ else if (use_sculpt_pbvh) {
DRW_shgroup_call_sculpt(shgrp, ob, true, false, false);
}
else {
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
new file mode 100644
index 00000000000..5aa7fe78e4e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
@@ -0,0 +1,35 @@
+
+uniform vec4 color;
+uniform vec3 xAxis;
+uniform vec3 yAxis;
+uniform vec3 origin;
+uniform int halfLineCount;
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec2 pos;
+ pos.x = float(gl_VertexID % 2);
+ pos.y = float(gl_VertexID / 2) / float(halfLineCount - 1);
+
+ if (pos.y > 1.0) {
+ pos.xy = pos.yx;
+ pos.x -= 1.0 + 1.0 / float(halfLineCount - 1);
+ }
+
+ pos -= 0.5;
+
+ vec3 world_pos = xAxis * pos.x + yAxis * pos.y + origin;
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor = color;
+
+ /* Convert to screen position [0..sizeVp]. */
+ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl
new file mode 100644
index 00000000000..ef68b0f4e6f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl
@@ -0,0 +1,14 @@
+uniform vec4 pColor;
+uniform float pSize;
+uniform vec3 pPosition;
+
+out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ gl_Position = point_world_to_ndc(pPosition);
+ finalColor = pColor;
+ gl_PointSize = pSize;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
new file mode 100644
index 00000000000..cb03ad44615
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
@@ -0,0 +1,103 @@
+
+uniform float normalSize;
+uniform bool doMultiframe;
+uniform bool doStrokeEndpoints;
+uniform bool hideSelect;
+uniform bool doWeightColor;
+uniform float gpEditOpacity;
+uniform vec4 gpEditColor;
+uniform sampler1D weightTex;
+
+in vec3 pos;
+in float ma;
+in uint vflag;
+in float weight;
+
+out vec4 finalColor;
+
+void discard_vert()
+{
+ /* We set the vertex at the camera origin to generate 0 fragments. */
+ gl_Position = vec4(0.0, 0.0, -3e36, 0.0);
+}
+
+#define GP_EDIT_POINT_SELECTED (1u << 0u)
+#define GP_EDIT_STROKE_SELECTED (1u << 1u)
+#define GP_EDIT_MULTIFRAME (1u << 2u)
+#define GP_EDIT_STROKE_START (1u << 3u)
+#define GP_EDIT_STROKE_END (1u << 4u)
+
+#ifdef USE_POINTS
+# define colorUnselect colorGpencilVertex
+# define colorSelect colorGpencilVertexSelect
+#else
+# define colorUnselect gpEditColor
+# define colorSelect (hideSelect ? colorUnselect : colorGpencilVertexSelect)
+#endif
+
+vec3 weight_to_rgb(float t)
+{
+ if (t < 0.0) {
+ /* No weight */
+ return colorUnselect.rgb;
+ }
+ else if (t > 1.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ bool is_multiframe = (vflag & GP_EDIT_MULTIFRAME) != 0u;
+ bool is_stroke_sel = (vflag & GP_EDIT_STROKE_SELECTED) != 0u;
+ bool is_point_sel = (vflag & GP_EDIT_POINT_SELECTED) != 0u;
+
+ if (doWeightColor) {
+ finalColor.rgb = weight_to_rgb(weight);
+ finalColor.a = gpEditOpacity;
+ }
+ else {
+ finalColor = (is_point_sel) ? colorSelect : colorUnselect;
+ finalColor.a *= gpEditOpacity;
+ }
+
+#ifdef USE_POINTS
+ gl_PointSize = sizeVertex * 2.0;
+
+ if (doStrokeEndpoints && !doWeightColor) {
+ bool is_stroke_start = (vflag & GP_EDIT_STROKE_START) != 0u;
+ bool is_stroke_end = (vflag & GP_EDIT_STROKE_END) != 0u;
+
+ if (is_stroke_start) {
+ gl_PointSize *= 2.0;
+ finalColor.rgb = vec3(0.0, 1.0, 0.0);
+ }
+ else if (is_stroke_end) {
+ gl_PointSize *= 1.5;
+ finalColor.rgb = vec3(1.0, 0.0, 0.0);
+ }
+ }
+
+ if ((!is_stroke_sel && !doWeightColor) || (!doMultiframe && is_multiframe)) {
+ discard_vert();
+ }
+#endif
+
+ /* Discard unwanted padding vertices. */
+ if (ma == -1.0 || (is_multiframe && !doMultiframe)) {
+ discard_vert();
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
index f6e3724eb51..85f79e94263 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
@@ -1,10 +1,46 @@
+uniform vec4 gpDepthPlane;
+
flat in uint objectId;
/* using uint because 16bit uint can contain more ids than int. */
out uint outId;
+vec3 ray_plane_intersection(vec3 ray_ori, vec3 ray_dir, vec4 plane)
+{
+ float d = dot(plane.xyz, ray_dir);
+ vec3 plane_co = plane.xyz * (-plane.w / dot(plane.xyz, plane.xyz));
+ vec3 h = ray_ori - plane_co;
+ float lambda = -dot(plane.xyz, h) / ((abs(d) < 1e-8) ? 1e-8 : d);
+ return ray_ori + ray_dir * lambda;
+}
+
void main()
{
- outId = objectId;
+#ifdef USE_GPENCIL
+ if (stroke_round_cap_mask(strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness) <
+ 0.001) {
+ discard;
+ }
+
+ if (depth != -1.0) {
+ /* Stroke order 2D. */
+ bool is_persp = ProjectionMatrix[3][3] == 0.0;
+ vec2 uvs = vec2(gl_FragCoord.xy) * sizeViewportInv;
+ vec3 pos_ndc = vec3(uvs, gl_FragCoord.z) * 2.0 - 1.0;
+ vec4 pos_world = ViewProjectionMatrixInverse * vec4(pos_ndc, 1.0);
+ vec3 pos = pos_world.xyz / pos_world.w;
+
+ vec3 ray_ori = pos;
+ vec3 ray_dir = (is_persp) ? (ViewMatrixInverse[3].xyz - pos) : ViewMatrixInverse[2].xyz;
+ vec3 isect = ray_plane_intersection(ray_ori, ray_dir, gpDepthPlane);
+ vec4 ndc = point_world_to_ndc(isect);
+ gl_FragDepth = (ndc.z / ndc.w) * 0.5 + 0.5;
+ }
+ else {
+ gl_FragDepth = gl_FragCoord.z;
+ }
+#endif
+
+ outId = uint(objectId);
}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
index 984e55b0c46..a2021759196 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
@@ -1,7 +1,9 @@
uniform bool isTransform;
+#ifndef USE_GPENCIL
in vec3 pos;
+#endif
#ifdef USE_GEOM
out vec3 vPos;
@@ -47,11 +49,19 @@ uint outline_colorid_get(void)
void main()
{
+#ifdef USE_GPENCIL
+ gpencil_vertex();
+# ifdef USE_WORLD_CLIP_PLANES
+ vec3 world_pos = point_object_to_world(pos1.xyz);
+# endif
+
+#else
vec3 world_pos = point_object_to_world(pos);
-#ifdef USE_GEOM
+ gl_Position = point_world_to_ndc(world_pos);
+# ifdef USE_GEOM
vPos = point_world_to_view(world_pos);
+# endif
#endif
- gl_Position = point_world_to_ndc(world_pos);
/* Small bias to always be on top of the geom. */
gl_Position.z -= 1e-3;
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
index 31ac9a2b181..1abac302cda 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
@@ -101,8 +101,10 @@ void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
void main()
{
+ bool no_attrib = all(equal(nor, vec3(0)));
+ vec3 wnor = no_attrib ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor));
+
vec3 wpos = point_object_to_world(pos);
- vec3 wnor = normalize(normal_object_to_world(nor));
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz;
@@ -147,7 +149,7 @@ void main()
#endif
/* Cull flat edges below threshold. */
- if (get_edge_sharpness(wd) < 0.0) {
+ if (!no_attrib && (get_edge_sharpness(wd) < 0.0)) {
edgeStart = vec2(-1.0);
}
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index c8f74120113..6e005e7ccaf 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -117,6 +117,60 @@ static bool workbench_render_framebuffers_init(void)
return ok;
}
+static void workbench_render_result_z(struct RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect)
+{
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ if ((view_layer->passflag & SCE_PASS_Z) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_read_depth(dfbl->default_fb,
+ rect->xmin,
+ rect->ymin,
+ BLI_rcti_size_x(rect),
+ BLI_rcti_size_y(rect),
+ rp->rect);
+
+ float winmat[4][4];
+ DRW_view_winmat_get(NULL, winmat, false);
+
+ int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+
+ /* Convert ogl depth [0..1] to view Z [near..far] */
+ if (DRW_view_is_persp_get(NULL)) {
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
+ rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
+ rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
+ }
+ }
+ }
+ else {
+ /* Keep in mind, near and far distance are negatives. */
+ float near = DRW_view_near_distance_get(NULL);
+ float far = DRW_view_far_distance_get(NULL);
+ float range = fabsf(far - near);
+
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
+ rp->rect[i] = -rp->rect[i] * range + near;
+ }
+ }
+ }
+ }
+}
+
static void workbench_render_framebuffers_finish(void)
{
}
@@ -195,8 +249,8 @@ void workbench_render(WORKBENCH_Data *data,
const char *viewname = RE_GetActiveRenderView(engine->re);
RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- GPU_framebuffer_read_color(dfbl->color_only_fb,
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_read_color(dfbl->default_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
@@ -205,6 +259,8 @@ void workbench_render(WORKBENCH_Data *data,
0,
rp->rect);
+ workbench_render_result_z(render_layer, viewname, rect);
+
workbench_render_framebuffers_finish();
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index fc7ca6c7d67..cc257b80daf 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -280,8 +280,9 @@ typedef enum {
DRW_STATE_BLEND_BACKGROUND = (1 << 20),
DRW_STATE_BLEND_OIT = (1 << 21),
DRW_STATE_BLEND_MUL = (1 << 22),
+ DRW_STATE_BLEND_SUB = (1 << 23),
/** Use dual source blending. WARNING: Only one color buffer allowed. */
- DRW_STATE_BLEND_CUSTOM = (1 << 23),
+ DRW_STATE_BLEND_CUSTOM = (1 << 24),
DRW_STATE_IN_FRONT_SELECT = (1 << 25),
DRW_STATE_LOGIC_INVERT = (1 << 26),
@@ -362,10 +363,10 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
#define DRW_shgroup_call_no_cull(shgrp, geom, ob) \
DRW_shgroup_call_ex(shgrp, ob, NULL, geom, true, NULL)
-void DRW_shgroup_call_range(DRWShadingGroup *shgroup,
- struct GPUBatch *geom,
- uint v_sta,
- uint v_ct);
+void DRW_shgroup_call_range(
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct);
+void DRW_shgroup_call_instance_range(
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct);
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct);
void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct);
@@ -402,6 +403,17 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint
void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state);
void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state);
+
+/* Reminders:
+ * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
+ * stencil_value being the value stored in the stencil buffer.
+ * - (writemask & reference) is what gets written if the test condition is fullfiled.
+ **/
+void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
+ uint write_mask,
+ uint reference,
+ uint comp_mask);
+/* TODO remove this function. Obsolete version. mask is actually reference value. */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask);
/* Issue a clear command. */
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index f37e5b14d83..d0cea5b8c5c 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -136,6 +136,7 @@ static struct DRWShapeCache {
GPUBatch *drw_particle_cross;
GPUBatch *drw_particle_circle;
GPUBatch *drw_particle_axis;
+ GPUBatch *drw_gpencil_dummy_quad;
} SHC = {NULL};
void DRW_shape_cache_free(void)
@@ -747,6 +748,29 @@ GPUBatch *DRW_cache_normal_arrow_get(void)
}
/* -------------------------------------------------------------------- */
+/** \name Dummy vbos
+ *
+ * We need a dummy vbo containing the vertex count to draw instances ranges.
+ *
+ * \{ */
+
+GPUBatch *DRW_gpencil_dummy_buffer_get(void)
+{
+ if (SHC.drw_gpencil_dummy_quad == NULL) {
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+ GPU_vertbuf_data_alloc(vbo, 4);
+
+ SHC.drw_gpencil_dummy_quad = GPU_batch_create_ex(
+ GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ }
+ return SHC.drw_gpencil_dummy_quad;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Common Object API
* \{ */
@@ -793,6 +817,9 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob)
return DRW_cache_text_face_wireframe_get(ob);
case OB_MBALL:
return DRW_cache_mball_face_wireframe_get(ob);
+ case OB_GPENCIL: {
+ return DRW_cache_gpencil_face_wireframe_get(ob);
+ }
default:
return NULL;
}
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index cb81bdafe62..8ac0d7ada21 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -29,6 +29,7 @@ struct ModifierData;
struct Object;
struct PTCacheEdit;
struct ParticleSystem;
+struct bGPDstroke;
void DRW_shape_cache_free(void);
void DRW_shape_cache_reset(void);
@@ -46,6 +47,9 @@ struct GPUBatch *DRW_cache_cube_get(void);
struct GPUBatch *DRW_cache_sphere_get(void);
struct GPUBatch *DRW_cache_normal_arrow_get(void);
+/* Dummy VBOs */
+struct GPUBatch *DRW_gpencil_dummy_buffer_get(void);
+
/* Common Object */
struct GPUBatch *DRW_cache_object_all_edges_get(struct Object *ob);
struct GPUBatch *DRW_cache_object_edge_detection_get(struct Object *ob, bool *r_is_manifold);
@@ -196,4 +200,17 @@ struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob,
struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob);
struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold);
+/* GPencil */
+struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra);
+struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra);
+struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra);
+struct GPUBatch *DRW_cache_gpencil_edit_points_get(struct Object *ob, int cfra);
+struct GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(struct Object *ob);
+struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob);
+
+struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob);
+
+struct bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(struct Object *ob);
+void DRW_cache_gpencil_sbuffer_clear(struct Object *ob);
+
#endif /* __DRAW_CACHE_H__ */
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
new file mode 100644
index 00000000000..c6cedd3f1d2
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -0,0 +1,745 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_batch.h"
+#include "ED_gpencil.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "BLI_polyfill_2d.h"
+#include "BLI_hash.h"
+
+#include "draw_cache.h"
+#include "draw_cache_impl.h"
+
+/* ---------------------------------------------------------------------- */
+typedef struct GpencilBatchCache {
+ /** Instancing Data */
+ GPUVertBuf *vbo;
+ GPUVertBuf *vbo_col;
+ /** Fill Topology */
+ GPUIndexBuf *ibo;
+ /** Instancing Batches */
+ GPUBatch *stroke_batch;
+ GPUBatch *fill_batch;
+ GPUBatch *lines_batch;
+
+ /** Edit Mode */
+ GPUVertBuf *edit_vbo;
+ GPUBatch *edit_lines_batch;
+ GPUBatch *edit_points_batch;
+
+ /** Cache is dirty */
+ bool is_dirty;
+ /** Edit mode flag */
+ bool is_editmode;
+ /** Last cache frame */
+ int cache_frame;
+} GpencilBatchCache;
+
+static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
+{
+ bool valid = true;
+ if (cache == NULL) {
+ return false;
+ }
+
+ cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
+ if (cfra != cache->cache_frame) {
+ valid = false;
+ }
+ else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
+ valid = false;
+ }
+ else if (gpd->flag & GP_DATA_PYTHON_UPDATED) {
+ gpd->flag &= ~GP_DATA_PYTHON_UPDATED;
+ valid = false;
+ }
+ else if (cache->is_dirty) {
+ valid = false;
+ }
+
+ return valid;
+}
+
+static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ GpencilBatchCache *cache = gpd->runtime.gpencil_cache;
+
+ if (!cache) {
+ cache = gpd->runtime.gpencil_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
+ cache->is_dirty = true;
+ cache->cache_frame = cfra;
+ return cache;
+}
+
+static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
+{
+ if (!cache) {
+ return;
+ }
+
+ GPU_BATCH_DISCARD_SAFE(cache->lines_batch);
+ GPU_BATCH_DISCARD_SAFE(cache->fill_batch);
+ GPU_BATCH_DISCARD_SAFE(cache->stroke_batch);
+ GPU_VERTBUF_DISCARD_SAFE(cache->vbo);
+ GPU_VERTBUF_DISCARD_SAFE(cache->vbo_col);
+ GPU_INDEXBUF_DISCARD_SAFE(cache->ibo);
+
+ GPU_BATCH_DISCARD_SAFE(cache->edit_lines_batch);
+ GPU_BATCH_DISCARD_SAFE(cache->edit_points_batch);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edit_vbo);
+
+ cache->is_dirty = true;
+}
+
+static GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ GpencilBatchCache *cache = gpd->runtime.gpencil_cache;
+ if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
+ gpencil_batch_cache_clear(cache);
+ return gpencil_batch_cache_init(ob, cfra);
+ }
+ else {
+ return cache;
+ }
+}
+
+void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
+{
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+}
+
+void DRW_gpencil_batch_cache_free(bGPdata *gpd)
+{
+ gpencil_batch_cache_clear(gpd->runtime.gpencil_cache);
+ MEM_SAFE_FREE(gpd->runtime.gpencil_cache);
+ gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ return;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Formats.
+ * \{ */
+
+/* MUST match the format below. */
+typedef struct gpStrokeVert {
+ /** Mat is float because we need to pack other float attribs with it. */
+ float mat, strength, stroke_id, point_id;
+ /** Position and thickness packed in the same attribute. */
+ float pos[3], thickness;
+ float uv_fill[2], u_stroke, v_rot;
+ /** Aspect ratio and hardnes. */
+ float aspect_ratio, hardness;
+} gpStrokeVert;
+
+static GPUVertFormat *gpencil_stroke_format(void)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "ma", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "hard", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ /* IMPORTANT: This means having only 4 attributes to fit into GPU module limit of 16 attrib. */
+ GPU_vertformat_multiload_enable(&format, 4);
+ }
+ return &format;
+}
+
+/* MUST match the format below. */
+typedef struct gpEditVert {
+ uint vflag;
+ float weight;
+} gpEditVert;
+
+static GPUVertFormat *gpencil_edit_stroke_format(void)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "vflag", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+/* MUST match the format below. */
+typedef struct gpColorVert {
+ float vcol[4]; /* Vertex color */
+ float fcol[4]; /* Fill color */
+} gpColorVert;
+
+static GPUVertFormat *gpencil_color_format(void)
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "col", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "fcol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ /* IMPORTANT: This means having only 4 attributes to fit into GPU module limit of 16 attrib. */
+ GPU_vertformat_multiload_enable(&format, 4);
+ }
+ return &format;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Buffers.
+ * \{ */
+
+typedef struct gpIterData {
+ bGPdata *gpd;
+ gpStrokeVert *verts;
+ gpColorVert *cols;
+ GPUIndexBufBuilder ibo;
+ int vert_len;
+ int tri_len;
+} gpIterData;
+
+static GPUVertBuf *gpencil_dummy_buffer_get(void)
+{
+ GPUBatch *batch = DRW_gpencil_dummy_buffer_get();
+ return batch->verts[0];
+}
+
+static int gpencil_stroke_is_cyclic(const bGPDstroke *gps)
+{
+ return ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2);
+}
+
+static void gpencil_buffer_add_point(gpStrokeVert *verts,
+ gpColorVert *cols,
+ const bGPDstroke *gps,
+ const bGPDspoint *pt,
+ int v,
+ bool is_endpoint)
+{
+ /* Note: we use the sign of stength and thickness to pass cap flag. */
+ const bool round_cap0 = (gps->caps[0] == GP_STROKE_CAP_ROUND);
+ const bool round_cap1 = (gps->caps[1] == GP_STROKE_CAP_ROUND);
+ gpStrokeVert *vert = &verts[v];
+ gpColorVert *col = &cols[v];
+ copy_v3_v3(vert->pos, &pt->x);
+ copy_v2_v2(vert->uv_fill, pt->uv_fill);
+ copy_v4_v4(col->vcol, pt->vert_color);
+ copy_v4_v4(col->fcol, gps->vert_color_fill);
+
+ /* Encode fill opacity defined by opacity modifier in vertex color alpha. If
+ * no opacity modifier, the value will be always 1.0f. The opacity factor can be any
+ * value between 0.0f and 2.0f */
+ col->fcol[3] = (((int)(col->fcol[3] * 10000.0f)) * 10.0f) + gps->fill_opacity_fac;
+
+ vert->strength = (round_cap0) ? pt->strength : -pt->strength;
+ vert->u_stroke = pt->uv_fac;
+ vert->stroke_id = gps->runtime.stroke_start;
+ vert->point_id = v;
+ /* Rotation are in [-90°..90°] range, so we can encode the sign of the angle + the cosine
+ * because the cosine will always be positive. */
+ vert->v_rot = cosf(pt->uv_rot) * signf(pt->uv_rot);
+ vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0 : -1.0);
+ /* Tag endpoint material to -1 so they get discarded by vertex shader. */
+ vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GP_MATERIAL_BUFFER_LEN);
+
+ vert->aspect_ratio = gps->aspect_ratio[0] / max_ff(gps->aspect_ratio[1], 1e-8);
+ vert->hardness = gps->hardeness;
+}
+
+static void gpencil_buffer_add_stroke(gpStrokeVert *verts,
+ gpColorVert *cols,
+ const bGPDstroke *gps)
+{
+ const bGPDspoint *pts = gps->points;
+ int pts_len = gps->totpoints;
+ bool is_cyclic = gpencil_stroke_is_cyclic(gps);
+ int v = gps->runtime.stroke_start;
+
+ /* First point for adjacency (not drawn). */
+ int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1);
+ gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
+
+ for (int i = 0; i < pts_len; i++) {
+ gpencil_buffer_add_point(verts, cols, gps, &pts[i], v++, false);
+ }
+ /* Draw line to first point to complete the loop for cyclic strokes. */
+ if (is_cyclic) {
+ gpencil_buffer_add_point(verts, cols, gps, &pts[0], v++, false);
+ }
+ /* Last adjacency point (not drawn). */
+ adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
+ gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
+}
+
+static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps)
+{
+ int tri_len = gps->tot_triangles;
+ int v = gps->runtime.stroke_start;
+ for (int i = 0; i < tri_len; i++) {
+ uint *tri = gps->triangles[i].verts;
+ GPU_indexbuf_add_tri_verts(ibo, v + tri[0], v + tri[1], v + tri[2]);
+ }
+}
+
+static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl),
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ void *thunk)
+{
+ gpIterData *iter = (gpIterData *)thunk;
+ gpencil_buffer_add_stroke(iter->verts, iter->cols, gps);
+ if (gps->tot_triangles > 0) {
+ gpencil_buffer_add_fill(&iter->ibo, gps);
+ }
+}
+
+static void gp_object_verts_count_cb(bGPDlayer *UNUSED(gpl),
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ void *thunk)
+{
+ gpIterData *iter = (gpIterData *)thunk;
+
+ /* Store first index offset */
+ gps->runtime.stroke_start = iter->vert_len;
+ gps->runtime.fill_start = iter->tri_len;
+ iter->vert_len += gps->totpoints + 2 + gpencil_stroke_is_cyclic(gps);
+ iter->tri_len += gps->tot_triangles;
+}
+
+static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ if (cache->vbo == NULL) {
+ /* Should be discarded together. */
+ BLI_assert(cache->vbo == NULL && cache->ibo == NULL);
+ BLI_assert(cache->stroke_batch == NULL && cache->stroke_batch == NULL);
+ /* TODO/PERF: Could be changed to only do it if needed.
+ * For now it's simpler to assume we always need it
+ * since multiple viewport could or could not need it.
+ * Ideally we should have a dedicated onion skin geom batch. */
+ /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
+ bool do_onion = true;
+
+ /* First count how many vertices and triangles are needed for the whole object. */
+ gpIterData iter = {
+ .gpd = gpd,
+ .verts = NULL,
+ .ibo = {0},
+ .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */
+ .tri_len = 0,
+ };
+ BKE_gpencil_visible_stroke_iter(ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra);
+
+ /* Create VBOs. */
+ GPUVertFormat *format = gpencil_stroke_format();
+ GPUVertFormat *format_col = gpencil_color_format();
+ cache->vbo = GPU_vertbuf_create_with_format(format);
+ cache->vbo_col = GPU_vertbuf_create_with_format(format_col);
+ /* Add extra space at the end of the buffer because of quad load. */
+ GPU_vertbuf_data_alloc(cache->vbo, iter.vert_len + 2);
+ GPU_vertbuf_data_alloc(cache->vbo_col, iter.vert_len + 2);
+ iter.verts = (gpStrokeVert *)cache->vbo->data;
+ iter.cols = (gpColorVert *)cache->vbo_col->data;
+ /* Create IBO. */
+ GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len);
+
+ /* Fill buffers with data. */
+ BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra);
+
+ /* Mark last 2 verts as invalid. */
+ for (int i = 0; i < 2; i++) {
+ iter.verts[iter.vert_len + i].mat = -1;
+ }
+
+ /* Finish the IBO. */
+ cache->ibo = GPU_indexbuf_build(&iter.ibo);
+
+ /* Create the batches */
+ cache->fill_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo);
+ GPU_batch_vertbuf_add(cache->fill_batch, cache->vbo_col);
+ cache->stroke_batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL);
+ GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo, 0);
+ GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo_col, 0);
+
+ gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
+ cache->is_dirty = false;
+ }
+}
+
+GPUBatch *DRW_cache_gpencil_strokes_get(Object *ob, int cfra)
+{
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
+ gpencil_batches_ensure(ob, cache, cfra);
+
+ return cache->stroke_batch;
+}
+
+GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra)
+{
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
+ gpencil_batches_ensure(ob, cache, cfra);
+
+ return cache->fill_batch;
+}
+
+static void gp_lines_indices_cb(bGPDlayer *UNUSED(gpl),
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ void *thunk)
+{
+ gpIterData *iter = (gpIterData *)thunk;
+ int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps);
+
+ int start = gps->runtime.stroke_start + 1;
+ int end = start + pts_len;
+ for (int i = start; i < end; i++) {
+ GPU_indexbuf_add_generic_vert(&iter->ibo, i);
+ }
+ GPU_indexbuf_add_primitive_restart(&iter->ibo);
+}
+
+GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ int cfra = DEG_get_ctime(draw_ctx->depsgraph);
+
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
+ gpencil_batches_ensure(ob, cache, cfra);
+
+ if (cache->lines_batch == NULL) {
+ GPUVertBuf *vbo = cache->vbo;
+
+ gpIterData iter = {
+ .gpd = ob->data,
+ .ibo = {0},
+ };
+
+ GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vbo->vertex_len, vbo->vertex_len);
+
+ /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
+ bool do_onion = true;
+ BKE_gpencil_visible_stroke_iter(ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra);
+
+ GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo);
+
+ cache->lines_batch = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, ibo, GPU_BATCH_OWNS_INDEX);
+ }
+ return cache->lines_batch;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Sbuffer stroke batches.
+ * \{ */
+
+bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Brush *brush = gpd->runtime.sbuffer_brush;
+ /* Convert the sbuffer to a bGPDstroke. */
+ if (gpd->runtime.sbuffer_gps == NULL) {
+ bGPDstroke *gps = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer");
+ gps->totpoints = gpd->runtime.sbuffer_used;
+ gps->mat_nr = max_ii(0, gpd->runtime.matid - 1);
+ gps->flag = gpd->runtime.sbuffer_sflag;
+ gps->thickness = brush->size;
+ gps->hardeness = brush->gpencil_settings->hardeness;
+ copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
+
+ /* Reduce slightly the opacity of fill to make easy fill areas while drawing. */
+ gps->fill_opacity_fac = 0.8f;
+
+ gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2);
+ gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND;
+ gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */
+ copy_v4_v4(gps->vert_color_fill, gpd->runtime.vert_color_fill);
+ gpd->runtime.sbuffer_gps = gps;
+ }
+ return gpd->runtime.sbuffer_gps;
+}
+
+static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill)
+{
+ tGPspoint *tpoints = gpd->runtime.sbuffer;
+ bGPDstroke *gps = gpd->runtime.sbuffer_gps;
+ int vert_len = gpd->runtime.sbuffer_used;
+
+ /* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */
+ BLI_assert(gps != NULL);
+
+ if (do_stroke && (gpd->runtime.sbuffer_stroke_batch == NULL)) {
+ gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__);
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ ARegion *region = draw_ctx->region;
+ Object *ob = draw_ctx->obact;
+
+ BLI_assert(ob && (ob->type == OB_GPENCIL));
+
+ /* Get origin to reproject points. */
+ float origin[3];
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ ToolSettings *ts = scene->toolsettings;
+ ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+
+ for (int i = 0; i < vert_len; i++) {
+ ED_gpencil_tpoint_to_point(region, origin, &tpoints[i], &gps->points[i]);
+ mul_m4_v3(ob->imat, &gps->points[i].x);
+ bGPDspoint *pt = &gps->points[i];
+ copy_v4_v4(pt->vert_color, gpd->runtime.vert_color);
+ }
+ /* Calc uv data along the stroke. */
+ BKE_gpencil_stroke_uv_update(gps);
+
+ /* Create VBO. */
+ GPUVertFormat *format = gpencil_stroke_format();
+ GPUVertFormat *format_color = gpencil_color_format();
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(format);
+ GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(format_color);
+ /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */
+ GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2);
+ GPU_vertbuf_data_alloc(vbo_col, 1 + vert_len + 1 + 2);
+ gpStrokeVert *verts = (gpStrokeVert *)vbo->data;
+ gpColorVert *cols = (gpColorVert *)vbo_col->data;
+
+ /* Fill buffers with data. */
+ gpencil_buffer_add_stroke(verts, cols, gps);
+
+ GPUBatch *batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL);
+ GPU_batch_instbuf_add_ex(batch, vbo, true);
+ GPU_batch_instbuf_add_ex(batch, vbo_col, true);
+
+ gpd->runtime.sbuffer_stroke_batch = batch;
+
+ MEM_freeN(gps->points);
+ }
+
+ if (do_fill && (gpd->runtime.sbuffer_fill_batch == NULL)) {
+ /* Create IBO. */
+ GPUIndexBufBuilder ibo_builder;
+ GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len);
+
+ if (gps->tot_triangles > 0) {
+ float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
+ /* Triangulate in 2D. */
+ for (int i = 0; i < vert_len; i++) {
+ copy_v2_v2(tpoints2d[i], &tpoints[i].x);
+ }
+ /* Compute directly inside the IBO data buffer. */
+ /* OPTI: This is a bottleneck if the stroke is very long. */
+ BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data);
+ /* Add stroke start offset. */
+ for (int i = 0; i < gps->tot_triangles * 3; i++) {
+ ibo_builder.data[i] += gps->runtime.stroke_start;
+ }
+ /* HACK since we didn't use the builder API to avoid another malloc and copy,
+ * we need to set the number of indices manually. */
+ ibo_builder.index_len = gps->tot_triangles * 3;
+
+ MEM_freeN(tpoints2d);
+ }
+
+ GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder);
+ GPUVertBuf *vbo = gpd->runtime.sbuffer_stroke_batch->inst[0];
+ GPUVertBuf *vbo_col = gpd->runtime.sbuffer_stroke_batch->inst[1];
+
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_INDEX);
+ GPU_batch_vertbuf_add(batch, vbo_col);
+
+ gpd->runtime.sbuffer_fill_batch = batch;
+ }
+}
+
+GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(Object *ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ gpencil_sbuffer_stroke_ensure(gpd, true, false);
+
+ return gpd->runtime.sbuffer_stroke_batch;
+}
+
+GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* Fill batch also need stroke batch to be created (vbo is shared). */
+ gpencil_sbuffer_stroke_ensure(gpd, true, true);
+
+ return gpd->runtime.sbuffer_fill_batch;
+}
+
+/* Sbuffer batches are temporary. We need to clear it after drawing */
+void DRW_cache_gpencil_sbuffer_clear(Object *ob)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ MEM_SAFE_FREE(gpd->runtime.sbuffer_gps);
+ GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_fill_batch);
+ GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_stroke_batch);
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/* Edit GPencil Batches */
+
+#define GP_EDIT_POINT_SELECTED (1 << 0)
+#define GP_EDIT_STROKE_SELECTED (1 << 1)
+#define GP_EDIT_MULTIFRAME (1 << 2)
+#define GP_EDIT_STROKE_START (1 << 3)
+#define GP_EDIT_STROKE_END (1 << 4)
+
+typedef struct gpEditIterData {
+ gpEditVert *verts;
+ int vgindex;
+} gpEditIterData;
+
+static uint32_t gpencil_point_edit_flag(const bool layer_lock,
+ const bGPDspoint *pt,
+ int v,
+ int v_len)
+{
+ uint32_t sflag = 0;
+ SET_FLAG_FROM_TEST(sflag, (!layer_lock) && pt->flag & GP_SPOINT_SELECT, GP_EDIT_POINT_SELECTED);
+ SET_FLAG_FROM_TEST(sflag, v == 0, GP_EDIT_STROKE_START);
+ SET_FLAG_FROM_TEST(sflag, v == (v_len - 1), GP_EDIT_STROKE_END);
+ return sflag;
+}
+
+static float gpencil_point_edit_weight(const MDeformVert *dvert, int v, int vgindex)
+{
+ return (dvert && dvert[v].dw) ? BKE_defvert_find_weight(&dvert[v], vgindex) : -1.0f;
+}
+
+static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ void *thunk)
+{
+ gpEditIterData *iter = (gpEditIterData *)thunk;
+ const int v_len = gps->totpoints;
+ const int v = gps->runtime.stroke_start + 1;
+ MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : NULL;
+ gpEditVert *vert_ptr = iter->verts + v;
+
+ const bool layer_lock = (gpl->flag & GP_LAYER_LOCKED);
+ uint32_t sflag = 0;
+ SET_FLAG_FROM_TEST(
+ sflag, (!layer_lock) && gps->flag & GP_STROKE_SELECT, GP_EDIT_STROKE_SELECTED);
+ SET_FLAG_FROM_TEST(sflag, gpf->runtime.onion_id != 0.0f, GP_EDIT_MULTIFRAME);
+
+ for (int i = 0; i < v_len; i++) {
+ vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[i], i, v_len);
+ vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex);
+ vert_ptr++;
+ }
+ /* Draw line to first point to complete the loop for cyclic strokes. */
+ vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len);
+ vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex);
+}
+
+static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ if (cache->edit_vbo == NULL) {
+ /* TODO/PERF: Could be changed to only do it if needed.
+ * For now it's simpler to assume we always need it
+ * since multiple viewport could or could not need it.
+ * Ideally we should have a dedicated onion skin geom batch. */
+ /* IMPORTANT: Keep in sync with gpencil_batches_ensure() */
+ bool do_onion = true;
+
+ /* Vertex counting has already been done for cache->vbo. */
+ BLI_assert(cache->vbo);
+ int vert_len = cache->vbo->vertex_len;
+
+ gpEditIterData iter;
+ iter.vgindex = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, iter.vgindex)) {
+ iter.vgindex = -1;
+ }
+
+ /* Create VBO. */
+ GPUVertFormat *format = gpencil_edit_stroke_format();
+ cache->edit_vbo = GPU_vertbuf_create_with_format(format);
+ /* Add extra space at the end of the buffer because of quad load. */
+ GPU_vertbuf_data_alloc(cache->edit_vbo, vert_len);
+ iter.verts = (gpEditVert *)cache->edit_vbo->data;
+
+ /* Fill buffers with data. */
+ BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra);
+
+ /* Create the batches */
+ cache->edit_points_batch = GPU_batch_create(GPU_PRIM_POINTS, cache->vbo, NULL);
+ GPU_batch_vertbuf_add(cache->edit_points_batch, cache->edit_vbo);
+
+ cache->edit_lines_batch = GPU_batch_create(GPU_PRIM_LINE_STRIP, cache->vbo, NULL);
+ GPU_batch_vertbuf_add(cache->edit_lines_batch, cache->edit_vbo);
+
+ gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
+ cache->is_dirty = false;
+ }
+}
+
+GPUBatch *DRW_cache_gpencil_edit_lines_get(Object *ob, int cfra)
+{
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
+ gpencil_batches_ensure(ob, cache, cfra);
+ gpencil_edit_batches_ensure(ob, cache, cfra);
+
+ return cache->edit_lines_batch;
+}
+
+GPUBatch *DRW_cache_gpencil_edit_points_get(Object *ob, int cfra)
+{
+ GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
+ gpencil_batches_ensure(ob, cache, cfra);
+ gpencil_edit_batches_ensure(ob, cache, cfra);
+
+ return cache->edit_points_batch;
+}
+
+/** \} */
diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c
index a4e46b3b59f..b1ad1455d8c 100644
--- a/source/blender/draw/intern/draw_common.c
+++ b/source/blender/draw/intern/draw_common.c
@@ -72,6 +72,8 @@ void DRW_globals_update(void)
UI_COLOR_RGBA_FROM_U8(0xB0, 0x00, 0xB0, 0xFF, gb->colorVertexMissingData);
UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, gb->colorEditMeshActive);
UI_GetThemeColor4fv(TH_EDGE_SELECT, gb->colorEdgeSelect);
+ UI_GetThemeColor4fv(TH_GP_VERTEX, gb->colorGpencilVertex);
+ UI_GetThemeColor4fv(TH_GP_VERTEX_SELECT, gb->colorGpencilVertexSelect);
UI_GetThemeColor4fv(TH_EDGE_SEAM, gb->colorEdgeSeam);
UI_GetThemeColor4fv(TH_EDGE_SHARP, gb->colorEdgeSharp);
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index bea287da4e9..24d3b7fa7b6 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -68,6 +68,8 @@ typedef struct GlobalsUboStorage {
float colorFace[4];
float colorFaceSelect[4];
float colorFaceFreestyle[4];
+ float colorGpencilVertex[4];
+ float colorGpencilVertexSelect[4];
float colorNormal[4];
float colorVNormal[4];
float colorLNormal[4];
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 4ec49536211..85caf0825e0 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1183,7 +1183,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer),
const bool use_xray = XRAY_ENABLED(v3d);
drw_engines_enable_from_engine(engine_type, drawtype, use_xray);
- if (gpencil_engine_needed) {
+ if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) {
use_drw_engine(&draw_engine_gpencil_type);
}
drw_engines_enable_overlays();
@@ -1654,14 +1654,6 @@ static void DRW_render_gpencil_to_image(RenderEngine *engine,
void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph)
{
- /* This function is only valid for Cycles & Workbench
- * Eevee does all work in the Eevee render directly.
- * Maybe it can be done equal for all engines?
- */
- if (STREQ(engine->type->name, "Eevee")) {
- return;
- }
-
/* Early out if there are no grease pencil objects, especially important
* to avoid failing in in background renders without OpenGL context. */
if (!DRW_render_check_grease_pencil(depsgraph)) {
@@ -1740,8 +1732,13 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph
GPU_framebuffer_restore();
/* Changing Context */
- /* GPXX Review this context */
- DRW_opengl_context_disable();
+ if (re_gl_context != NULL) {
+ DRW_gpu_render_context_disable(re_gpu_context);
+ DRW_opengl_render_context_disable(re_gl_context);
+ }
+ else {
+ DRW_opengl_context_disable();
+ }
DST.buffer_finish_called = false;
}
@@ -1838,14 +1835,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
drw_view_reset();
engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect);
DST.buffer_finish_called = false;
-
- /* grease pencil: render result is merged in the previous render result. */
- if (DRW_render_check_grease_pencil(depsgraph)) {
- DRW_state_reset();
- drw_view_reset();
- DRW_render_gpencil_to_image(engine, render_layer, &render_rect);
- DST.buffer_finish_called = false;
- }
}
RE_engine_end_result(engine, render_result, false, false, false);
@@ -2215,13 +2204,6 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
}
}
- /* TODO: GPXX Workaround for grease pencil selection while draw manager support a callback from
- * scene finish */
- void *data = GPU_viewport_engine_data_get(DST.viewport, &draw_engine_gpencil_type);
- if (data != NULL) {
- DRW_gpencil_free_runtime_data(data);
- }
-
DRW_state_lock(0);
DRW_state_reset();
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 6d415ee95b3..cb825becd73 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -181,7 +181,8 @@ typedef enum {
DRW_CMD_DRAW = 0, /* Only sortable type. Must be 0. */
DRW_CMD_DRAW_RANGE = 1,
DRW_CMD_DRAW_INSTANCE = 2,
- DRW_CMD_DRAW_PROCEDURAL = 3,
+ DRW_CMD_DRAW_INSTANCE_RANGE = 3,
+ DRW_CMD_DRAW_PROCEDURAL = 4,
/* Other Commands */
DRW_CMD_CLEAR = 12,
DRW_CMD_DRWSTATE = 13,
@@ -200,6 +201,7 @@ typedef struct DRWCommandDraw {
/* Assume DRWResourceHandle to be 0. */
typedef struct DRWCommandDrawRange {
GPUBatch *batch;
+ DRWResourceHandle handle;
uint vert_first;
uint vert_count;
} DRWCommandDrawRange;
@@ -211,6 +213,13 @@ typedef struct DRWCommandDrawInstance {
uint use_attribs; /* bool */
} DRWCommandDrawInstance;
+typedef struct DRWCommandDrawInstanceRange {
+ GPUBatch *batch;
+ DRWResourceHandle handle;
+ uint inst_first;
+ uint inst_count;
+} DRWCommandDrawInstanceRange;
+
typedef struct DRWCommandDrawProcedural {
GPUBatch *batch;
DRWResourceHandle handle;
@@ -224,7 +233,9 @@ typedef struct DRWCommandSetMutableState {
} DRWCommandSetMutableState;
typedef struct DRWCommandSetStencil {
- uint mask;
+ uint write_mask;
+ uint comp_mask;
+ uint ref;
} DRWCommandSetStencil;
typedef struct DRWCommandSetSelectID {
@@ -243,6 +254,7 @@ typedef union DRWCommand {
DRWCommandDraw draw;
DRWCommandDrawRange range;
DRWCommandDrawInstance instance;
+ DRWCommandDrawInstanceRange instance_range;
DRWCommandDrawProcedural procedural;
DRWCommandSetMutableState state;
DRWCommandSetStencil stencil;
@@ -273,6 +285,7 @@ typedef enum {
DRW_UNIFORM_BLOCK_OBMATS,
DRW_UNIFORM_BLOCK_OBINFOS,
DRW_UNIFORM_RESOURCE_CHUNK,
+ DRW_UNIFORM_RESOURCE_ID,
/** Legacy / Fallback */
DRW_UNIFORM_BASE_INSTANCE,
DRW_UNIFORM_MODEL_MATRIX,
@@ -469,7 +482,6 @@ typedef struct DRWManager {
/* Managed by `DRW_state_set`, `DRW_state_reset` */
DRWState state;
DRWState state_lock;
- uint stencil_mask;
/* Per viewport */
GPUViewport *viewport;
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 28d5daf011c..83142da051a 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -637,13 +637,12 @@ static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResou
cmd->handle = handle;
}
-static void drw_command_draw_range(DRWShadingGroup *shgroup,
- GPUBatch *batch,
- uint start,
- uint count)
+static void drw_command_draw_range(
+ DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint start, uint count)
{
DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE);
cmd->batch = batch;
+ cmd->handle = handle;
cmd->vert_first = start;
cmd->vert_count = count;
}
@@ -661,6 +660,16 @@ static void drw_command_draw_instance(DRWShadingGroup *shgroup,
cmd->use_attribs = use_attrib;
}
+static void drw_command_draw_intance_range(
+ DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint start, uint count)
+{
+ DRWCommandDrawInstanceRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE_RANGE);
+ cmd->batch = batch;
+ cmd->handle = handle;
+ cmd->inst_first = start;
+ cmd->inst_count = count;
+}
+
static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
GPUBatch *batch,
DRWResourceHandle handle,
@@ -681,11 +690,18 @@ static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf,
cmd->select_id = select_id;
}
-static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint mask)
+static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup,
+ uint write_mask,
+ uint reference,
+ uint comp_mask)
{
- BLI_assert(mask <= 0xFF);
+ BLI_assert(write_mask <= 0xFF);
+ BLI_assert(reference <= 0xFF);
+ BLI_assert(comp_mask <= 0xFF);
DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL);
- cmd->mask = mask;
+ cmd->write_mask = write_mask;
+ cmd->comp_mask = comp_mask;
+ cmd->ref = reference;
}
static void drw_command_clear(DRWShadingGroup *shgroup,
@@ -746,13 +762,27 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup,
}
}
-void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint v_sta, uint v_ct)
+void DRW_shgroup_call_range(
+ DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_ct)
+{
+ BLI_assert(geom != NULL);
+ if (G.f & G_FLAG_PICKSEL) {
+ drw_command_set_select_id(shgroup, NULL, DST.select_id);
+ }
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct);
+}
+
+void DRW_shgroup_call_instance_range(
+ DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct)
{
+ BLI_assert(i_ct > 0);
BLI_assert(geom != NULL);
if (G.f & G_FLAG_PICKSEL) {
drw_command_set_select_id(shgroup, NULL, DST.select_id);
}
- drw_command_draw_range(shgroup, geom, v_sta, v_ct);
+ DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob);
+ drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_ct);
}
static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup,
@@ -1101,12 +1131,18 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock");
int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE);
int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
+ int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID);
if (chunkid_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1);
}
+ if (resourceid_location != -1) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 1);
+ }
+
if (baseinst_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1);
@@ -1302,9 +1338,18 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state)
drw_command_set_mutable_state(shgroup, 0x0, state);
}
+void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup,
+ uint write_mask,
+ uint reference,
+ uint comp_mask)
+{
+ drw_command_set_stencil_mask(shgroup, write_mask, reference, comp_mask);
+}
+
+/* TODO remove this function. */
void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask)
{
- drw_command_set_stencil_mask(shgroup, mask);
+ drw_command_set_stencil_mask(shgroup, 0xFF, mask, 0xFF);
}
void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 90de20c0d30..49c71a3f212 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -50,6 +50,7 @@ void DRW_select_load_id(uint id)
typedef struct DRWCommandsState {
GPUBatch *batch;
int resource_chunk;
+ int resource_id;
int base_inst;
int inst_count;
int v_first;
@@ -60,6 +61,7 @@ typedef struct DRWCommandsState {
int obinfos_loc;
int baseinst_loc;
int chunkid_loc;
+ int resourceid_loc;
/* Legacy matrix support. */
int obmat_loc;
int obinv_loc;
@@ -221,7 +223,6 @@ void drw_state_set(DRWState state)
{
int test;
if (CHANGED_ANY_STORE_VAR(DRW_STATE_STENCIL_TEST_ENABLED, test)) {
- DST.stencil_mask = STENCIL_UNDEFINED;
if (test) {
glEnable(GL_STENCIL_TEST);
}
@@ -234,11 +235,12 @@ void drw_state_set(DRWState state)
/* Blending (all buffer) */
{
int test;
- if (CHANGED_ANY_STORE_VAR(
- DRW_STATE_BLEND_ALPHA | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_BLEND_ADD |
- DRW_STATE_BLEND_MUL | DRW_STATE_BLEND_ADD_FULL | DRW_STATE_BLEND_OIT |
- DRW_STATE_BLEND_BACKGROUND | DRW_STATE_BLEND_CUSTOM | DRW_STATE_LOGIC_INVERT,
- test)) {
+ if (CHANGED_ANY_STORE_VAR(DRW_STATE_BLEND_ALPHA | DRW_STATE_BLEND_ALPHA_PREMUL |
+ DRW_STATE_BLEND_ADD | DRW_STATE_BLEND_MUL |
+ DRW_STATE_BLEND_ADD_FULL | DRW_STATE_BLEND_OIT |
+ DRW_STATE_BLEND_BACKGROUND | DRW_STATE_BLEND_CUSTOM |
+ DRW_STATE_LOGIC_INVERT | DRW_STATE_BLEND_SUB,
+ test)) {
if (test) {
glEnable(GL_BLEND);
@@ -278,6 +280,9 @@ void drw_state_set(DRWState state)
/* Let alpha accumulate. */
glBlendFunc(GL_ONE, GL_ONE);
}
+ else if ((state & DRW_STATE_BLEND_SUB) != 0) {
+ glBlendFunc(GL_ONE, GL_ONE);
+ }
else if ((state & DRW_STATE_BLEND_CUSTOM) != 0) {
/* Custom blend parameters using dual source blending.
* Can only be used with one Draw Buffer. */
@@ -293,6 +298,13 @@ void drw_state_set(DRWState state)
else {
BLI_assert(0);
}
+
+ if ((state & DRW_STATE_BLEND_SUB) != 0) {
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ }
+ else {
+ glBlendEquation(GL_FUNC_ADD);
+ }
}
else {
glDisable(GL_BLEND);
@@ -385,19 +397,23 @@ void drw_state_set(DRWState state)
DST.state = state;
}
-static void drw_stencil_set(uint mask)
+static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_mask)
{
- if (DST.stencil_mask != mask) {
- DST.stencil_mask = mask;
- if ((DST.state & DRW_STATE_STENCIL_ALWAYS) != 0) {
- glStencilFunc(GL_ALWAYS, mask, 0xFF);
- }
- else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) {
- glStencilFunc(GL_EQUAL, mask, 0xFF);
- }
- else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) {
- glStencilFunc(GL_NOTEQUAL, mask, 0xFF);
- }
+ /* Reminders:
+ * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
+ * stencil_value being the value stored in the stencil buffer.
+ * - (writemask & reference) is what gets written if the test condition is fullfiled.
+ **/
+ glStencilMask(write_mask);
+
+ if ((DST.state & DRW_STATE_STENCIL_ALWAYS) != 0) {
+ glStencilFunc(GL_ALWAYS, reference, compare_mask);
+ }
+ else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) {
+ glStencilFunc(GL_EQUAL, reference, compare_mask);
+ }
+ else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) {
+ glStencilFunc(GL_NOTEQUAL, reference, compare_mask);
}
}
@@ -978,6 +994,9 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
state->chunkid_loc = uni->location;
GPU_shader_uniform_int(shgroup->shader, uni->location, 0);
break;
+ case DRW_UNIFORM_RESOURCE_ID:
+ state->resourceid_loc = uni->location;
+ break;
case DRW_UNIFORM_TFEEDBACK_TARGET:
BLI_assert(data && (*use_tfeedback == false));
*use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
@@ -1096,6 +1115,14 @@ static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHa
}
state->resource_chunk = chunk;
}
+
+ if (state->resourceid_loc != -1) {
+ int id = DRW_handle_id_get(handle);
+ if (state->resource_id != id) {
+ GPU_shader_uniform_int(NULL, state->resourceid_loc, id);
+ state->resource_id = id;
+ }
+ }
}
static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state)
@@ -1114,6 +1141,7 @@ static void draw_call_single_do(DRWShadingGroup *shgroup,
DRWResourceHandle handle,
int vert_first,
int vert_count,
+ int inst_first,
int inst_count,
bool do_base_instance)
{
@@ -1142,7 +1170,7 @@ static void draw_call_single_do(DRWShadingGroup *shgroup,
batch,
vert_first,
vert_count,
- do_base_instance ? DRW_handle_id_get(&handle) : 0,
+ do_base_instance ? DRW_handle_id_get(&handle) : inst_first,
inst_count,
state->baseinst_loc);
}
@@ -1151,6 +1179,7 @@ static void draw_call_batching_start(DRWCommandsState *state)
{
state->neg_scale = false;
state->resource_chunk = 0;
+ state->resource_id = -1;
state->base_inst = 0;
state->inst_count = 0;
state->v_first = 0;
@@ -1227,6 +1256,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
.obinfos_loc = -1,
.baseinst_loc = -1,
.chunkid_loc = -1,
+ .resourceid_loc = -1,
.obmat_loc = -1,
.obinv_loc = -1,
.mvp_loc = -1,
@@ -1307,7 +1337,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled);
break;
case DRW_CMD_STENCIL:
- drw_stencil_set(cmd->stencil.mask);
+ drw_stencil_state_set(cmd->stencil.write_mask, cmd->stencil.ref, cmd->stencil.comp_mask);
break;
case DRW_CMD_SELECTID:
state.select_id = cmd->select_id.select_id;
@@ -1315,8 +1345,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
break;
case DRW_CMD_DRAW:
if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
- cmd->draw.batch->inst[0]) {
- draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0, true);
+ cmd->draw.batch->inst) {
+ draw_call_single_do(
+ shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0, 0, true);
}
else {
draw_call_batching_do(shgroup, &state, &cmd->draw);
@@ -1329,6 +1360,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
cmd->procedural.handle,
0,
cmd->procedural.vert_count,
+ 0,
1,
true);
break;
@@ -1339,6 +1371,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
cmd->instance.handle,
0,
0,
+ 0,
cmd->instance.inst_count,
cmd->instance.use_attribs == 0);
break;
@@ -1346,12 +1379,24 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
draw_call_single_do(shgroup,
&state,
cmd->range.batch,
- (DRWResourceHandle)0,
+ cmd->range.handle,
cmd->range.vert_first,
cmd->range.vert_count,
+ 0,
1,
true);
break;
+ case DRW_CMD_DRAW_INSTANCE_RANGE:
+ draw_call_single_do(shgroup,
+ &state,
+ cmd->instance_range.batch,
+ cmd->instance_range.handle,
+ 0,
+ 0,
+ cmd->instance_range.inst_first,
+ cmd->instance_range.inst_count,
+ false);
+ break;
}
}
diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl
index 6a3bf150095..cfadb87819c 100644
--- a/source/blender/draw/intern/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl
@@ -32,6 +32,8 @@ layout(std140) uniform globalsBlock
vec4 colorFace;
vec4 colorFaceSelect;
vec4 colorFaceFreestyle;
+ vec4 colorGpencilVertex;
+ vec4 colorGpencilVertexSelect;
vec4 colorNormal;
vec4 colorVNormal;
vec4 colorLNormal;
diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
index 09b573d4bb5..45d9f54d943 100644
--- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
@@ -692,6 +692,10 @@ void SMAANeighborhoodBlendingVS(float2 texcoord, out float4 offset)
//-----------------------------------------------------------------------------
// Edge Detection Pixel Shaders (First Pass)
+# ifndef SMAA_LUMA_WEIGHT
+# define SMAA_LUMA_WEIGHT float4(0.2126, 0.7152, 0.0722, 0.0)
+# endif
+
/**
* Luma Edge Detection
*
@@ -716,7 +720,8 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord,
# endif
// Calculate lumas:
- float4 weights = float4(0.2126 * 0.5, 0.7152 * 0.5, 0.0722 * 0.5, 0.5);
+ // float4 weights = float4(0.2126, 0.7152, 0.0722, 0.0);
+ float4 weights = SMAA_LUMA_WEIGHT;
float L = dot(SMAASamplePoint(colorTex, texcoord).rgba, weights);
float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgba, weights);
@@ -727,9 +732,11 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord,
delta.xy = abs(L - float2(Lleft, Ltop));
float2 edges = step(threshold, delta.xy);
+# ifndef SMAA_NO_DISCARD
// Then discard if there is no edge:
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
// Calculate right and bottom deltas:
float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgba, weights);
@@ -793,9 +800,11 @@ float2 SMAAColorEdgeDetectionPS(float2 texcoord,
// We do the usual threshold:
float2 edges = step(threshold, delta.xy);
+# ifndef SMAA_NO_DISCARD
// Then discard if there is no edge:
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
// Calculate right and bottom deltas:
float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb;
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index 6605e1165d4..3faefd485bf 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -60,11 +60,11 @@ vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos)
vec2 perp = vec2(-edge.y, edge.x);
float dist = dot(perp, frag_co - edge_start);
/* Add 0.1 to diffenrentiate with cleared pixels. */
- return vec4(perp * 0.5 + 0.5, dist * 0.25 + 0.5 + 0.1, 0.0);
+ return vec4(perp * 0.5 + 0.5, dist * 0.25 + 0.5 + 0.1, 1.0);
}
else {
/* Default line if the origin is perfectly aligned with a pixel. */
- return vec4(1.0, 0.0, 0.5 + 0.1, 0.0);
+ return vec4(1.0, 0.0, 0.5 + 0.1, 1.0);
}
}
@@ -89,7 +89,14 @@ uniform int baseInstance;
# define instanceId gl_InstanceID
# endif
-# define resource_id (baseInstance + instanceId)
+# ifdef UNIFORM_RESOURCE_ID
+/* This is in the case we want to do a special instance drawcall but still want to have the
+ * right resourceId and all the correct ubo datas. */
+uniform int resourceId;
+# define resource_id resourceId
+# else
+# define resource_id (baseInstance + instanceId)
+# endif
/* Use this to declare and pass the value if
* the fragment shader uses the resource_id. */
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index d1fd1ebd06f..ebde475a075 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -5105,10 +5105,16 @@ void ANIM_channel_draw_widgets(const bContext *C,
/* Mask Layer. */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- prop = RNA_struct_find_property(&ptr, "mask_layer");
+ prop = RNA_struct_find_property(&ptr, "use_mask_layer");
gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop);
if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) {
- icon = (gpl->flag & GP_LAYER_USE_MASK) ? ICON_MOD_MASK : ICON_LAYER_ACTIVE;
+ icon = ICON_LAYER_ACTIVE;
+ if (gpl->flag & GP_LAYER_USE_MASK) {
+ icon = ICON_MOD_MASK;
+ }
+ else {
+ icon = ICON_LAYER_ACTIVE;
+ }
uiDefAutoButR(block,
&ptr,
prop,
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 20f565990e9..8b5e22db61a 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -3135,7 +3135,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
if (gpl->flag & GP_LAYER_SELECT) {
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
/* update other layer status */
- BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_active_set(gpd, gpl);
BKE_gpencil_layer_autolock_set(gpd, false);
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
}
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 0b286b4ee2b..1f421d23b27 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -299,7 +299,7 @@ void ED_armature_bone_rename(Main *bmain,
if (ob->type == OB_GPENCIL) {
bGPdata *gpd = (bGPdata *)ob->data;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if ((gpl->parent != NULL) && (gpl->parent->data == arm)) {
if (STREQ(gpl->parsubstr, oldname)) {
BLI_strncpy(gpl->parsubstr, newname, MAXBONENAME);
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 21f1801f7eb..512e1ec6270 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -43,7 +43,6 @@ set(SRC
gpencil_add_monkey.c
gpencil_add_stroke.c
gpencil_armature.c
- gpencil_brush.c
gpencil_convert.c
gpencil_data.c
gpencil_edit.c
@@ -54,9 +53,14 @@ set(SRC
gpencil_ops_versioning.c
gpencil_paint.c
gpencil_primitive.c
+ gpencil_sculpt_paint.c
gpencil_select.c
gpencil_undo.c
gpencil_utils.c
+ gpencil_uv.c
+ gpencil_vertex_paint.c
+ gpencil_vertex_ops.c
+ gpencil_weight_paint.c
gpencil_intern.h
)
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 1a30555a584..ef9b6d2943b 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -33,6 +33,7 @@
#include "BLI_sys_types.h"
#include "BLI_math.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLF_api.h"
@@ -562,7 +563,7 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
{
GPU_program_point_size(true);
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* check if stroke can be drawn */
if (annotation_can_draw_stroke(gps, dflag) == false) {
continue;
@@ -625,7 +626,7 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
}
/* Draw selected verts for strokes being edited */
-static void annotation_draw_strokes_edit(bGPdata *gpd,
+static void annotation_draw_strokes_edit(bGPdata *UNUSED(gpd),
bGPDlayer *gpl,
const bGPDframe *gpf,
int offsx,
@@ -660,7 +661,7 @@ static void annotation_draw_strokes_edit(bGPdata *gpd,
GPU_program_point_size(true);
/* draw stroke verts */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* check if stroke can be drawn */
if (annotation_can_draw_stroke(gps, dflag) == false) {
continue;
@@ -689,6 +690,9 @@ static void annotation_draw_strokes_edit(bGPdata *gpd,
vsize = bsize + 2;
}
+ /* Why? */
+ UNUSED_VARS(vsize);
+
float selectColor[4];
UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
selectColor[3] = alpha;
@@ -709,31 +713,12 @@ static void annotation_draw_strokes_edit(bGPdata *gpd,
immBegin(GPU_PRIM_POINTS, gps->totpoints);
- /* Draw start and end point differently if enabled stroke direction hint */
- bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
-
/* Draw all the stroke points (selected or not) */
bGPDspoint *pt = gps->points;
for (int i = 0; i < gps->totpoints; i++, pt++) {
/* size and color first */
- if (show_direction_hint && i == 0) {
- /* start point in green bigger */
- immAttr3f(color, 0.0f, 1.0f, 0.0f);
- immAttr1f(size, vsize + 4);
- }
- else if (show_direction_hint && (i == gps->totpoints - 1)) {
- /* end point in red smaller */
- immAttr3f(color, 1.0f, 0.0f, 0.0f);
- immAttr1f(size, vsize + 1);
- }
- else if (pt->flag & GP_SPOINT_SELECT) {
- immAttr3fv(color, selectColor);
- immAttr1f(size, vsize);
- }
- else {
- immAttr3fv(color, gpl->color);
- immAttr1f(size, bsize);
- }
+ immAttr3fv(color, gpl->color);
+ immAttr1f(size, bsize);
/* then position */
if (gps->flag & GP_STROKE_3DSPACE) {
@@ -857,7 +842,7 @@ static void annotation_draw_data_layers(
{
float ink[4];
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* verify never thickness is less than 1 */
CLAMP_MIN(gpl->thickness, 1.0f);
short lthick = gpl->thickness;
@@ -872,7 +857,7 @@ static void annotation_draw_data_layers(
}
/* get frame to draw */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, cfra, GP_GETFRAME_USE_PREV);
if (gpf == NULL) {
continue;
}
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index fe163e5b6e5..3e33f811225 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -537,9 +537,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
pts->pressure = pt->pressure;
pts->strength = pt->strength;
pts->time = pt->time;
-
- /* force fill recalc */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
}
/* increment counters */
@@ -604,14 +602,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* copy appropriate settings for stroke */
gps->totpoints = totelem;
gps->thickness = gpl->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->flag = gpd->runtime.sbuffer_sflag;
gps->inittime = p->inittime;
-
- /* enable recalculation flag by default (only used if hq fill) */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
/* allocate enough memory for a continuous array for storage points */
gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
@@ -1207,7 +1204,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
ToolSettings *ts = scene->toolsettings;
/* get active layer (or add a new one if non-existent) */
- p->gpl = BKE_gpencil_layer_getactive(p->gpd);
+ p->gpl = BKE_gpencil_layer_active_get(p->gpd);
if (p->gpl == NULL) {
/* tag for annotations */
p->gpd->flag |= GP_DATA_ANNOTATIONS;
@@ -1235,7 +1232,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
*/
bool has_layer_to_erase = false;
- if (gpencil_layer_is_editable(p->gpl)) {
+ if (BKE_gpencil_layer_is_editable(p->gpl)) {
/* Ensure that there's stuff to erase here (not including selection mask below)... */
if (p->gpl->actframe && p->gpl->actframe->strokes.first) {
has_layer_to_erase = true;
@@ -1263,7 +1260,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 4d879306cec..db13f57b192 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -233,128 +233,8 @@ static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points,
}
/* --------------- Stroke Fills ----------------- */
-/* calc bounding box in 2d using flat projection data */
-static void gp_calc_2d_bounding_box(
- const float (*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand)
-{
- copy_v2_v2(minv, points2d[0]);
- copy_v2_v2(maxv, points2d[0]);
-
- 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];
- }
- }
- /* If not expanded, use a perfect square */
- if (expand == false) {
- if (maxv[0] > maxv[1]) {
- maxv[1] = maxv[0];
- }
- else {
- maxv[0] = maxv[1];
- }
- }
-}
-
-/* calc texture coordinates using flat projected points */
-static void gp_calc_stroke_text_coordinates(const float (*points2d)[2],
- int totpoints,
- const float minv[2],
- float maxv[2],
- float (*r_uv)[2])
-{
- float d[2];
- d[0] = maxv[0] - minv[0];
- d[1] = maxv[1] - minv[1];
- for (int i = 0; i < totpoints; i++) {
- r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
- r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
- }
-}
-
-/* Triangulate stroke for high quality fill
- * (this is done only if cache is null or stroke was modified). */
-static void gp_triangulate_stroke_fill(bGPDstroke *gps)
-{
- BLI_assert(gps->totpoints >= 3);
-
- /* allocate memory for temporary areas */
- gps->tot_triangles = gps->totpoints - 2;
- uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles,
- "GP Stroke temp triangulation");
- float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
- "GP Stroke temp 2d points");
- float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
-
- int direction = 0;
-
- /* convert to 2d and triangulate */
- BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
- BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
-
- /* calc texture coordinates automatically */
- float minv[2];
- float maxv[2];
- /* first needs bounding box data */
- gp_calc_2d_bounding_box((const float(*)[2])points2d, gps->totpoints, minv, maxv, false);
- /* calc uv data */
- gp_calc_stroke_text_coordinates((const float(*)[2])points2d, gps->totpoints, minv, maxv, uv);
-
- /* Number of triangles */
- gps->tot_triangles = gps->totpoints - 2;
- /* save triangulation data in stroke cache */
- 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);
- }
-
- for (int i = 0; i < gps->tot_triangles; i++) {
- bGPDtriangle *stroke_triangle = &gps->triangles[i];
- memcpy(stroke_triangle->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]]);
- }
- }
- else {
- /* No triangles needed - Free anything allocated previously */
- if (gps->triangles) {
- MEM_freeN(gps->triangles);
- }
-
- 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);
-}
-
/* add a new fill point and texture coordinates to vertex buffer */
static void gp_add_filldata_tobuffer(const bGPDspoint *pt,
- const float uv[2],
uint pos,
uint texcoord,
short flag,
@@ -375,48 +255,10 @@ static void gp_add_filldata_tobuffer(const bGPDspoint *pt,
fpt[2] = 0.0f; /* 2d always is z=0.0f */
}
- immAttr2f(texcoord, uv[0], uv[1]); /* texture coordinates */
- immVertex3fv(pos, fpt); /* position */
+ immAttr2f(texcoord, pt->uv_fill[0], pt->uv_fill[1]); /* texture coordinates */
+ immVertex3fv(pos, fpt); /* position */
}
-#if 0 /* GPXX disabled, not used in annotations */
-/* assign image texture for filling stroke */
-static int gp_set_filling_texture(Image *image, short flag)
-{
- ImBuf *ibuf;
- uint *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
- int error = GL_NO_ERROR;
- ImageUser iuser = {NULL};
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- return (int)GL_INVALID_OPERATION;
- }
-
- GPU_create_gl_tex(
- bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D, false, false, image);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- if (flag & GP_STYLE_COLOR_TEX_CLAMP) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- }
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
- BKE_image_release_ibuf(image, ibuf, NULL);
-
- return error;
-}
-#endif
-
/* draw fills for shapes */
static void gp_draw_stroke_fill(bGPdata *gpd,
bGPDstroke *gps,
@@ -428,18 +270,12 @@ static void gp_draw_stroke_fill(bGPdata *gpd,
const float color[4])
{
BLI_assert(gps->totpoints >= 3);
+ BLI_assert(gps->tot_triangles >= 1);
const bool use_mat = (gpd->mat != NULL);
Material *ma = (use_mat) ? gpd->mat[gps->mat_nr] : BKE_material_default_gpencil();
MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
- /* Calculate triangles cache for filling area (must be done only after changes) */
- if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (gps->tot_triangles == 0) ||
- (gps->triangles == NULL)) {
- gp_triangulate_stroke_fill(gps);
- }
- BLI_assert(gps->tot_triangles >= 1);
-
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -450,25 +286,13 @@ static void gp_draw_stroke_fill(bGPdata *gpd,
immUniform1i("fill_type", gp_style->fill_style);
immUniform1f("mix_factor", gp_style->mix_factor);
- immUniform1f("gradient_angle", gp_style->gradient_angle);
- immUniform1f("gradient_radius", gp_style->gradient_radius);
- immUniform1f("pattern_gridsize", gp_style->pattern_gridsize);
- immUniform2fv("gradient_scale", gp_style->gradient_scale);
- immUniform2fv("gradient_shift", gp_style->gradient_shift);
-
immUniform1f("texture_angle", gp_style->texture_angle);
immUniform2fv("texture_scale", gp_style->texture_scale);
immUniform2fv("texture_offset", gp_style->texture_offset);
immUniform1f("texture_opacity", gp_style->texture_opacity);
- immUniform1i("t_mix", (gp_style->flag & GP_STYLE_FILL_TEX_MIX) != 0);
- immUniform1i("t_flip", (gp_style->flag & GP_STYLE_COLOR_FLIP_FILL) != 0);
-#if 0 /* GPXX disabled, not used in annotations */
- /* image texture */
- if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_TEXTURE) ||
- (gp_style->flag & GP_STYLE_COLOR_TEX_MIX)) {
- gp_set_filling_texture(gp_style->ima, gp_style->flag);
- }
-#endif
+ immUniform1i("t_mix", (gp_style->flag & GP_MATERIAL_FILL_TEX_MIX) != 0);
+ immUniform1i("t_flip", (gp_style->flag & GP_MATERIAL_FLIP_FILL) != 0);
+
/* Draw all triangles for filling the polygon (cache must be calculated before) */
immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3);
/* TODO: use batch instead of immediate mode, to share vertices */
@@ -477,7 +301,6 @@ static void gp_draw_stroke_fill(bGPdata *gpd,
for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
for (int j = 0; j < 3; j++) {
gp_add_filldata_tobuffer(&gps->points[stroke_triangle->verts[j]],
- stroke_triangle->uv[j],
pos,
texcoord,
gps->flag,
@@ -887,15 +710,15 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
Material *ma = (use_mat) ? tgpw->gpd->mat[gps->mat_nr] : BKE_material_default_gpencil();
MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
- if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
+ if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE) ||
/* if onion and ghost flag do not draw*/
- (tgpw->onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) {
+ (tgpw->onion && (gp_style->flag & GP_MATERIAL_ONIONSKIN))) {
continue;
}
/* if disable fill, the colors with fill must be omitted too except fill boundary strokes */
if ((tgpw->disable_fill == 1) && (gp_style->fill_rgba[3] > 0.0f) &&
- ((gps->flag & GP_STROKE_NOFILL) == 0) && (gp_style->flag & GP_STYLE_FILL_SHOW)) {
+ ((gps->flag & GP_STROKE_NOFILL) == 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW)) {
continue;
}
@@ -980,7 +803,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
}
}
- if (gp_style->mode == GP_STYLE_MODE_DOTS) {
+ if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
/* volumetric stroke drawing */
if (tgpw->disable_fill != 1) {
gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink);
@@ -1061,7 +884,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
copy_v4_v4(ink, tcolor);
}
}
- if (gp_style->mode == GP_STYLE_MODE_DOTS) {
+ if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
/* blob/disk-based "volumetric" drawing */
gp_draw_stroke_volumetric_2d(gps->points,
gps->totpoints,
@@ -1116,113 +939,8 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
/* ----- General Drawing ------ */
-/* draw interpolate strokes (used only while operator is running) */
-void ED_gp_draw_interpolation(const bContext *C, tGPDinterpolate *tgpi, const int type)
-{
- tGPDdraw tgpw;
- ARegion *region = CTX_wm_region(C);
- RegionView3D *rv3d = region->regiondata;
- tGPDinterpolate_layer *tgpil;
- Object *obact = CTX_data_active_object(C);
- /* Drawing code is expected to run with fully evaluated depsgraph. */
- Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C);
-
- float color[4];
-
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
- color[3] = 0.6f;
- int dflag = 0;
- /* if 3d stuff, enable flags */
- if (type == REGION_DRAW_POST_VIEW) {
- dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
- }
-
- tgpw.rv3d = rv3d;
- tgpw.depsgraph = depsgraph;
- tgpw.ob = obact;
- tgpw.gpd = tgpi->gpd;
- tgpw.offsx = 0;
- tgpw.offsy = 0;
- tgpw.winx = tgpi->region->winx;
- tgpw.winy = tgpi->region->winy;
- tgpw.dflag = dflag;
-
- /* turn on alpha-blending */
- GPU_blend(true);
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- /* calculate parent position */
- ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpil->gpl, tgpw.diff_mat);
- if (tgpil->interFrame) {
- tgpw.gpl = tgpil->gpl;
- tgpw.gpf = tgpil->interFrame;
- tgpw.t_gpf = tgpil->interFrame;
- tgpw.gps = NULL;
-
- tgpw.lthick = tgpil->gpl->line_change;
- tgpw.opacity = 1.0;
- copy_v4_v4(tgpw.tintcolor, color);
- tgpw.onion = true;
- tgpw.custonion = true;
- if (obact->totcol == 0) {
- tgpw.gpd->mat = NULL;
- }
-
- gp_draw_strokes(&tgpw);
- }
- }
- GPU_blend(false);
-}
-
/* wrapper to draw strokes for filling operator */
void ED_gp_draw_fill(tGPDdraw *tgpw)
{
gp_draw_strokes(tgpw);
}
-
-/* draw a short status message in the top-right corner */
-static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *region)
-{
-
- /* Cannot draw any status text when drawing OpenGL Renders */
- if (G.f & G_FLAG_RENDER_VIEWPORT) {
- return;
- }
-
- /* Get bounds of region - Necessary to avoid problems with region overlap. */
- const rcti *rect = ED_region_visible_rect(region);
-
- /* for now, this should only be used to indicate when we are in stroke editmode */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- const char *printable = IFACE_("GPencil Stroke Editing");
- float printable_size[2];
-
- int font_id = BLF_default();
-
- BLF_width_and_height(
- font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
-
- int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect->ymax - U.widget_unit);
-
- /* text label */
- UI_FontThemeColor(font_id, TH_TEXT_HI);
-#ifdef WITH_INTERNATIONAL
- BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#else
- BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#endif
-
- /* grease pencil icon... */
- // XXX: is this too intrusive?
- GPU_blend_set_func_separate(
- GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- GPU_blend(true);
-
- xco -= U.widget_unit;
- yco -= (int)printable_size[1] / 2;
-
- UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
-
- GPU_blend(false);
- }
-}
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index f4636e81966..86355787b3c 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -58,15 +58,13 @@
/* Loops over the gp-frames for a gp-layer, and applies the given callback */
bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *))
{
- bGPDframe *gpf;
-
/* error checker */
if (gpl == NULL) {
return false;
}
/* do loop */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* execute callback */
if (gpf_cb(gpf, scene)) {
return true;
@@ -83,7 +81,6 @@ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPD
/* make a listing all the gp-frames in a layer as cfraelems */
void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
{
- bGPDframe *gpf;
CfraElem *ce;
/* error checking */
@@ -92,7 +89,7 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
}
/* loop through gp-frames, adding */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
ce = MEM_callocN(sizeof(CfraElem), "CfraElem");
@@ -110,15 +107,13 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
/* check if one of the frames in this layer is selected */
bool ED_gplayer_frame_select_check(bGPDlayer *gpl)
{
- bGPDframe *gpf;
-
/* error checking */
if (gpl == NULL) {
return false;
}
/* stop at the first one found */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
if (gpf->flag & GP_FRAME_SELECT) {
return true;
}
@@ -151,15 +146,13 @@ static void gpframe_select(bGPDframe *gpf, short select_mode)
/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
{
- bGPDframe *gpf;
-
/* error checking */
if (gpl == NULL) {
return;
}
/* handle according to mode */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
gpframe_select(gpf, select_mode);
}
}
@@ -185,7 +178,7 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
return;
}
- gpf = BKE_gpencil_layer_find_frame(gpl, selx);
+ gpf = BKE_gpencil_layer_frame_find(gpl, selx);
if (gpf) {
gpframe_select(gpf, select_mode);
@@ -195,14 +188,12 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
/* select the frames in this layer that occur within the bounds specified */
void ED_gplayer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
{
- bGPDframe *gpf;
-
if (gpl == NULL) {
return;
}
/* only select those frames which are in bounds */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
if (IN_RANGE(gpf->framenum, min, max)) {
gpframe_select(gpf, select_mode);
}
@@ -215,14 +206,12 @@ void ED_gplayer_frames_select_region(KeyframeEditData *ked,
short tool,
short select_mode)
{
- bGPDframe *gpf;
-
if (gpl == NULL) {
return;
}
/* only select frames which are within the region */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* construct a dummy point coordinate to do this testing with */
float pt[2] = {0};
@@ -251,7 +240,6 @@ void ED_gplayer_frames_select_region(KeyframeEditData *ked,
/* Delete selected frames */
bool ED_gplayer_frames_delete(bGPDlayer *gpl)
{
- bGPDframe *gpf, *gpfn;
bool changed = false;
/* error checking */
@@ -260,11 +248,9 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl)
}
/* check for frames to delete */
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
-
+ LISTBASE_FOREACH_MUTABLE (bGPDframe *, gpf, &gpl->frames) {
if (gpf->flag & GP_FRAME_SELECT) {
- BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_frame_delete(gpl, gpf);
changed = true;
}
}
@@ -275,16 +261,13 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl)
/* Duplicate selected frames from given gp-layer */
void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
{
- bGPDframe *gpf, *gpfn;
-
/* error checking */
if (gpl == NULL) {
return;
}
/* duplicate selected frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
- gpfn = gpf->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDframe *, gpf, &gpl->frames) {
/* duplicate this frame */
if (gpf->flag & GP_FRAME_SELECT) {
@@ -304,13 +287,11 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
*/
void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
{
- bGPDframe *gpf;
-
if (gpl == NULL) {
return;
}
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
if (gpf->flag & GP_FRAME_SELECT) {
gpf->key_type = type;
}
@@ -370,10 +351,9 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
for (ale = anim_data.first; ale; ale = ale->next) {
ListBase copied_frames = {NULL, NULL};
bGPDlayer *gpl = (bGPDlayer *)ale->data;
- bGPDframe *gpf;
/* loop over frames, and copy only selected frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* if frame is selected, make duplicate it and its strokes */
if (gpf->flag & GP_FRAME_SELECT) {
/* make a copy of this frame */
@@ -489,7 +469,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
gpfs->framenum += offset;
/* get frame to copy data into (if no frame returned, then just ignore) */
- gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
+ gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
if (gpf) {
bGPDstroke *gps, *gpsn;
@@ -502,21 +482,15 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
*/
for (gps = gpfs->strokes.first; gps; gps = gps->next) {
/* make a copy of stroke, then of its points array */
- gpsn = MEM_dupallocN(gps);
- gpsn->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- gpsn->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, gpsn);
- }
- /* duplicate triangle information */
- gpsn->triangles = MEM_dupallocN(gps->triangles);
+ gpsn = BKE_gpencil_stroke_duplicate(gps, true);
+
/* append stroke to frame */
BLI_addtail(&gpf->strokes, gpsn);
}
/* if no strokes (i.e. new frame) added, free gpf */
if (BLI_listbase_is_empty(&gpf->strokes)) {
- BKE_gpencil_layer_delframe(gpld, gpf);
+ BKE_gpencil_layer_frame_delete(gpld, gpf);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index 8b4620d233b..f08188c48ce 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -66,17 +66,20 @@ static int gpencil_monkey_color(
ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx);
copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba);
+
copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+ srgb_to_linearrgb_v4(ma->gp_style->fill_rgba, ma->gp_style->fill_rgba);
if (!stroke) {
- ma->gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
+ ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
}
if (!fill) {
- ma->gp_style->flag &= ~GP_STYLE_FILL_SHOW;
+ ma->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
}
else {
- ma->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ ma->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
}
return idx;
@@ -855,89 +858,117 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, CFRA);
/* generate strokes */
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin, 270, 75);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false);
BKE_gpencil_stroke_add_points(gps, data0, 270, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data1, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 60, false);
BKE_gpencil_stroke_add_points(gps, data2, 18, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false);
BKE_gpencil_stroke_add_points(gps, data3, 64, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data4, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false);
BKE_gpencil_stroke_add_points(gps, data5, 64, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data6, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 18, 40);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 18, 40, false);
BKE_gpencil_stroke_add_points(gps, data7, 18, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false);
BKE_gpencil_stroke_add_points(gps, data8, 49, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data9, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false);
BKE_gpencil_stroke_add_points(gps, data10, 49, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false);
BKE_gpencil_stroke_add_points(gps, data11, 18, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40);
+ gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false);
BKE_gpencil_stroke_add_points(gps, data12, 18, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data13, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data14, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 65, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 65, 60, false);
BKE_gpencil_stroke_add_points(gps, data15, 65, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 60, false);
BKE_gpencil_stroke_add_points(gps, data16, 34, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data17, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 40);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 40, false);
BKE_gpencil_stroke_add_points(gps, data18, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 40);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 40, false);
BKE_gpencil_stroke_add_points(gps, data19, 34, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data20, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 64, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 64, 60, false);
BKE_gpencil_stroke_add_points(gps, data21, 64, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false);
BKE_gpencil_stroke_add_points(gps, data22, 26, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false);
BKE_gpencil_stroke_add_points(gps, data23, 26, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data24, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false);
BKE_gpencil_stroke_add_points(gps, data25, 18, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false);
BKE_gpencil_stroke_add_points(gps, data26, 18, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
- gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60);
+ gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false);
BKE_gpencil_stroke_add_points(gps, data27, 33, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
/* update depsgraph */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index dfcf7f6e765..d4e17144ca2 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -65,10 +65,13 @@ static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct,
ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx);
copy_v4_v4(ma->gp_style->stroke_rgba, pct->line);
+ srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba);
+
copy_v4_v4(ma->gp_style->fill_rgba, pct->fill);
+ srgb_to_linearrgb_v4(ma->gp_style->fill_rgba, ma->gp_style->fill_rgba);
if (fill) {
- ma->gp_style->flag |= GP_STYLE_FILL_SHOW;
+ ma->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
}
return idx;
@@ -240,8 +243,9 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
UNUSED_VARS(frame_color);
/* generate stroke */
- gps = BKE_gpencil_add_stroke(frame_lines, color_black, 175, 75);
+ gps = BKE_gpencil_stroke_add(frame_lines, color_black, 175, 75, false);
BKE_gpencil_stroke_add_points(gps, data0, 175, mat);
+ BKE_gpencil_stroke_geometry_update(gps);
/* update depsgraph */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
index c0871fd32fc..02913a19523 100644
--- a/source/blender/editors/gpencil/gpencil_armature.c
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -357,7 +357,7 @@ static void gpencil_add_verts_to_dgroups(
}
/* loop all strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
bGPDspoint *pt = NULL;
@@ -368,7 +368,7 @@ static void gpencil_add_verts_to_dgroups(
continue;
}
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 255f17f13cc..934466475a5 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -152,7 +152,7 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C),
* - assumes that the active space is the 3D-View
*/
static void gp_strokepoint_convertcoords(bContext *C,
- bGPdata *gpd,
+ bGPdata *UNUSED(gpd),
bGPDlayer *gpl,
bGPDstroke *gps,
bGPDspoint *source_pt,
@@ -174,7 +174,7 @@ static void gp_strokepoint_convertcoords(bContext *C,
/* apply parent transform */
float fpt[3];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
copy_v3_v3(&pt->x, fpt);
@@ -1270,7 +1270,7 @@ static void gp_layer_to_curve(bContext *C,
Collection *collection = CTX_data_collection(C);
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
bGPDstroke *gps, *prev_gps = NULL;
Object *ob;
Curve *cu;
@@ -1410,7 +1410,7 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe
int i;
bool valid = true;
- if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV)) ||
+ if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) ||
!(gps = gpf->strokes.first)) {
return false;
}
@@ -1476,8 +1476,8 @@ static bool gp_convert_poll(bContext *C)
/* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
* and if we are not in edit mode!
*/
- return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_getactive(gpd)) &&
- (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV)) &&
+ return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
+ (gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) &&
(gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
}
@@ -1487,7 +1487,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)ob->data;
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
Scene *scene = CTX_data_scene(C);
const int mode = RNA_enum_get(op->ptr, "type");
const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
@@ -1751,4 +1751,92 @@ void GPENCIL_OT_convert(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ************************************************ */
+/* Generate Grease Pencil from Image. */
+static bool image_to_gpencil_poll(bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ if (sl->spacetype == SPACE_IMAGE) {
+ return true;
+ }
+
+ return false;
+}
+
+static int image_to_gpencil_exec(bContext *C, wmOperator *op)
+{
+ const float size = RNA_float_get(op->ptr, "size");
+ const bool is_mask = RNA_boolean_get(op->ptr, "mask");
+
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ bool done = false;
+
+ if (sima->image == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Create Object. */
+ const float *cur = scene->cursor.location;
+ ushort local_view_bits = 0;
+ Object *ob = ED_gpencil_add_object(C, cur, local_view_bits);
+ DEG_relations_tag_update(bmain); /* added object */
+
+ /* Create material slot. */
+ Material *ma = BKE_gpencil_object_material_new(bmain, ob, "Image Material", NULL);
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ gp_style->mode = GP_MATERIAL_MODE_SQUARE;
+
+ /* Add layer and frame. */
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true);
+ bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, CFRA);
+ done = BKE_gpencil_from_image(sima, gpf, size, is_mask);
+
+ if (done) {
+ /* Delete any selected point. */
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
+ }
+
+ BKE_reportf(op->reports, RPT_INFO, "Object created");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_image_to_grease_pencil(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Generate Grease Pencil Object using image as source";
+ ot->idname = "GPENCIL_OT_image_to_grease_pencil";
+ ot->description = "Generate a Grease Pencil Object using Image as source";
+
+ /* api callbacks */
+ ot->exec = image_to_gpencil_exec;
+ ot->poll = image_to_gpencil_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_float(ot->srna,
+ "size",
+ 0.005f,
+ 0.0001f,
+ 10.0f,
+ "Point Size",
+ "Size used for graese pencil points",
+ 0.001f,
+ 1.0f);
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna,
+ "mask",
+ false,
+ "Generate Mask",
+ "Create an inverted image for masking using alpha channel");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index a8c3fb02e11..9b33e999a25 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -292,7 +292,7 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
ED_annotation_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
/* sanity checks */
if (ELEM(NULL, gpd, gpl)) {
@@ -309,15 +309,18 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
* - if this is the only layer, this naturally becomes NULL
*/
if (gpl->prev) {
- BKE_gpencil_layer_setactive(gpd, gpl->prev);
+ BKE_gpencil_layer_active_set(gpd, gpl->prev);
}
else {
- BKE_gpencil_layer_setactive(gpd, gpl->next);
+ BKE_gpencil_layer_active_set(gpd, gpl->next);
}
/* delete the layer now... */
BKE_gpencil_layer_delete(gpd, gpl);
+ /* Reorder masking. */
+ BKE_gpencil_layer_mask_sort_all(gpd);
+
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -342,7 +345,7 @@ void GPENCIL_OT_layer_remove(wmOperatorType *ot)
static bool gp_active_layer_annotation_poll(bContext *C)
{
bGPdata *gpd = ED_annotation_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
return (gpl != NULL);
}
@@ -373,7 +376,7 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op)
bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
ED_annotation_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
const int direction = RNA_enum_get(op->ptr, "type") * -1;
@@ -384,6 +387,9 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op)
BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) {
+ /* Reorder masking. */
+ BKE_gpencil_layer_mask_sort_all(gpd);
+
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
@@ -441,7 +447,7 @@ void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot)
static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
bGPDlayer *new_layer;
/* sanity checks */
@@ -460,7 +466,7 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
'.',
offsetof(bGPDlayer, info),
sizeof(new_layer->info));
- BKE_gpencil_layer_setactive(gpd, new_layer);
+ BKE_gpencil_layer_active_set(gpd, new_layer);
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -499,7 +505,7 @@ static bool gp_layer_duplicate_object_poll(bContext *C)
}
bGPdata *gpd = (bGPdata *)ob->data;
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl == NULL) {
return false;
@@ -532,7 +538,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
Object *ob_src = CTX_data_active_object(C);
bGPdata *gpd_src = (bGPdata *)ob_src->data;
- bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
+ bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd_src);
/* Sanity checks. */
if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
@@ -568,7 +574,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
/* Make copy of source stroke. */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
/* Check if material is in destination object,
* otherwise add the slot with the material. */
@@ -630,21 +636,21 @@ enum {
static int gp_frame_duplicate_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
Scene *scene = CTX_data_scene(C);
int mode = RNA_enum_get(op->ptr, "mode");
/* sanity checks */
- if (ELEM(NULL, gpd, gpl)) {
+ if (ELEM(NULL, gpd, gpl_active)) {
return OPERATOR_CANCELLED;
}
if (mode == 0) {
- BKE_gpencil_frame_addcopy(gpl, CFRA);
+ BKE_gpencil_frame_addcopy(gpl_active, CFRA);
}
else {
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
BKE_gpencil_frame_addcopy(gpl, CFRA);
}
@@ -700,16 +706,13 @@ static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op)
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) {
- bGPDstroke *gps, *gpsn;
if (gpf == NULL) {
continue;
}
/* simply delete strokes which are no fill */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -778,8 +781,6 @@ static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- bGPDstroke *gps = NULL;
- bGPDstroke *gpsn = NULL;
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
@@ -788,9 +789,7 @@ static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
}
/* simply delete strokes which are no loose */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -861,7 +860,7 @@ void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
static int gp_hide_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *layer = BKE_gpencil_layer_active_get(gpd);
bool unselected = RNA_boolean_get(op->ptr, "unselected");
/* sanity checks */
@@ -870,10 +869,8 @@ static int gp_hide_exec(bContext *C, wmOperator *op)
}
if (unselected) {
- bGPDlayer *gpl;
-
/* hide unselected */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl != layer) {
gpl->flag |= GP_LAYER_HIDE;
}
@@ -946,7 +943,6 @@ static void gp_reveal_select_frame(bContext *C, bGPDframe *frame, bool select)
static int gp_reveal_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl;
const bool select = RNA_boolean_get(op->ptr, "select");
/* sanity checks */
@@ -954,8 +950,7 @@ static int gp_reveal_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
-
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl->flag & GP_LAYER_HIDE) {
gpl->flag &= ~GP_LAYER_HIDE;
@@ -1008,7 +1003,6 @@ void GPENCIL_OT_reveal(wmOperatorType *ot)
static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl;
/* sanity checks */
if (gpd == NULL) {
@@ -1016,7 +1010,7 @@ static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
}
/* make all layers non-editable */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
gpl->flag |= GP_LAYER_LOCKED;
}
@@ -1048,7 +1042,6 @@ void GPENCIL_OT_lock_all(wmOperatorType *ot)
static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl;
/* sanity checks */
if (gpd == NULL) {
@@ -1056,7 +1049,7 @@ static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
}
/* make all layers editable again */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
gpl->flag &= ~GP_LAYER_LOCKED;
}
@@ -1087,8 +1080,7 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot)
static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd);
- bGPDlayer *gpl;
+ bGPDlayer *layer = BKE_gpencil_layer_active_get(gpd);
int flags = GP_LAYER_LOCKED;
bool isolate = false;
@@ -1102,7 +1094,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
}
/* Test whether to isolate or clear all flags */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* Skip if this is the active layer */
if (gpl == layer) {
continue;
@@ -1121,7 +1113,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
/* TODO: Include onion-skinning on this list? */
if (isolate) {
/* Set flags on all "other" layers */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl == layer) {
continue;
}
@@ -1132,7 +1124,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
}
else {
/* Clear flags - Restore everything else */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
gpl->flag &= ~flags;
}
}
@@ -1172,7 +1164,7 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
static int gp_merge_layer_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl_next = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl_next = BKE_gpencil_layer_active_get(gpd);
bGPDlayer *gpl_current = gpl_next->prev;
if (ELEM(NULL, gpd, gpl_current, gpl_next)) {
@@ -1191,7 +1183,7 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
/* try to find frame in current layer */
bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum));
if (!frame) {
- bGPDframe *actframe = BKE_gpencil_layer_getframe(
+ bGPDframe *actframe = BKE_gpencil_layer_frame_get(
gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV);
frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum);
/* duplicate strokes of current active frame */
@@ -1203,10 +1195,29 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
BLI_movelisttolist(&frame->strokes, &gpf->strokes);
}
+ /* Add Masks to destination layer. */
+ LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_next->mask_layers) {
+ /* Don't add merged layers or missing layer names. */
+ if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_next->info) ||
+ STREQ(mask->name, gpl_current->info)) {
+ continue;
+ }
+ if (!BKE_gpencil_layer_mask_named_get(gpl_current, mask->name)) {
+ bGPDlayer_Mask *mask_new = MEM_dupallocN(mask);
+ BLI_addtail(&gpl_current->mask_layers, mask_new);
+ gpl_current->act_mask++;
+ }
+ }
+ /* Set destination layer as active. */
+ BKE_gpencil_layer_active_set(gpd, gpl_current);
+
/* Now delete next layer */
BKE_gpencil_layer_delete(gpd, gpl_next);
BLI_ghash_free(gh_frames_cur, NULL, NULL);
+ /* Reorder masking. */
+ BKE_gpencil_layer_mask_sort(gpd, gpl_current);
+
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -1268,7 +1279,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
}
/* Set active layer */
- BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_active_set(gpd, gpl);
/* updates */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -1297,6 +1308,49 @@ void GPENCIL_OT_layer_change(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
}
+static int gp_layer_active_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ int layer_num = RNA_int_get(op->ptr, "layer");
+
+ /* Try to get layer */
+ bGPDlayer *gpl = BLI_findlink(&gpd->layers, layer_num);
+
+ if (gpl == NULL) {
+ BKE_reportf(
+ op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Set active layer */
+ BKE_gpencil_layer_active_set(gpd, gpl);
+
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_active(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Active Layer";
+ ot->idname = "GPENCIL_OT_layer_active";
+ ot->description = "Active Grease Pencil layer";
+
+ /* callbacks */
+ ot->exec = gp_layer_active_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* GPencil layer to use. */
+ ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
/* ************************************************ */
/* ******************* Arrange Stroke Up/Down in drawing order ************************** */
@@ -1312,7 +1366,7 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl_act = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl_act = BKE_gpencil_layer_active_get(gpd);
/* sanity checks */
if (ELEM(NULL, gpd, gpl_act, gpl_act->actframe)) {
@@ -1469,7 +1523,7 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
}
}
/* try to find slot */
- int idx = BKE_gpencil_object_material_get_index(ob, ma);
+ int idx = BKE_gpencil_object_material_index_get(ob, ma);
if (idx < 0) {
return OPERATOR_CANCELLED;
}
@@ -1494,7 +1548,7 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
continue;
}
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* only if selected */
if (gps->flag & GP_STROKE_SELECT) {
/* skip strokes that are invalid for current view */
@@ -1562,15 +1616,15 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
for (short i = 0; i < *totcol; i++) {
Material *tmp_ma = BKE_object_material_get(ob, i + 1);
if (tmp_ma) {
- tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ tmp_ma->gp_style->flag |= GP_MATERIAL_LOCKED;
DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
/* loop all selected strokes and unlock any color */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
/* only if selected */
if (gps->flag & GP_STROKE_SELECT) {
@@ -1581,7 +1635,7 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
/* unlock color */
Material *tmp_ma = BKE_object_material_get(ob, gps->mat_nr + 1);
if (tmp_ma) {
- tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ tmp_ma->gp_style->flag &= ~GP_MATERIAL_LOCKED;
DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -1619,28 +1673,273 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* ************************************************ */
/* Drawing Brushes Operators */
-/* ******************* Brush create presets ************************** */
-static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
+/* ******************* Brush resets ************************** */
+static int gp_brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- BKE_brush_gpencil_presets(bmain, ts);
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ Brush *brush = NULL;
+
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL: {
+ Paint *paint = &ts->gp_paint->paint;
+ brush = paint->brush;
+ if (brush && brush->gpencil_settings) {
+ BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type);
+ }
+ break;
+ }
+ case CTX_MODE_SCULPT_GPENCIL: {
+ Paint *paint = &ts->gp_sculptpaint->paint;
+ brush = paint->brush;
+ if (brush && brush->gpencil_settings) {
+ BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type);
+ }
+ break;
+ }
+ case CTX_MODE_WEIGHT_GPENCIL: {
+ Paint *paint = &ts->gp_weightpaint->paint;
+ brush = paint->brush;
+ if (brush && brush->gpencil_settings) {
+ BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type);
+ }
+ break;
+ }
+ case CTX_MODE_VERTEX_GPENCIL: {
+ Paint *paint = &ts->gp_vertexpaint->paint;
+ brush = paint->brush;
+ if (brush && brush->gpencil_settings) {
+ BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type);
+ }
+ break;
+ }
+ default:
+ break;
+ }
/* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_brush_reset(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reset Brush";
+ ot->idname = "GPENCIL_OT_brush_reset";
+ ot->description = "Reset Brush to default parameters";
+
+ /* api callbacks */
+ ot->exec = gp_brush_reset_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static Brush *gp_brush_get_first_by_mode(Main *bmain,
+ Paint *UNUSED(paint),
+ const enum eContextObjectMode mode,
+ char tool)
+{
+ Brush *brush_next = NULL;
+ for (Brush *brush = bmain->brushes.first; brush; brush = brush_next) {
+ brush_next = brush->id.next;
+
+ if (brush->gpencil_settings == NULL) {
+ continue;
+ }
+
+ if ((mode == CTX_MODE_PAINT_GPENCIL) && (brush->gpencil_tool == tool)) {
+ return brush;
+ }
+
+ if ((mode == CTX_MODE_SCULPT_GPENCIL) && (brush->gpencil_sculpt_tool == tool)) {
+ return brush;
+ }
+
+ if ((mode == CTX_MODE_WEIGHT_GPENCIL) && (brush->gpencil_weight_tool == tool)) {
+ return brush;
+ }
+
+ if ((mode == CTX_MODE_VERTEX_GPENCIL) && (brush->gpencil_vertex_tool == tool)) {
+ return brush;
+ }
+ }
+
+ return NULL;
+}
+
+static void gp_brush_delete_mode_brushes(Main *bmain,
+ Paint *paint,
+ const enum eContextObjectMode mode)
+{
+ Brush *brush_active = paint->brush;
+ Brush *brush_next = NULL;
+ for (Brush *brush = bmain->brushes.first; brush; brush = brush_next) {
+ brush_next = brush->id.next;
+
+ if ((brush->gpencil_settings == NULL) && (brush->ob_mode != OB_MODE_PAINT_GPENCIL)) {
+ continue;
+ }
+
+ short preset = (brush->gpencil_settings) ? brush->gpencil_settings->preset_type :
+ GP_BRUSH_PRESET_UNKNOWN;
+
+ if (preset != GP_BRUSH_PRESET_UNKNOWN) {
+ /* Verify to delete only the brushes of the current mode. */
+ if (mode == CTX_MODE_PAINT_GPENCIL) {
+ if ((preset < GP_BRUSH_PRESET_AIRBRUSH) || (preset > GP_BRUSH_PRESET_TINT)) {
+ continue;
+ }
+ if ((brush_active) && (brush_active->gpencil_tool != brush->gpencil_tool)) {
+ continue;
+ }
+ }
+
+ if (mode == CTX_MODE_SCULPT_GPENCIL) {
+ if ((preset < GP_BRUSH_PRESET_SMOOTH_STROKE) || (preset > GP_BRUSH_PRESET_CLONE_STROKE)) {
+ continue;
+ }
+ if ((brush_active) && (brush_active->gpencil_sculpt_tool != brush->gpencil_sculpt_tool)) {
+ continue;
+ }
+ }
+
+ if (mode == CTX_MODE_WEIGHT_GPENCIL) {
+ if (preset != GP_BRUSH_PRESET_DRAW_WEIGHT) {
+ continue;
+ }
+ if ((brush_active) && (brush_active->gpencil_weight_tool != brush->gpencil_weight_tool)) {
+ continue;
+ }
+ }
+
+ if (mode == CTX_MODE_VERTEX_GPENCIL) {
+ if ((preset < GP_BRUSH_PRESET_VERTEX_DRAW) || (preset > GP_BRUSH_PRESET_VERTEX_REPLACE)) {
+ continue;
+ }
+ if ((brush_active) && (brush_active->gpencil_vertex_tool != brush->gpencil_vertex_tool)) {
+ continue;
+ }
+ }
+ }
+
+ /* Before delete, unpinn any material of the brush. */
+ if ((brush->gpencil_settings) && (brush->gpencil_settings->material != NULL)) {
+ brush->gpencil_settings->material = NULL;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
+ }
+
+ BKE_brush_delete(bmain, brush);
+ }
+}
+
+static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ Paint *paint = NULL;
+
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL: {
+ paint = &ts->gp_paint->paint;
+ break;
+ }
+ case CTX_MODE_SCULPT_GPENCIL: {
+ paint = &ts->gp_sculptpaint->paint;
+ break;
+ }
+ case CTX_MODE_WEIGHT_GPENCIL: {
+ paint = &ts->gp_weightpaint->paint;
+ break;
+ }
+ case CTX_MODE_VERTEX_GPENCIL: {
+ paint = &ts->gp_vertexpaint->paint;
+ break;
+ }
+ default:
+ break;
+ }
+
+ char tool = '0';
+ if (paint) {
+ Brush *brush_active = paint->brush;
+ if (brush_active) {
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL: {
+ tool = brush_active->gpencil_tool;
+ break;
+ }
+ case CTX_MODE_SCULPT_GPENCIL: {
+ tool = brush_active->gpencil_sculpt_tool;
+ break;
+ }
+ case CTX_MODE_WEIGHT_GPENCIL: {
+ tool = brush_active->gpencil_weight_tool;
+ break;
+ }
+ case CTX_MODE_VERTEX_GPENCIL: {
+ tool = brush_active->gpencil_vertex_tool;
+ break;
+ }
+ default: {
+ tool = brush_active->gpencil_tool;
+ break;
+ }
+ }
+ }
+
+ gp_brush_delete_mode_brushes(bmain, paint, mode);
+
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL: {
+ BKE_brush_gpencil_paint_presets(bmain, ts);
+ break;
+ }
+ case CTX_MODE_SCULPT_GPENCIL: {
+ BKE_brush_gpencil_sculpt_presets(bmain, ts);
+ break;
+ }
+ case CTX_MODE_WEIGHT_GPENCIL: {
+ BKE_brush_gpencil_weight_presets(bmain, ts);
+ break;
+ }
+ case CTX_MODE_VERTEX_GPENCIL: {
+ BKE_brush_gpencil_vertex_presets(bmain, ts);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ BKE_paint_toolslots_brush_validate(bmain, paint);
+
+ /* Set Again the first brush of the mode. */
+ Brush *deft_brush = gp_brush_get_first_by_mode(bmain, paint, mode, tool);
+ if (deft_brush) {
+ BKE_paint_brush_set(paint, deft_brush);
+ }
+ /* notifiers */
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, NULL);
+ }
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_brush_presets_create(wmOperatorType *ot)
+void GPENCIL_OT_brush_reset_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Create Preset Brushes";
- ot->idname = "GPENCIL_OT_brush_presets_create";
- ot->description = "Create a set of predefined Grease Pencil drawing brushes";
+ ot->name = "Reset All Brushes";
+ ot->idname = "GPENCIL_OT_brush_reset_all";
+ ot->description = "Delete all mode brushes and recreate a default set";
/* api callbacks */
- ot->exec = gp_brush_presets_create_exec;
+ ot->exec = gp_brush_reset_all_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2323,9 +2622,9 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
BKE_object_defgroup_unique_name(vgroup, ob_active);
BLI_addtail(&ob_active->defbase, vgroup);
/* update vertex groups in strokes in original data */
- for (bGPDlayer *gpl_src = gpd->layers.first; gpl_src; gpl_src = gpl_src->next) {
- for (bGPDframe *gpf = gpl_src->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_src->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
MDeformVert *dvert;
int i;
for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) {
@@ -2372,12 +2671,12 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
float inverse_diff_mat[4][4];
/* recalculate all stroke points */
- ED_gpencil_parent_location(depsgraph, ob_iter, gpd_src, gpl_src, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
Material *ma_src = NULL;
for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* Reassign material. Look old material and try to find in destination. */
ma_src = BKE_gpencil_material(ob_src, gps->mat_nr + 1);
@@ -2468,7 +2767,8 @@ static bool gpencil_active_color_poll(bContext *C)
return false;
}
-/* **************** Lock and hide any color non used in current layer ************************** */
+/* **************** Lock and hide any color non used in current layer **************************
+ */
static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -2491,16 +2791,16 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
ma = BKE_gpencil_material(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
- gp_style->flag |= GP_STYLE_COLOR_LOCKED;
- gp_style->flag |= GP_STYLE_COLOR_HIDE;
+ gp_style->flag |= GP_MATERIAL_LOCKED;
+ gp_style->flag |= GP_MATERIAL_HIDE;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
/* loop all selected strokes and unlock any color used in active layer */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) &&
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) &&
(gpl->flag & GP_LAYER_ACTIVE)) {
for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
/* skip strokes that are invalid for current view */
@@ -2514,8 +2814,8 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
gp_style = ma->gp_style;
/* unlock/unhide color if not unlocked before */
if (gp_style != NULL) {
- gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
- gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
+ gp_style->flag &= ~GP_MATERIAL_LOCKED;
+ gp_style->flag &= ~GP_MATERIAL_HIDE;
}
}
}
@@ -2555,11 +2855,11 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
MaterialGPencilStyle *active_color = BKE_gpencil_material_settings(ob, ob->actcol);
MaterialGPencilStyle *gp_style;
- int flags = GP_STYLE_COLOR_LOCKED;
+ int flags = GP_MATERIAL_LOCKED;
bool isolate = false;
if (RNA_boolean_get(op->ptr, "affect_visibility")) {
- flags |= GP_STYLE_COLOR_HIDE;
+ flags |= GP_MATERIAL_HIDE;
}
if (ELEM(NULL, gpd, active_color)) {
@@ -2677,7 +2977,7 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
if (ma) {
color = ma->gp_style;
if (active_color != color) {
- color->flag |= GP_STYLE_COLOR_HIDE;
+ color->flag |= GP_MATERIAL_HIDE;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -2685,7 +2985,7 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
}
else {
/* hide selected/active */
- active_color->flag |= GP_STYLE_COLOR_HIDE;
+ active_color->flag |= GP_MATERIAL_HIDE;
}
/* updates */
@@ -2739,7 +3039,7 @@ static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
ma = BKE_gpencil_material(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
- gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
+ gp_style->flag &= ~GP_MATERIAL_HIDE;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -2792,7 +3092,7 @@ static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
ma = BKE_gpencil_material(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
- gp_style->flag |= GP_STYLE_COLOR_LOCKED;
+ gp_style->flag |= GP_MATERIAL_LOCKED;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -2845,7 +3145,7 @@ static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
ma = BKE_gpencil_material(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
- gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
+ gp_style->flag &= ~GP_MATERIAL_LOCKED;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -2900,7 +3200,7 @@ static int gpencil_color_select_exec(bContext *C, wmOperator *op)
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
/* verify something to do */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -3057,3 +3357,118 @@ bool ED_gpencil_add_lattice_modifier(const bContext *C,
return true;
}
+
+/* Masking operators */
+static int gp_layer_mask_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
+ if (gpl_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ char name[128];
+ RNA_string_get(op->ptr, "name", name);
+ bGPDlayer *gpl = BKE_gpencil_layer_named_get(gpd, name);
+
+ if (gpl == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to find layer to add");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (gpl == gpl_active) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot add active layer as mask");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (BKE_gpencil_layer_mask_named_get(gpl_active, name)) {
+ BKE_report(op->reports, RPT_ERROR, "Layer already added");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (gpl_active->act_mask == 256) {
+ BKE_report(op->reports, RPT_ERROR, "Maximum number of masking layers reached");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_gpencil_layer_mask_add(gpl_active, name);
+
+ /* Reorder masking. */
+ BKE_gpencil_layer_mask_sort(gpd, gpl_active);
+
+ /* notifiers */
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id,
+ ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ }
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_mask_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Mask Layer";
+ ot->idname = "GPENCIL_OT_layer_mask_add";
+ ot->description = "Add new layer as masking";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_mask_add_exec;
+ ot->poll = gp_add_poll;
+
+ /* properties */
+ RNA_def_string(ot->srna, "name", NULL, 128, "Layer", "Name of the layer");
+}
+
+static int gp_layer_mask_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ if (gpl == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ if (gpl->act_mask > 0) {
+ bGPDlayer_Mask *mask = BLI_findlink(&gpl->mask_layers, gpl->act_mask - 1);
+ if (mask != NULL) {
+ BKE_gpencil_layer_mask_remove(gpl, mask);
+ if ((gpl->mask_layers.first != NULL) && (gpl->act_mask == 0)) {
+ gpl->act_mask = 1;
+ }
+ }
+ }
+
+ /* Reorder masking. */
+ BKE_gpencil_layer_mask_sort(gpd, gpl);
+
+ /* notifiers */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_mask_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Mask Layer";
+ ot->idname = "GPENCIL_OT_layer_mask_remove";
+ ot->description = "Remove Layer Mask";
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* callbacks */
+ ot->exec = gp_layer_mask_remove_exec;
+ ot->poll = gp_active_layer_poll;
+}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index e5caeb93c73..f8ad34e8d14 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -355,7 +355,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts);
}
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
}
@@ -414,6 +414,9 @@ static bool gpencil_sculptmode_toggle_poll(bContext *C)
static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
const bool back = RNA_boolean_get(op->ptr, "back");
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
@@ -450,6 +453,12 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
ob->mode = mode;
}
+ if (mode == OB_MODE_SCULPT_GPENCIL) {
+ /* be sure we have brushes */
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_sculptpaint);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->gp_sculptpaint->paint);
+ }
+
/* setup other modes */
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
@@ -504,6 +513,9 @@ static bool gpencil_weightmode_toggle_poll(bContext *C)
static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
const bool back = RNA_boolean_get(op->ptr, "back");
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
@@ -540,6 +552,12 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
ob->mode = mode;
}
+ if (mode == OB_MODE_WEIGHT_GPENCIL) {
+ /* be sure we have brushes */
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_weightpaint);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->gp_weightpaint->paint);
+ }
+
/* setup other modes */
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
@@ -580,6 +598,104 @@ void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/* Vertex Paint Mode Management */
+
+static bool gpencil_vertexmode_toggle_poll(bContext *C)
+{
+ /* if using gpencil object, use this gpd */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return ob->data != NULL;
+ }
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op)
+{
+ const bool back = RNA_boolean_get(op->ptr, "back");
+
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ bool is_object = false;
+ short mode;
+ /* if using a gpencil object, use this datablock */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ gpd = ob->data;
+ is_object = true;
+ }
+
+ if (gpd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Just toggle paintmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_VERTEXMODE;
+ /* set mode */
+ if (gpd->flag & GP_DATA_STROKE_VERTEXMODE) {
+ mode = OB_MODE_VERTEX_GPENCIL;
+ }
+ else {
+ mode = OB_MODE_OBJECT;
+ }
+
+ if (is_object) {
+ /* try to back previous mode */
+ if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_VERTEXMODE) == 0) && (back == 1)) {
+ mode = ob->restore_mode;
+ }
+ ob->restore_mode = ob->mode;
+ ob->mode = mode;
+ }
+
+ if (mode == OB_MODE_VERTEX_GPENCIL) {
+ /* be sure we have brushes */
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->gp_vertexpaint->paint);
+ }
+
+ /* setup other modes */
+ ED_gpencil_setup_modes(C, gpd, mode);
+ /* set cache as dirty */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ if (is_object) {
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ }
+ if (G.background == false) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_vertexmode_toggle(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Strokes Vertex Mode Toggle";
+ ot->idname = "GPENCIL_OT_vertexmode_toggle";
+ ot->description = "Enter/Exit vertex paint mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_vertexmode_toggle_exec;
+ ot->poll = gpencil_vertexmode_toggle_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ prop = RNA_def_boolean(
+ ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
/* ************************************************ */
/* Stroke Editing Operators */
@@ -659,23 +775,17 @@ static void gp_duplicate_points(const bGPDstroke *gps,
else if (i == gps->totpoints - 1) {
len = i - start_idx + 1;
}
- // printf("copying from %d to %d = %d\n", start_idx, i, len);
/* make copies of the relevant data */
if (len) {
bGPDstroke *gpsd;
/* make a stupid copy first of the entire stroke (to get the flags too) */
- gpsd = MEM_dupallocN(gps);
+ gpsd = BKE_gpencil_stroke_duplicate((bGPDstroke *)gps, false);
/* saves original layer name */
BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo));
- /* initialize triangle memory - will be calculated on next redraw */
- gpsd->triangles = NULL;
- gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
- gpsd->tot_triangles = 0;
-
/* now, make a new points array, and copy of the relevant parts */
gpsd->points = MEM_mallocN(sizeof(bGPDspoint) * len, "gps stroke points copy");
memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
@@ -695,8 +805,11 @@ static void gp_duplicate_points(const bGPDstroke *gps,
}
}
+ BKE_gpencil_stroke_geometry_update(gpsd);
+
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
+
BLI_addtail(new_strokes, gpsd);
/* cleanup + reset for next */
@@ -746,17 +859,12 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
bGPDstroke *gpsd;
/* make direct copies of the stroke and its points */
- gpsd = MEM_dupallocN(gps);
+ gpsd = BKE_gpencil_stroke_duplicate(gps, true);
+
BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
- gpsd->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- gpsd->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
- }
- /* triangle information - will be calculated on next redraw */
- gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
- gpsd->triangles = NULL;
+ /* Initialize triangle information. */
+ BKE_gpencil_stroke_geometry_update(gpsd);
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
@@ -827,6 +935,7 @@ static void copy_move_point(bGPDstroke *gps,
pt_final->flag = pt->flag;
pt_final->uv_fac = pt->uv_fac;
pt_final->uv_rot = pt->uv_rot;
+ copy_v4_v4(pt_final->vert_color, pt->vert_color);
if (gps->dvert != NULL) {
MDeformVert *dvert = &temp_dverts[from_idx];
@@ -864,7 +973,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
pt = &gps->points[i];
if (pt->flag == GP_SPOINT_SELECT) {
/* duplicate original stroke data */
- bGPDstroke *gps_new = MEM_dupallocN(gps);
+ bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, false);
gps_new->prev = gps_new->next = NULL;
/* add new points array */
@@ -876,14 +985,15 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
gps_new->dvert = MEM_callocN(sizeof(MDeformVert), __func__);
}
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps_new->triangles = NULL;
- gps_new->tot_triangles = 0;
BLI_insertlinkafter(&gpf->strokes, gps, gps_new);
/* copy selected point data to new stroke */
copy_move_point(gps_new, gps->points, gps->dvert, i, 0, true);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ BKE_gpencil_stroke_geometry_update(gps_new);
+
/* deselect orinal point */
pt->flag &= ~GP_SPOINT_SELECT;
}
@@ -926,7 +1036,6 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
copy_move_point(gps, temp_points, temp_dverts, i, i2, false);
i2++;
}
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
/* If first point, add new point at the beginning. */
if (do_first) {
@@ -951,6 +1060,9 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps)
pt->flag |= GP_SPOINT_SELECT;
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+
MEM_SAFE_FREE(temp_points);
MEM_SAFE_FREE(temp_dverts);
}
@@ -1190,7 +1302,8 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
bGPDstroke *gpsd;
/* make direct copies of the stroke and its points */
- gpsd = MEM_dupallocN(gps);
+ gpsd = BKE_gpencil_stroke_duplicate(gps, false);
+
/* saves original layer name */
BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo));
gpsd->points = MEM_dupallocN(gps->points);
@@ -1199,10 +1312,8 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
BKE_gpencil_stroke_weights_duplicate(gps, gpsd);
}
- /* triangles cache - will be recalculated on next redraw */
- gpsd->flag |= GP_STROKE_RECALC_GEOMETRY;
- gpsd->tot_triangles = 0;
- gpsd->triangles = NULL;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpsd);
/* add to temp buffer */
gpsd->next = gpsd->prev = NULL;
@@ -1267,6 +1378,9 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
static bool gp_strokes_paste_poll(bContext *C)
{
+ if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) {
+ return false;
+ }
/* 1) Must have GP datablock to paste to
* - We don't need to have an active layer though, as that can easily get added
* - If the active layer is locked, we can't paste there,
@@ -1285,20 +1399,17 @@ typedef enum eGP_PasteMode {
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); /* only use active for copy merge */
Scene *scene = CTX_data_scene(C);
bGPDframe *gpf;
eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
+ const bool on_back = RNA_boolean_get(op->ptr, "paste_back");
GHash *new_colors;
- /* check for various error conditions */
- if (gpd == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
- return OPERATOR_CANCELLED;
- }
- else if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
+ /* Check for various error conditions. */
+ if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) {
BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition");
return OPERATOR_CANCELLED;
}
@@ -1312,7 +1423,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
/* no active layer - let's just create one */
gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
- else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_TO_ACTIVE)) {
+ else if ((BKE_gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_TO_ACTIVE)) {
BKE_report(
op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
return OPERATOR_CANCELLED;
@@ -1330,17 +1441,6 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
}
if (ok == false) {
- /* XXX: this check is not 100% accurate
- * (i.e. image editor is incompatible with normal 2D strokes),
- * but should be enough to give users a good idea of what's going on.
- */
- if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) {
- BKE_report(op->reports, RPT_ERROR, "Cannot paste 2D strokes in 3D View");
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Cannot paste 3D strokes in 2D editors");
- }
-
return OPERATOR_CANCELLED;
}
}
@@ -1362,14 +1462,15 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
new_colors = gp_copybuf_validate_colormap(C);
/* Copy over the strokes from the buffer (and adjust the colors) */
- for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ bGPDstroke *gps_init = (!on_back) ? gp_strokes_copypastebuf.first : gp_strokes_copypastebuf.last;
+ for (bGPDstroke *gps = gps_init; gps; gps = (!on_back) ? gps->next : gps->prev) {
if (ED_gpencil_stroke_can_use(C, gps)) {
/* Need to verify if layer exists */
if (type != GP_COPY_TO_ACTIVE) {
gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
if (gpl == NULL) {
/* no layer - use active (only if layer deleted before paste) */
- gpl = CTX_data_active_gpencil_layer(C);
+ gpl = BKE_gpencil_layer_active_get(gpd);
}
}
@@ -1378,26 +1479,26 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
* we are obliged to add a new frame if one
* doesn't exist already
*/
- gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
if (gpf) {
/* Create new stroke */
- bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, true);
new_stroke->runtime.tmp_layerinfo[0] = '\0';
+ new_stroke->next = new_stroke->prev = NULL;
- new_stroke->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- new_stroke->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
- }
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
- new_stroke->triangles = NULL;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(new_stroke);
- new_stroke->next = new_stroke->prev = NULL;
- BLI_addtail(&gpf->strokes, new_stroke);
+ if (on_back) {
+ BLI_addhead(&gpf->strokes, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
/* Remap material */
Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
- new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
+ new_stroke->mat_nr = BKE_gpencil_object_material_index_get(ob, ma);
CLAMP_MIN(new_stroke->mat_nr, 0);
}
}
@@ -1415,6 +1516,8 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_paste(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
static const EnumPropertyItem copy_type[] = {
{GP_COPY_TO_ACTIVE, "ACTIVE", 0, "Paste to Active", ""},
{GP_COPY_BY_LAYER, "LAYER", 0, "Paste by Layer", ""},
@@ -1435,6 +1538,10 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", copy_type, GP_COPY_TO_ACTIVE, "Type", "");
+
+ prop = RNA_def_boolean(
+ ot->srna, "paste_back", 0, "Paste on Back", "Add pasted strokes behind all strokes");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ******************* Move To Layer ****************************** */
@@ -1477,7 +1584,6 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
*/
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps, *gpsn;
/* skip if no frame with strokes, or if this is the layer we're moving strokes to */
if ((gpl == target_layer) || (gpf == NULL)) {
@@ -1485,8 +1591,7 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
}
/* make copies of selected strokes, and deselect these once we're done */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -1514,7 +1619,7 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
/* Paste them all in one go */
if (strokes.first) {
- bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, GP_GETFRAME_ADD_NEW);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(target_layer, CFRA, GP_GETFRAME_ADD_NEW);
BLI_movelisttolist(&gpf->strokes, &strokes);
BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
@@ -1554,32 +1659,13 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
/* ********************* Add Blank Frame *************************** */
-/* Basically the same as the drawing op */
-static bool UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C)
-{
- if (ED_operator_regionactive(C)) {
- /* check if current context can support GPencil data */
- if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
- return 1;
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into");
- }
- }
- else {
- CTX_wm_operator_poll_msg_set(C, "Active region not set");
- }
-
- return 0;
-}
-
static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Scene *scene = CTX_data_scene(C);
int cfra = CFRA;
- bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *active_gpl = BKE_gpencil_layer_active_get(gpd);
const bool all_layers = RNA_boolean_get(op->ptr, "all_layers");
@@ -1599,7 +1685,7 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
}
/* 1) Check for an existing frame on the current frame */
- bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, cfra);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_find(gpl, cfra);
if (gpf) {
/* Shunt all frames after (and including) the existing one later by 1-frame */
for (; gpf; gpf = gpf->next) {
@@ -1608,7 +1694,7 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
}
/* 2) Now add a new frame, with nothing in it */
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_ADD_NEW);
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, cfra, GP_GETFRAME_ADD_NEW);
}
CTX_DATA_END;
@@ -1650,7 +1736,7 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
static bool gp_actframe_delete_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
/* only if there's an active layer with an active frame */
return (gpl && gpl->actframe);
@@ -1659,7 +1745,7 @@ static bool gp_actframe_delete_poll(bContext *C)
static bool gp_annotation_actframe_delete_poll(bContext *C)
{
bGPdata *gpd = ED_annotation_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
/* only if there's an active layer with an active frame */
return (gpl && gpl->actframe);
@@ -1673,11 +1759,11 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) :
ED_annotation_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
@@ -1690,7 +1776,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
}
/* delete it... */
- BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_frame_delete(gpl, gpf);
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -1747,14 +1833,14 @@ static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
/* try to get the "active" frame - but only if it actually occurs on this frame */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
if (gpf == NULL) {
continue;
}
/* delete it... */
- BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_frame_delete(gpl, gpf);
/* we successfully modified something */
success = true;
@@ -1821,15 +1907,13 @@ static int gp_delete_selected_strokes(bContext *C)
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
if (gpf == NULL) {
continue;
}
/* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -2060,9 +2144,8 @@ static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode)
gps->dvert = new_dvert;
gps->totpoints = tot;
- /* triangles cache needs to be recalculated */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
/* deselect the stroke, since none of its selected points will still be selected */
gps->flag &= ~GP_STROKE_SELECT;
@@ -2104,7 +2187,7 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst
const int totpoints = gps_first->totpoints + gps_last->totpoints;
/* create new stroke */
- bGPDstroke *join_stroke = MEM_dupallocN(gps_first);
+ bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false);
join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__);
join_stroke->totpoints = totpoints;
@@ -2132,6 +2215,7 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst
pt_final->strength = pt->strength;
pt_final->time = delta;
pt_final->flag = pt->flag;
+ copy_v4_v4(pt_final->vert_color, pt->vert_color);
/* retiming with fixed time interval (we cannot determine real time) */
delta += 0.01f;
@@ -2170,6 +2254,8 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst
/* add new stroke at head */
BLI_addhead(&gpf->strokes, join_stroke);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(join_stroke);
/* remove first stroke */
BLI_remlink(&gpf->strokes, gps_first);
@@ -2246,18 +2332,14 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf,
/* Create each new stroke... */
for (idx = 0; idx < num_islands; idx++) {
tGPDeleteIsland *island = &islands[idx];
- new_stroke = MEM_dupallocN(gps);
+ new_stroke = BKE_gpencil_stroke_duplicate(gps, false);
/* if cyclic and first stroke, save to join later */
if ((is_cyclic) && (gps_first == NULL)) {
gps_first = new_stroke;
}
- /* initialize triangle memory - to be calculated on next redraw */
- new_stroke->triangles = NULL;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
new_stroke->flag &= ~GP_STROKE_CYCLIC;
- new_stroke->tot_triangles = 0;
/* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
new_stroke->totpoints = island->end_idx - island->start_idx + 1;
@@ -2320,6 +2402,9 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf,
BKE_gpencil_free_stroke(new_stroke);
}
else {
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(new_stroke);
+
if (next_stroke) {
BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
}
@@ -2355,15 +2440,13 @@ static int gp_delete_selected_points(bContext *C)
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
if (gpf == NULL) {
continue;
}
/* simply delete strokes which are selected */
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -2379,7 +2462,7 @@ static int gp_delete_selected_points(bContext *C)
gps->flag &= ~GP_STROKE_SELECT;
/* delete unwanted points by splitting stroke into several smaller ones */
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
changed = true;
}
@@ -2532,16 +2615,16 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
Object *obact = CTX_data_active_object(C);
const float gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL);
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
/* calculate difference matrix object */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
bGPDspoint *pt;
int i;
@@ -2568,7 +2651,7 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
/* return data */
copy_v3_v3(&pt->x, fpt);
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
+ gp_apply_parent_point(depsgraph, obact, gpl, pt);
}
}
}
@@ -2609,16 +2692,16 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = scene->cursor.location;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
/* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
bGPDspoint *pt;
int i;
@@ -2652,7 +2735,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
copy_v3_v3(&pt->x, cursor_global);
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
+ gp_apply_parent_point(depsgraph, obact, gpl, pt);
}
}
}
@@ -2707,16 +2790,16 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
INIT_MINMAX(min, max);
/* calculate midpoints from selected points */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
float diff_mat[4][4];
/* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
bGPDspoint *pt;
int i;
@@ -2783,7 +2866,7 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
/* sanity checks */
if (ELEM(NULL, gpd, gpl, gpl->frames.first)) {
@@ -2791,8 +2874,8 @@ static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
}
/* loop all strokes */
- 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) {
/* Apply thickness */
if ((gps->thickness == 0) && (gpl->line_change == 0)) {
gps->thickness = gpl->thickness;
@@ -2866,8 +2949,8 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
continue;
}
/* skip hidden or locked colors */
- if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) ||
+ (gp_style->flag & GP_MATERIAL_LOCKED)) {
continue;
}
@@ -2891,7 +2974,7 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
/* Create new geometry. */
if ((gps->flag & GP_STROKE_CYCLIC) && (geometry)) {
- BKE_gpencil_close_stroke(gps);
+ BKE_gpencil_stroke_close(gps);
}
}
@@ -2980,8 +3063,8 @@ static int gp_stroke_caps_set_exec(bContext *C, wmOperator *op)
continue;
}
/* skip hidden or locked colors */
- if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) ||
+ (gp_style->flag & GP_MATERIAL_LOCKED)) {
continue;
}
@@ -3061,6 +3144,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
pt.pressure = point->pressure;
pt.strength = point->strength;
pt.time = point->time;
+ copy_v4_v4(pt.vert_color, point->vert_color);
/* replace first point with last point */
point2 = &gps->points[end];
@@ -3071,6 +3155,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
point->pressure = point2->pressure;
point->strength = point2->strength;
point->time = point2->time;
+ copy_v4_v4(point->vert_color, point2->vert_color);
/* replace last point with first saved before */
point = &gps->points[end];
@@ -3081,6 +3166,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
point->pressure = pt.pressure;
point->strength = pt.strength;
point->time = pt.time;
+ copy_v4_v4(point->vert_color, pt.vert_color);
end--;
}
@@ -3111,6 +3197,7 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
newpoint->pressure = pressure;
newpoint->strength = strength;
newpoint->time = point->time + deltatime;
+ copy_v4_v4(newpoint->vert_color, point->vert_color);
if (gps->dvert != NULL) {
MDeformVert *dvert = &gps->dvert[idx];
@@ -3184,8 +3271,7 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a,
static int gp_stroke_join_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
- bGPDstroke *gps, *gpsn;
+ bGPDlayer *activegpl = BKE_gpencil_layer_active_get(gpd);
Object *ob = CTX_data_active_object(C);
bGPDframe *gpf_a = NULL;
@@ -3215,8 +3301,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
continue;
}
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
if (gps->flag & GP_STROKE_SELECT) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -3241,15 +3326,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
/* create a new stroke if was not created before (only created if something to join) */
if (new_stroke == NULL) {
- new_stroke = MEM_dupallocN(stroke_a);
- new_stroke->points = MEM_dupallocN(stroke_a->points);
- if (stroke_a->dvert != NULL) {
- new_stroke->dvert = MEM_dupallocN(stroke_a->dvert);
- BKE_gpencil_stroke_weights_duplicate(stroke_a, new_stroke);
- }
- new_stroke->triangles = NULL;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ new_stroke = BKE_gpencil_stroke_duplicate(stroke_a, true);
/* if new, set current color */
if (type == GP_STROKE_JOINCOPY) {
@@ -3263,6 +3340,9 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
/* if join only, delete old strokes */
if (type == GP_STROKE_JOIN) {
if (stroke_a) {
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(new_stroke);
+
BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
BLI_remlink(&gpf->strokes, stroke_a);
BKE_gpencil_free_stroke(stroke_a);
@@ -3287,6 +3367,8 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op)
if (activegpl->actframe == NULL) {
activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(new_stroke);
BLI_addtail(&activegpl->actframe->strokes, new_stroke);
}
@@ -3347,7 +3429,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
if (gps->flag & GP_STROKE_SELECT) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -3460,7 +3542,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
GP_REPROJECT_TOP,
GP_REPROJECT_CURSOR)) {
if (mode != GP_REPROJECT_CURSOR) {
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, origin);
}
else {
copy_v3_v3(origin, scene->cursor.location);
@@ -3495,7 +3577,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
copy_v3_v3(&pt->x, &pt2.x);
/* apply parent again */
- gp_apply_parent_point(depsgraph, ob, gpd, gpl, pt);
+ gp_apply_parent_point(depsgraph, ob, gpl, pt);
}
/* Project screen-space back to 3D space (from current perspective)
* so that all points have been treated the same way. */
@@ -3602,6 +3684,43 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
ot->srna, "type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", "");
}
+static int gp_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ BKE_gpencil_stroke_geometry_update(gps);
+ }
+ }
+ }
+ /* update changed data */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_recalc_geometry(wmOperatorType *ot)
+{
+
+ /* identifiers */
+ ot->name = "Recalculate internal geometry";
+ ot->idname = "GPENCIL_OT_recalc_geometry";
+ ot->description = "Update all internal geometry data";
+
+ /* callbacks */
+ ot->exec = gp_recalc_geometry_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ******************* Stroke subdivide ************************** */
/* helper to smooth */
static void gp_smooth_stroke(bContext *C, wmOperator *op)
@@ -3629,19 +3748,19 @@ static void gp_smooth_stroke(bContext *C, wmOperator *op)
/* perform smoothing */
if (smooth_position) {
- BKE_gpencil_smooth_stroke(gps, i, factor);
+ BKE_gpencil_stroke_smooth(gps, i, factor);
}
if (smooth_strength) {
- BKE_gpencil_smooth_stroke_strength(gps, i, factor);
+ BKE_gpencil_stroke_smooth_strength(gps, i, factor);
}
if (smooth_thickness) {
/* thickness need to repeat process several times */
for (int r2 = 0; r2 < r * 20; r2++) {
- BKE_gpencil_smooth_stroke_thickness(gps, i, factor);
+ BKE_gpencil_stroke_smooth_thickness(gps, i, factor);
}
}
if (smooth_uv) {
- BKE_gpencil_smooth_stroke_uv(gps, i, factor);
+ BKE_gpencil_stroke_smooth_uv(gps, i, factor);
}
}
}
@@ -3710,7 +3829,6 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
if (gps->dvert != NULL) {
gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
}
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
/* loop and interpolate */
i2 = 0;
@@ -3724,6 +3842,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
pt_final->strength = pt->strength;
pt_final->time = pt->time;
pt_final->flag = pt->flag;
+ copy_v4_v4(pt_final->vert_color, pt->vert_color);
if (gps->dvert != NULL) {
dvert = &temp_dverts[i];
@@ -3747,6 +3866,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->flag |= GP_SPOINT_SELECT;
@@ -3780,9 +3900,8 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op)
MEM_SAFE_FREE(temp_dverts);
}
- /* triangles cache needs to be recalculated */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
@@ -3850,7 +3969,7 @@ static int gp_stroke_simplify_exec(bContext *C, wmOperator *op)
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
/* simplify stroke using Ramer-Douglas-Peucker algorithm */
- BKE_gpencil_simplify_stroke(gps, factor);
+ BKE_gpencil_stroke_simplify_adaptive(gps, factor);
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
@@ -3899,7 +4018,7 @@ static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op)
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
for (int i = 0; i < steps; i++) {
- BKE_gpencil_simplify_fixed(gps);
+ BKE_gpencil_stroke_simplify_fixed(gps);
}
}
}
@@ -3949,7 +4068,7 @@ static int gp_stroke_sample_exec(bContext *C, wmOperator *op)
/* Go through each editable + selected stroke */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- BKE_gpencil_sample_stroke(gps, length, true);
+ BKE_gpencil_stroke_sample(gps, length, true);
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
@@ -4001,14 +4120,12 @@ static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
if (gpf == NULL) {
continue;
}
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -4016,7 +4133,7 @@ static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
}
if (gps->flag & GP_STROKE_SELECT) {
- BKE_gpencil_trim_stroke(gps);
+ BKE_gpencil_stroke_trim(gps);
}
}
/* if not multiedit, exit loop*/
@@ -4066,7 +4183,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base_old = CTX_data_active_base(C);
+ Base *base_prev = CTX_data_active_base(C);
bGPdata *gpd_src = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
@@ -4096,7 +4213,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
/* Take into account user preferences for duplicating actions. */
short dupflag = (U.dupflag & USER_DUP_ACT);
- base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, dupflag);
+ base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_prev, dupflag);
ob_dst = base_new->object;
ob_dst->mode = OB_MODE_OBJECT;
/* create new grease pencil datablock */
@@ -4111,7 +4228,6 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
if (gpf == NULL) {
continue;
@@ -4119,8 +4235,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
gpf_dst = NULL;
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -4139,7 +4254,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
/* add frame if not created before */
if (gpf_dst == NULL) {
- gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW);
+ gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW);
}
/* add duplicate materials */
@@ -4152,7 +4267,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
/* selected points mode */
if (mode == GP_SEPARATE_POINT) {
/* make copy of source stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true);
/* Reassign material. */
gps_dst->mat_nr = idx;
@@ -4169,7 +4284,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0);
/* delete selected points from origin stroke */
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
}
/* selected strokes mode */
else if (mode == GP_SEPARATE_STROKE) {
@@ -4200,10 +4315,10 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
if (gpl) {
/* try to set a new active layer in source datablock */
if (gpl->prev) {
- BKE_gpencil_layer_setactive(gpd_src, gpl->prev);
+ BKE_gpencil_layer_active_set(gpd_src, gpl->prev);
}
else if (gpl->next) {
- BKE_gpencil_layer_setactive(gpd_src, gpl->next);
+ BKE_gpencil_layer_active_set(gpd_src, gpl->next);
}
/* unlink from source datablock */
BLI_remlink(&gpd_src->layers, gpl);
@@ -4212,8 +4327,8 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
BLI_addtail(&gpd_dst->layers, gpl);
/* add duplicate materials */
- 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) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -4227,8 +4342,8 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
/* Ensure destination object has one active layer. */
if (gpd_dst->layers.first != NULL) {
- if (BKE_gpencil_layer_getactive(gpd_dst) == NULL) {
- BKE_gpencil_layer_setactive(gpd_dst, gpd_dst->layers.first);
+ if (BKE_gpencil_layer_active_get(gpd_dst) == NULL) {
+ BKE_gpencil_layer_active_set(gpd_dst, gpd_dst->layers.first);
}
}
@@ -4288,14 +4403,12 @@ static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- bGPDstroke *gps, *gpsn;
if (gpf == NULL) {
continue;
}
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
@@ -4308,7 +4421,7 @@ static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
/* split selected strokes */
if (gps->flag & GP_STROKE_SELECT) {
/* make copy of source stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true);
/* link to same frame */
BLI_addtail(&gpf->strokes, gps_dst);
@@ -4322,11 +4435,11 @@ static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0);
/* delete selected points from origin stroke */
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false, 0);
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0);
}
}
/* select again tagged points */
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
bGPDspoint *ptn = gps->points;
for (int i2 = 0; i2 < gps->totpoints; i2++, ptn++) {
if (ptn->flag & GP_SPOINT_TAG) {
@@ -4566,8 +4679,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
GP_EDITABLE_STROKES_END(gpstroke_iter);
/* dissolve selected points */
- bGPDstroke *gpsn;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl->flag & GP_LAYER_LOCKED) {
continue;
}
@@ -4576,8 +4688,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
if (gpf == NULL) {
continue;
}
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
if (gps->flag & GP_STROKE_SELECT) {
gpencil_cutter_dissolve(gpl, gps);
}
@@ -4662,11 +4773,11 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob)
bGPdata *gpd = (bGPdata *)ob->data;
gpd->flag &= ~(GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE |
- GP_DATA_STROKE_WEIGHTMODE);
+ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE);
ob->restore_mode = ob->mode;
ob->mode &= ~(OB_MODE_PAINT_GPENCIL | OB_MODE_EDIT_GPENCIL | OB_MODE_SCULPT_GPENCIL |
- OB_MODE_WEIGHT_GPENCIL);
+ OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL);
/* Inform all CoW versions that we changed the mode. */
DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE);
@@ -4687,7 +4798,7 @@ static bool gp_merge_by_distance_poll(bContext *C)
return false;
}
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
return ((gpl != NULL) && (ob->mode == OB_MODE_EDIT_GPENCIL));
}
@@ -4707,7 +4818,7 @@ static int gp_merge_by_distance_exec(bContext *C, wmOperator *op)
/* Go through each editable selected stroke */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- BKE_gpencil_merge_distance_stroke(gpf_, gps, threshold, unselected);
+ BKE_gpencil_stroke_merge_distance(gpf_, gps, threshold, unselected);
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index d76ab85ad31..c928c1e933a 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -134,6 +134,9 @@ typedef struct tGPDfill {
/* scaling factor */
short fill_factor;
+ /* Frame to use. */
+ int active_cfra;
+
/** number of elements currently in cache */
short sbuffer_used;
/** temporary points */
@@ -228,7 +231,6 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
Object *ob = tgpf->ob;
bGPdata *gpd = tgpf->gpd;
- int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
tGPDdraw tgpw;
tgpw.rv3d = tgpf->rv3d;
@@ -245,9 +247,9 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
GPU_blend(true);
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* calculate parent position */
- ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
+ BKE_gpencil_parent_matrix_get(tgpw.depsgraph, ob, gpl, tgpw.diff_mat);
/* do not draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE) {
@@ -256,25 +258,25 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
/* if active layer and no keyframe, create a new one */
if (gpl == tgpf->gpl) {
- if ((gpl->actframe == NULL) || (gpl->actframe->framenum != cfra_eval)) {
- BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ if ((gpl->actframe == NULL) || (gpl->actframe->framenum != tgpf->active_cfra)) {
+ BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW);
}
}
/* get frame to draw */
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_USE_PREV);
if (gpf == NULL) {
continue;
}
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* check if stroke can be drawn */
if ((gps->points == NULL) || (gps->totpoints < 2)) {
continue;
}
/* check if the color is visible */
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
+ if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE)) {
continue;
}
@@ -291,7 +293,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
tgpw.onion = true;
tgpw.custonion = true;
- bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE);
+ bool textured_stroke = (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE);
/* normal strokes */
if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
@@ -666,6 +668,62 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf)
BLI_stack_free(stack);
}
+/* Check if there are some pixel not filled with green. If no points, means nothing to fill. */
+static bool gpencil_check_borders(tGPDfill *tgpf)
+{
+ ImBuf *ibuf;
+ void *lock;
+ ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
+ int idx;
+ int pixel = 0;
+ float color[4];
+ bool found = false;
+
+ /* horizontal lines */
+ for (idx = 0; idx < ibuf->x; idx++) {
+ /* bottom line */
+ get_pixel(ibuf, idx, color);
+ if (color[1] != 1.0f) {
+ found = true;
+ break;
+ }
+ /* top line */
+ pixel = idx + (ibuf->x * (ibuf->y - 1));
+ get_pixel(ibuf, pixel, color);
+ if (color[1] != 1.0f) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ /* vertical lines */
+ for (idx = 0; idx < ibuf->y; idx++) {
+ /* left line */
+ get_pixel(ibuf, ibuf->x * idx, color);
+ if (color[1] != 1.0f) {
+ found = true;
+ break;
+ }
+ /* right line */
+ pixel = ibuf->x * idx + (ibuf->x - 1);
+ get_pixel(ibuf, pixel, color);
+ if (color[1] != 1.0f) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ /* release ibuf */
+ if (ibuf) {
+ BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
+ }
+
+ tgpf->ima->id.tag |= LIB_TAG_DOIT;
+
+ return found;
+}
+
/* clean external border of image to avoid infinite loops */
static void gpencil_clean_borders(tGPDfill *tgpf)
{
@@ -1006,8 +1064,6 @@ static void gpencil_points_from_stack(tGPDfill *tgpf)
/* create a grease pencil stroke using points in buffer */
static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
{
- const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
-
ToolSettings *ts = tgpf->scene->toolsettings;
const char *align_flag = &ts->gpencil_v3d_align;
const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
@@ -1026,16 +1082,23 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
return;
}
- /* get frame or create a new one */
- tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ /* Get frame or create a new one. */
+ tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW);
+
+ /* Set frame as selected. */
+ tgpf->gpf->flag |= GP_FRAME_SELECT;
/* create new stroke */
bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+ gps->fill_opacity_fac = 1.0f;
+ gps->hardeness = brush->gpencil_settings->hardeness;
+ copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
gps->inittime = 0.0f;
+ /* Apply the vertex color to fill. */
+ ED_gpencil_fill_vertex_color_set(ts, brush, gps);
+
/* the polygon must be closed, so enabled cyclic */
gps->flag |= GP_STROKE_CYCLIC;
gps->flag |= GP_STROKE_3DSPACE;
@@ -1054,11 +1117,6 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
gps->totpoints = tgpf->sbuffer_used;
gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_used, "gp_stroke_points");
- /* initialize triangle memory to dummy data */
- gps->tot_triangles = 0;
- gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
/* add stroke to frame */
if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
BLI_addhead(&tgpf->gpf->strokes, gps);
@@ -1093,6 +1151,9 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
pt->strength = 1.0f;
pt->time = 0.0f;
+ /* Apply the vertex color to point. */
+ ED_gpencil_point_vertex_color_set(ts, brush, pt);
+
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr);
if (dw) {
@@ -1115,7 +1176,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
float smoothfac = 1.0f;
for (int r = 0; r < 1; r++) {
for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
+ BKE_gpencil_stroke_smooth(gps, i, smoothfac - reduce);
}
reduce += 0.25f; // reduce the factor
}
@@ -1124,7 +1185,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) &&
((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
float origin[3];
- ED_gp_get_drawing_reference(tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(
+ tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin);
ED_gp_project_stroke_to_plane(
tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1);
}
@@ -1132,7 +1194,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
/* if parented change position relative to parent object */
for (int a = 0; a < tgpf->sbuffer_used; a++) {
pt = &gps->points[a];
- gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
+ gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt);
}
/* if camera view, reproject flat to view to avoid perspective effect */
@@ -1142,14 +1204,17 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
/* simplify stroke */
for (int b = 0; b < tgpf->fill_simplylvl; b++) {
- BKE_gpencil_simplify_fixed(gps);
+ BKE_gpencil_stroke_simplify_fixed(gps);
}
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
/* ----------------------- */
/* Drawing */
/* Helper: Draw status message while the user is running the operator */
-static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf))
+static void gpencil_fill_status_indicators(bContext *C)
{
const char *status_str = TIP_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
ED_workspace_status_text(C, status_str);
@@ -1228,10 +1293,11 @@ static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
/* set GP datablock */
tgpf->gpd = gpd;
- tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
+ tgpf->gpl = BKE_gpencil_layer_active_get(gpd);
if (tgpf->gpl == NULL) {
tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
}
+
tgpf->lock_axis = ts->gp_sculpt.lock_axis;
tgpf->oldkey = -1;
@@ -1339,7 +1405,7 @@ static int gpencil_fill_init(bContext *C, wmOperator *op)
tGPDfill *tgpf;
/* cannot paint in locked layer */
bGPdata *gpd = CTX_data_gpencil_data(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
return 0;
}
@@ -1401,7 +1467,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH);
- gpencil_fill_status_indicators(C, tgpf);
+ gpencil_fill_status_indicators(C);
DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@@ -1416,6 +1482,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPDfill *tgpf = op->customdata;
+ Scene *scene = tgpf->scene;
int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
@@ -1426,7 +1493,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
case LEFTMOUSE:
tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
- /* first time the event is not enabled to show help lines */
+ /* first time the event is not enabled to show help lines. */
if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
ARegion *region = BKE_area_find_region_xy(
CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
@@ -1437,42 +1504,55 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
in_bounds = BLI_rcti_isect_pt(&region->winrct, event->x, event->y);
if ((in_bounds) && (region->regiontype == RGN_TYPE_WINDOW)) {
- /* TODO GPXX: Verify the mouse click is right for any window size */
tgpf->center[0] = event->mval[0];
tgpf->center[1] = event->mval[1];
+ /* Set active frame as current for filling. */
+ tgpf->active_cfra = CFRA;
+
/* render screen to temp image */
if (gp_render_offscreen(tgpf)) {
/* apply boundary fill */
gpencil_boundaryfill_area(tgpf);
- /* clean borders to avoid infinite loops */
- gpencil_clean_borders(tgpf);
+ /* Check if detected some border to fill. */
+ if (gpencil_check_borders(tgpf)) {
- /* analyze outline */
- gpencil_get_outline_points(tgpf);
+ /* clean borders to avoid infinite loops */
+ gpencil_clean_borders(tgpf);
- /* create array of points from stack */
- gpencil_points_from_stack(tgpf);
+ /* analyze outline */
+ gpencil_get_outline_points(tgpf);
- /* create z-depth array for reproject */
- gpencil_get_depth_array(tgpf);
+ /* create array of points from stack */
+ gpencil_points_from_stack(tgpf);
- /* create stroke and reproject */
- gpencil_stroke_from_buffer(tgpf);
- }
+ /* create z-depth array for reproject */
+ gpencil_get_depth_array(tgpf);
- /* restore size */
- tgpf->region->winx = (short)tgpf->bwinx;
- tgpf->region->winy = (short)tgpf->bwiny;
- tgpf->region->winrct = tgpf->brect;
+ /* create stroke and reproject */
+ gpencil_stroke_from_buffer(tgpf);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Fill canceled. No edges detected");
+ }
+ }
/* free temp stack data */
if (tgpf->stack) {
BLI_stack_free(tgpf->stack);
}
+ /* Free memory. */
+ MEM_SAFE_FREE(tgpf->sbuffer);
+ MEM_SAFE_FREE(tgpf->depth_arr);
+
+ /* restore size */
+ tgpf->region->winx = (short)tgpf->bwinx;
+ tgpf->region->winy = (short)tgpf->bwiny;
+ tgpf->region->winrct = tgpf->brect;
+
/* push undo data */
gpencil_undo_push(tgpf->gpd);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 077b5b88118..2d36e426835 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -111,6 +111,8 @@ typedef struct tGPDinterpolate_layer {
} tGPDinterpolate_layer;
typedef struct tGPDinterpolate {
+ /** Current depsgraph from context */
+ struct Depsgraph *depsgraph;
/** current scene from context */
struct Scene *scene;
/** area where painting originated */
@@ -138,10 +140,6 @@ typedef struct tGPDinterpolate {
int flag;
NumInput num; /* numeric input */
- /** handle for drawing strokes while operator is running 3d stuff */
- void *draw_handle_3d;
- /** handle for drawing strokes while operator is running screen stuff */
- void *draw_handle_screen;
} tGPDinterpolate;
/* Temporary primitive operation data */
@@ -155,6 +153,8 @@ typedef struct tGPDprimitive {
struct Scene *scene;
/** current active gp object */
struct Object *ob;
+ /** current evaluated gp object */
+ struct Object *ob_eval;
/** area where painting originated */
struct ScrArea *sa;
/** region where painting originated */
@@ -166,7 +166,7 @@ typedef struct tGPDprimitive {
/** current GP datablock */
struct bGPdata *gpd;
/** current material */
- struct Material *mat;
+ struct Material *material;
/** current brush */
struct Brush *brush;
@@ -233,10 +233,6 @@ typedef struct tGPDprimitive {
} tGPDprimitive;
/* Modal Operator Drawing Callbacks ------------------------ */
-
-void ED_gp_draw_interpolation(const struct bContext *C,
- struct tGPDinterpolate *tgpi,
- const int type);
void ED_gp_draw_fill(struct tGPDdraw *tgpw);
/* ***************************************************** */
@@ -284,7 +280,6 @@ void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4],
*/
void gp_apply_parent(struct Depsgraph *depsgraph,
struct Object *obact,
- bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps);
/**
@@ -292,7 +287,6 @@ void gp_apply_parent(struct Depsgraph *depsgraph,
*/
void gp_apply_parent_point(struct Depsgraph *depsgraph,
struct Object *obact,
- bGPdata *gpd,
bGPDlayer *gpl,
bGPDspoint *pt);
@@ -342,7 +336,6 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf,
int gp_delete_selected_point_wrap(bContext *C);
void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide);
-void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, struct RNG *rng);
/* Layers Enums -------------------------------------- */
@@ -367,6 +360,14 @@ void GPENCIL_OT_annotate(struct wmOperatorType *ot);
void GPENCIL_OT_draw(struct wmOperatorType *ot);
void GPENCIL_OT_fill(struct wmOperatorType *ot);
+/* Vertex Paint. */
+void GPENCIL_OT_vertex_paint(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_color_brightness_contrast(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_color_hsv(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_color_invert(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_color_levels(struct wmOperatorType *ot);
+void GPENCIL_OT_vertex_color_set(struct wmOperatorType *ot);
+
/* Guides ----------------------- */
void GPENCIL_OT_guide_rotate(struct wmOperatorType *ot);
@@ -390,6 +391,7 @@ void GPENCIL_OT_selectmode_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_paintmode_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_sculptmode_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_weightmode_toggle(struct wmOperatorType *ot);
+void GPENCIL_OT_vertexmode_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_selection_opacity_toggle(struct wmOperatorType *ot);
void GPENCIL_OT_select(struct wmOperatorType *ot);
@@ -405,6 +407,7 @@ void GPENCIL_OT_select_less(struct wmOperatorType *ot);
void GPENCIL_OT_select_first(struct wmOperatorType *ot);
void GPENCIL_OT_select_last(struct wmOperatorType *ot);
void GPENCIL_OT_select_alternate(struct wmOperatorType *ot);
+void GPENCIL_OT_select_color(struct wmOperatorType *ot);
void GPENCIL_OT_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_delete(struct wmOperatorType *ot);
@@ -415,16 +418,19 @@ void GPENCIL_OT_extrude(struct wmOperatorType *ot);
void GPENCIL_OT_move_to_layer(struct wmOperatorType *ot);
void GPENCIL_OT_layer_change(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_active(struct wmOperatorType *ot);
void GPENCIL_OT_snap_to_grid(struct wmOperatorType *ot);
void GPENCIL_OT_snap_to_cursor(struct wmOperatorType *ot);
void GPENCIL_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void GPENCIL_OT_reproject(struct wmOperatorType *ot);
+void GPENCIL_OT_recalc_geometry(struct wmOperatorType *ot);
/* stroke sculpting -- */
void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
+void GPENCIL_OT_weight_paint(struct wmOperatorType *ot);
/* buttons editing --- */
@@ -440,6 +446,9 @@ void GPENCIL_OT_layer_annotation_move(struct wmOperatorType *ot);
void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_layer_duplicate_object(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_mask_add(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_mask_remove(struct wmOperatorType *ot);
+
void GPENCIL_OT_hide(struct wmOperatorType *ot);
void GPENCIL_OT_reveal(struct wmOperatorType *ot);
@@ -459,6 +468,7 @@ void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot);
void GPENCIL_OT_frame_clean_loose(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
+void GPENCIL_OT_image_to_grease_pencil(struct wmOperatorType *ot);
enum {
GP_STROKE_JOIN = -1,
@@ -498,8 +508,16 @@ void GPENCIL_OT_stroke_merge(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_cutter(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_trim(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_merge_by_distance(struct wmOperatorType *ot);
+void GPENCIL_OT_stroke_merge_material(struct wmOperatorType *ot);
-void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot);
+void GPENCIL_OT_material_to_vertex_color(struct wmOperatorType *ot);
+void GPENCIL_OT_extract_palette_vertex(struct wmOperatorType *ot);
+
+void GPENCIL_OT_transform_fill(struct wmOperatorType *ot);
+void GPENCIL_OT_reset_transform_fill(struct wmOperatorType *ot);
+
+void GPENCIL_OT_brush_reset(struct wmOperatorType *ot);
+void GPENCIL_OT_brush_reset_all(struct wmOperatorType *ot);
/* undo stack ---------- */
@@ -617,7 +635,7 @@ struct GP_EditableStrokes_Iter {
bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
- ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
+ BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* loop over strokes */ \
bGPDstroke *gpsn_; \
@@ -643,10 +661,6 @@ struct GP_EditableStrokes_Iter {
} \
(void)0
-#define GPENCIL_ANY_SCULPT_MASK(flag) \
- ((flag & (GP_SCULPT_MASK_SELECTMODE_POINT | GP_SCULPT_MASK_SELECTMODE_STROKE | \
- GP_SCULPT_MASK_SELECTMODE_SEGMENT)))
-
/**
* Iterate over all editable strokes using evaluated data in the current context,
* stopping on each usable layer + stroke pair (i.e. gpl and gps)
@@ -662,26 +676,21 @@ struct GP_EditableStrokes_Iter {
struct GP_EditableStrokes_Iter gpstroke_iter = {{{0}}}; \
Depsgraph *depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C); \
Object *obact_ = CTX_data_active_object(C); \
- Object *obeval_ = DEG_get_evaluated_object(depsgraph_, obact_); \
- bGPdata *gpd_ = CTX_data_gpencil_data(C); \
+ Object *ob_eval_ = (Object *)DEG_get_evaluated_id(depsgraph_, &obact_->id); \
+ bGPdata *gpd_ = (bGPdata *)ob_eval_->data; \
const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
- int idx_eval = 0; \
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { \
- if (gpencil_layer_is_editable(gpl)) { \
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { \
+ if (BKE_gpencil_layer_is_editable(gpl)) { \
bGPDframe *init_gpf_ = gpl->actframe; \
if (is_multiedit_) { \
init_gpf_ = gpl->frames.first; \
} \
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
- ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
+ BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
- /* get evaluated frame with modifiers applied */ \
- bGPDframe *gpf_eval_ = (!is_multiedit_) ? \
- &obeval_->runtime.gpencil_evaluated_frames[idx_eval] : \
- gpf_; \
/* loop over strokes */ \
- for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->next) { \
+ for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \
/* skip strokes that are invalid for current view */ \
if (ED_gpencil_stroke_can_use(C, gps) == false) \
continue; \
@@ -698,7 +707,6 @@ struct GP_EditableStrokes_Iter {
} \
} \
} \
- idx_eval++; \
} \
} \
(void)0
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 940fb85f91a..bd00a492035 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -115,31 +115,38 @@ static void gp_interpolate_update_points(const bGPDstroke *gps_from,
pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor);
pt->strength = interpf(prev->strength, next->strength, 1.0f - factor);
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
-
- /* GPXX interpolate dverts */
-#if 0
- MDeformVert *dvert = &new_stroke->dvert[i];
- dvert->totweight = 0;
- dvert->dw = NULL;
-#endif
}
}
/* ****************** Interpolate Interactive *********************** */
+/* Helper: free all temp strokes for display. */
+static void gp_interpolate_free_temp_strokes(bGPDframe *gpf)
+{
+ if (gpf == NULL) {
+ return;
+ }
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_TAG) {
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+ }
+ }
+}
/* Helper: Update all strokes interpolated */
static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
{
bGPdata *gpd = tgpi->gpd;
- tGPDinterpolate_layer *tgpil;
const float shift = tgpi->shift;
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- bGPDstroke *new_stroke;
+ LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
const float factor = tgpil->factor + shift;
- for (new_stroke = tgpil->interFrame->strokes.first; new_stroke;
- new_stroke = new_stroke->next) {
+ bGPDframe *gpf = tgpil->gpl->actframe;
+ /* Free temp strokes. */
+ gp_interpolate_free_temp_strokes(gpf);
+
+ LISTBASE_FOREACH (bGPDstroke *, new_stroke, &tgpil->interFrame->strokes) {
bGPDstroke *gps_from, *gps_to;
int stroke_idx;
@@ -156,6 +163,13 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
/* update points position */
if ((gps_from) && (gps_to)) {
gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+
+ /* Add temp strokes. */
+ if (gpf) {
+ bGPDstroke *gps_eval = BKE_gpencil_stroke_duplicate(new_stroke, true);
+ gps_eval->flag |= GP_STROKE_TAG;
+ BLI_addtail(&gpf->strokes, gps_eval);
+ }
}
}
}
@@ -172,19 +186,18 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag;
/* get layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* all layers or only active */
if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) {
continue;
}
/* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
continue;
}
/* read strokes */
- for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from;
- gps_from = gps_from->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_from, &gpl->actframe->strokes) {
bGPDstroke *gps_to;
int fFrame;
@@ -232,7 +245,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpi->high_limit = 2.0f - tgpi->init_factor;
/* set layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
tGPDinterpolate_layer *tgpil;
/* all layers or only active */
@@ -240,7 +253,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
continue;
}
/* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
continue;
}
@@ -262,8 +275,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
(tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
/* create new strokes data with interpolated points reading original stroke */
- for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from;
- gps_from = gps_from->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_from, &tgpil->prevFrame->strokes) {
bGPDstroke *gps_to;
int fFrame;
@@ -293,7 +305,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
}
/* create new stroke */
- new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
+ new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true);
if (valid) {
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
@@ -305,8 +317,6 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
sizeof(*new_stroke->dvert) * gps_to->totpoints);
}
new_stroke->totpoints = gps_to->totpoints;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
}
/* update points position */
gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
@@ -318,12 +328,10 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
if (new_stroke->dvert != NULL) {
new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert));
}
- new_stroke->tot_triangles = 0;
- new_stroke->triangles = MEM_recallocN(new_stroke->triangles,
- sizeof(*new_stroke->triangles));
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(new_stroke);
/* add to strokes */
BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
}
@@ -331,25 +339,6 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
}
/* ----------------------- */
-/* Drawing Callbacks */
-
-/* Drawing callback for modal operator in screen mode */
-static void gpencil_interpolate_draw_screen(const struct bContext *C,
- ARegion *UNUSED(region),
- void *arg)
-{
- tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_PIXEL);
-}
-
-/* Drawing callback for modal operator in 3d mode */
-static void gpencil_interpolate_draw_3d(const bContext *C, ARegion *UNUSED(region), void *arg)
-{
- tGPDinterpolate *tgpi = (tGPDinterpolate *)arg;
- ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW);
-}
-
-/* ----------------------- */
/* Helper: calculate shift based on position of mouse (we only use x-axis for now.
* since this is more convenient for users to do), and store new shift value
@@ -415,25 +404,23 @@ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpol
static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
{
tGPDinterpolate *tgpi = op->customdata;
- tGPDinterpolate_layer *tgpil;
bGPdata *gpd = tgpi->gpd;
/* don't assume that operator data exists at all */
if (tgpi) {
- /* remove drawing handler */
- if (tgpi->draw_handle_screen) {
- ED_region_draw_cb_exit(tgpi->region->type, tgpi->draw_handle_screen);
- }
- if (tgpi->draw_handle_3d) {
- ED_region_draw_cb_exit(tgpi->region->type, tgpi->draw_handle_3d);
- }
-
/* clear status message area */
ED_area_status_text(tgpi->sa, NULL);
ED_workspace_status_text(C, NULL);
+ /* Clear any temp stroke. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ gp_interpolate_free_temp_strokes(gpf);
+ }
+ }
+
/* finally, free memory used by temp data */
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
BKE_gpencil_free_strokes(tgpil->interFrame);
MEM_freeN(tgpil->interFrame);
}
@@ -455,6 +442,7 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte
bGPdata *gpd = CTX_data_gpencil_data(C);
/* set current scene and window */
+ tgpi->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpi->scene = CTX_data_scene(C);
tgpi->sa = CTX_wm_area(C);
tgpi->region = CTX_wm_region(C);
@@ -550,15 +538,6 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
tgpi = op->customdata;
}
- /* Enable custom drawing handlers
- * It needs 2 handlers because strokes can in 3d space and screen space
- * and each handler use different coord system
- */
- tgpi->draw_handle_screen = ED_region_draw_cb_activate(
- tgpi->region->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL);
- tgpi->draw_handle_3d = ED_region_draw_cb_activate(
- tgpi->region->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
-
/* set cursor to indicate modal */
WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
@@ -579,8 +558,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
tGPDinterpolate *tgpi = op->customdata;
wmWindow *win = CTX_wm_window(C);
bGPDframe *gpf_dst;
- bGPDstroke *gps_src, *gps_dst;
- tGPDinterpolate_layer *tgpil;
+ bGPDstroke *gps_dst;
const bool has_numinput = hasNumInput(&tgpi->num);
switch (event->type) {
@@ -593,26 +571,22 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
WM_cursor_modal_restore(win);
/* insert keyframes as required... */
- for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
- gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+ LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
+ gpf_dst = BKE_gpencil_layer_frame_get(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
- for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &tgpil->interFrame->strokes) {
if (gps_src->totpoints == 0) {
continue;
}
/* make copy of source stroke, then adjust pointer to points too */
- gps_dst = MEM_dupallocN(gps_src);
- 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);
- }
- gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
- gps_dst->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps_dst);
+
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
}
@@ -973,7 +947,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* loop all layer to check if need interpolation */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
bGPDframe *prevFrame, *nextFrame;
bGPDstroke *gps_from, *gps_to;
int cframe, fFrame;
@@ -983,7 +957,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
continue;
}
/* only editable and visible layers are considered */
- if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
continue;
}
@@ -1017,7 +991,6 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
/* create new strokes data with interpolated points reading original stroke */
for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
- bGPDstroke *new_stroke = NULL;
/* only selected */
if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) &&
@@ -1042,12 +1015,12 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
/* create a new frame if needed */
if (interFrame == NULL) {
- interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
+ interFrame = BKE_gpencil_layer_frame_get(gpl, cframe, GP_GETFRAME_ADD_NEW);
interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
}
/* create new stroke */
- new_stroke = BKE_gpencil_stroke_duplicate(gps_from);
+ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true);
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
@@ -1064,14 +1037,16 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
sizeof(*new_stroke->dvert) * gps_to->totpoints);
}
+
new_stroke->totpoints = gps_to->totpoints;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
}
/* update points position */
gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(new_stroke);
+
/* add to strokes */
BLI_addtail(&interFrame->strokes, new_stroke);
}
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index 91339709162..9a7ad8d7220 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -37,6 +37,7 @@
#include "BKE_gpencil.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_report.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -60,6 +61,7 @@ typedef struct tGPencilPointCache {
float x, y, z;
float pressure;
float strength;
+ float vert_color[4];
} tGPencilPointCache;
/* helper function to sort points */
@@ -93,6 +95,7 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps,
pt_dst->uv_fac = 1.0f;
pt_dst->uv_rot = 0;
pt_dst->flag |= GP_SPOINT_SELECT;
+ copy_v4_v4(pt_dst->vert_color, point_elem->vert_color);
}
}
@@ -113,7 +116,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts);
}
Brush *brush = paint->brush;
@@ -125,25 +128,21 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
else {
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
/* stroke */
bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
gps->totpoints = totpoints;
gps->inittime = 0.0f;
gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+ gps->hardeness = brush->gpencil_settings->hardeness;
+ copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
gps->flag |= GP_STROKE_SELECT;
gps->flag |= GP_STROKE_3DSPACE;
gps->mat_nr = ob->actcol - 1;
/* allocate memory for points */
gps->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, "gp_stroke_points");
- /* initialize triangle memory to dummy data */
- gps->tot_triangles = 0;
- gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
if (cyclic) {
gps->flag |= GP_STROKE_CYCLIC;
@@ -181,17 +180,14 @@ static void gpencil_get_elements_len(bContext *C, int *totstrokes, int *totpoint
static void gpencil_dissolve_points(bContext *C)
{
- bGPDstroke *gps, *gpsn;
-
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *gpf = gpl->actframe;
if (gpf == NULL) {
continue;
}
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
- gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_TAG, false, 0);
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false, 0);
}
}
CTX_DATA_END;
@@ -224,7 +220,7 @@ static void gpencil_calc_points_factor(bContext *C,
if (gpf == NULL) {
continue;
}
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
if (gps->flag & GP_STROKE_SELECT) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (clear_stroke) {
@@ -239,6 +235,7 @@ static void gpencil_calc_points_factor(bContext *C,
copy_v3_v3(&pt2->x, &pt->x);
pt2->pressure = pt->pressure;
pt2->strength = pt->strength;
+ copy_v4_v4(pt2->vert_color, pt->vert_color);
pt->flag &= ~GP_SPOINT_SELECT;
if (clear_point) {
pt->flag |= GP_SPOINT_TAG;
@@ -288,6 +285,7 @@ static void gpencil_calc_points_factor(bContext *C,
copy_v3_v3(&sort_pt->x, &pt2->x);
sort_pt->pressure = pt2->pressure;
sort_pt->strength = pt2->strength;
+ copy_v4_v4(sort_pt->vert_color, pt2->vert_color);
sort_pt->gps = gps_array[i];
@@ -336,6 +334,7 @@ static int gpencil_insert_to_array(tGPencilPointCache *src_array,
dst_elem->pressure = src_elem->pressure;
dst_elem->strength = src_elem->strength;
dst_elem->factor = src_elem->factor;
+ copy_v4_v4(dst_elem->vert_color, src_elem->vert_color);
}
return last;
@@ -458,7 +457,7 @@ static bool gp_strokes_merge_poll(bContext *C)
/* check hidden or locked materials */
MaterialGPencilStyle *gp_style = ma->gp_style;
- if ((gp_style->flag & GP_STYLE_COLOR_HIDE) || (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ if ((gp_style->flag & GP_MATERIAL_HIDE) || (gp_style->flag & GP_MATERIAL_LOCKED)) {
return false;
}
@@ -569,3 +568,100 @@ void GPENCIL_OT_stroke_merge(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "clear_point", 0, "Dissolve Points", "Dissolve old selected points");
RNA_def_boolean(ot->srna, "clear_stroke", 0, "Delete Strokes", "Delete old selected strokes");
}
+
+/* Merge similar materials. */
+static bool gp_stroke_merge_material_poll(bContext *C)
+{
+ /* only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int gp_stroke_merge_material_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const float hue_threshold = RNA_float_get(op->ptr, "hue_threshold");
+ const float sat_threshold = RNA_float_get(op->ptr, "sat_threshold");
+ const float val_threshold = RNA_float_get(op->ptr, "val_threshold");
+
+ /* Review materials. */
+ GHash *mat_table = BLI_ghash_int_new(__func__);
+
+ short *totcol = BKE_object_material_len_p(ob);
+ if (totcol == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bool changed = BKE_gpencil_merge_materials_table_get(
+ ob, hue_threshold, sat_threshold, val_threshold, mat_table);
+
+ int removed = BLI_ghash_len(mat_table);
+
+ /* Update stroke material index. */
+ if (changed) {
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ if (BLI_ghash_haskey(mat_table, POINTER_FROM_INT(gps->mat_nr))) {
+ int *idx = BLI_ghash_lookup(mat_table, POINTER_FROM_INT(gps->mat_nr));
+ gps->mat_nr = POINTER_AS_INT(idx);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* Free hash memory. */
+ BLI_ghash_free(mat_table, NULL, NULL);
+
+ /* notifiers */
+ if (changed) {
+ BKE_reportf(op->reports, RPT_INFO, "Merged %d materiales of %d", removed, *totcol);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+ else {
+ BKE_report(op->reports, RPT_INFO, "Nothing to merge");
+ }
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_merge_material(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Merge Grease Pencil Materials";
+ ot->idname = "GPENCIL_OT_stroke_merge_material";
+ ot->description = "Replace materials in strokes merging similar";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_merge_material_exec;
+ ot->poll = gp_stroke_merge_material_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_float(
+ ot->srna, "hue_threshold", 0.001f, 0.0f, 1.0f, "Hue Threshold", "", 0.0f, 1.0f);
+ prop = RNA_def_float(
+ ot->srna, "sat_threshold", 0.001f, 0.0f, 1.0f, "Saturation Threshold", "", 0.0f, 1.0f);
+ prop = RNA_def_float(
+ ot->srna, "val_threshold", 0.001f, 0.0f, 1.0f, "Value Threshold", "", 0.0f, 1.0f);
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 7a541cd8f03..275075c38db 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -95,6 +95,60 @@ static bool gp_stroke_paintmode_poll_with_tool(bContext *C, const char gpencil_t
WM_toolsystem_active_tool_is_brush(C) && (brush->gpencil_tool == gpencil_tool));
}
+static bool gp_stroke_vertexmode_poll_with_tool(bContext *C, const char gpencil_vertex_tool)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (!gpd) {
+ return false;
+ }
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (!ts || !ts->gp_vertexpaint) {
+ return false;
+ }
+
+ Brush *brush = BKE_paint_brush(&ts->gp_vertexpaint->paint);
+ return ((gpd->flag & GP_DATA_STROKE_VERTEXMODE) && (brush && brush->gpencil_settings) &&
+ WM_toolsystem_active_tool_is_brush(C) &&
+ (brush->gpencil_vertex_tool == gpencil_vertex_tool));
+}
+
+static bool gp_stroke_sculptmode_poll_with_tool(bContext *C, const char gpencil_sculpt_tool)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (!gpd) {
+ return false;
+ }
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (!ts || !ts->gp_sculptpaint) {
+ return false;
+ }
+
+ Brush *brush = BKE_paint_brush(&ts->gp_sculptpaint->paint);
+ return ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) && (brush && brush->gpencil_settings) &&
+ WM_toolsystem_active_tool_is_brush(C) &&
+ (brush->gpencil_sculpt_tool == gpencil_sculpt_tool));
+}
+
+static bool gp_stroke_weightmode_poll_with_tool(bContext *C, const char gpencil_weight_tool)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (!gpd) {
+ return false;
+ }
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ if (!ts || !ts->gp_weightpaint) {
+ return false;
+ }
+
+ Brush *brush = BKE_paint_brush(&ts->gp_weightpaint->paint);
+ return ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) && (brush && brush->gpencil_settings) &&
+ WM_toolsystem_active_tool_is_brush(C) &&
+ (brush->gpencil_weight_tool == gpencil_weight_tool));
+}
+
/* Poll callback for stroke painting (draw brush) */
static bool gp_stroke_paintmode_draw_poll(bContext *C)
{
@@ -113,6 +167,12 @@ static bool gp_stroke_paintmode_fill_poll(bContext *C)
return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_FILL);
}
+/* Poll callback for stroke painting (tint) */
+static bool gp_stroke_paintmode_tint_poll(bContext *C)
+{
+ return gp_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_TINT);
+}
+
/* Poll callback for stroke sculpting mode */
static bool gp_stroke_sculptmode_poll(bContext *C)
{
@@ -125,9 +185,8 @@ static bool gp_stroke_sculptmode_poll(bContext *C)
return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
}
else {
- /* weight paint is a submode of sculpt */
if ((ob) && (ob->type == OB_GPENCIL)) {
- return GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd);
+ return GPENCIL_SCULPT_MODE(gpd);
}
}
@@ -141,12 +200,113 @@ static bool gp_stroke_weightmode_poll(bContext *C)
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL)) {
- return (gpd && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE));
+ return GPENCIL_WEIGHT_MODE(gpd);
}
return 0;
}
+/* Poll callback for stroke vertex paint mode */
+static bool gp_stroke_vertexmode_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = CTX_data_active_object(C);
+
+ if ((ob) && (ob->type == OB_GPENCIL)) {
+ return (gpd && (gpd->flag & GP_DATA_STROKE_VERTEXMODE));
+ }
+
+ return 0;
+}
+
+/* Poll callback for vertex painting (draw) */
+static bool gp_stroke_vertexmode_draw_poll(bContext *C)
+{
+ return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_DRAW);
+}
+
+/* Poll callback for vertex painting (blur) */
+static bool gp_stroke_vertexmode_blur_poll(bContext *C)
+{
+ return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_BLUR);
+}
+
+/* Poll callback for vertex painting (average) */
+static bool gp_stroke_vertexmode_average_poll(bContext *C)
+{
+ return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_AVERAGE);
+}
+
+/* Poll callback for vertex painting (smear) */
+static bool gp_stroke_vertexmode_smear_poll(bContext *C)
+{
+ return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_SMEAR);
+}
+
+/* Poll callback for vertex painting (replace) */
+static bool gp_stroke_vertexmode_replace_poll(bContext *C)
+{
+ return gp_stroke_vertexmode_poll_with_tool(C, GPVERTEX_TOOL_REPLACE);
+}
+
+/* Poll callback for sculpt (Smooth) */
+static bool gp_stroke_sculptmode_smooth_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_SMOOTH);
+}
+/* Poll callback for sculpt (Thickness) */
+static bool gp_stroke_sculptmode_thickness_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_THICKNESS);
+}
+
+/* Poll callback for sculpt (Strength) */
+static bool gp_stroke_sculptmode_strength_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_STRENGTH);
+}
+
+/* Poll callback for sculpt (Grab) */
+static bool gp_stroke_sculptmode_grab_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_GRAB);
+}
+
+/* Poll callback for sculpt (Push) */
+static bool gp_stroke_sculptmode_push_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_PUSH);
+}
+
+/* Poll callback for sculpt (Twist) */
+static bool gp_stroke_sculptmode_twist_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_TWIST);
+}
+
+/* Poll callback for sculpt (Pinch) */
+static bool gp_stroke_sculptmode_pinch_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_PINCH);
+}
+/* Poll callback for sculpt (Randomize) */
+static bool gp_stroke_sculptmode_randomize_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_RANDOMIZE);
+}
+
+/* Poll callback for sculpt (Clone) */
+static bool gp_stroke_sculptmode_clone_poll(bContext *C)
+{
+ return gp_stroke_sculptmode_poll_with_tool(C, GPSCULPT_TOOL_CLONE);
+}
+
+/* Poll callback for weight paint (Draw) */
+static bool gp_stroke_weightmode_draw_poll(bContext *C)
+{
+ return gp_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_DRAW);
+}
+
/* Stroke Editing Keymap - Only when editmode is enabled */
static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
{
@@ -177,6 +337,13 @@ static void ed_keymap_gpencil_painting_fill(wmKeyConfig *keyconf)
keymap->poll = gp_stroke_paintmode_fill_poll;
}
+/* keys for draw with a tint brush */
+static void ed_keymap_gpencil_painting_tint(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Paint (Tint)", 0, 0);
+ keymap->poll = gp_stroke_paintmode_tint_poll;
+}
+
/* Stroke Painting Keymap - Only when paintmode is enabled */
static void ed_keymap_gpencil_painting(wmKeyConfig *keyconf)
{
@@ -200,6 +367,106 @@ static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf)
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight Mode", 0, 0);
keymap->poll = gp_stroke_weightmode_poll;
}
+
+static void ed_keymap_gpencil_vertexpainting(wmKeyConfig *keyconf)
+{
+ /* set poll callback - so that this keymap only gets enabled when stroke vertex is enabled */
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex Mode", 0, 0);
+ keymap->poll = gp_stroke_vertexmode_poll;
+}
+
+/* keys for vertex with a draw brush */
+static void ed_keymap_gpencil_vertexpainting_draw(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Draw)", 0, 0);
+ keymap->poll = gp_stroke_vertexmode_draw_poll;
+}
+
+/* keys for vertex with a blur brush */
+static void ed_keymap_gpencil_vertexpainting_blur(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Blur)", 0, 0);
+ keymap->poll = gp_stroke_vertexmode_blur_poll;
+}
+/* keys for vertex with a average brush */
+static void ed_keymap_gpencil_vertexpainting_average(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Average)", 0, 0);
+ keymap->poll = gp_stroke_vertexmode_average_poll;
+}
+/* keys for vertex with a smear brush */
+static void ed_keymap_gpencil_vertexpainting_smear(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Smear)", 0, 0);
+ keymap->poll = gp_stroke_vertexmode_smear_poll;
+}
+/* keys for vertex with a replace brush */
+static void ed_keymap_gpencil_vertexpainting_replace(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Vertex (Replace)", 0, 0);
+ keymap->poll = gp_stroke_vertexmode_replace_poll;
+}
+/* keys for sculpt with a smooth brush */
+static void ed_keymap_gpencil_sculptpainting_smooth(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Smooth)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_smooth_poll;
+}
+/* keys for sculpt with a thickness brush */
+static void ed_keymap_gpencil_sculptpainting_thickness(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Thickness)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_thickness_poll;
+}
+/* keys for sculpt with a strength brush */
+static void ed_keymap_gpencil_sculptpainting_strength(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Strength)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_strength_poll;
+}
+/* keys for sculpt with a grab brush */
+static void ed_keymap_gpencil_sculptpainting_grab(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Grab)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_grab_poll;
+}
+/* keys for sculpt with a push brush */
+static void ed_keymap_gpencil_sculptpainting_push(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Push)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_push_poll;
+}
+/* keys for sculpt with a twist brush */
+static void ed_keymap_gpencil_sculptpainting_twist(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Twist)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_twist_poll;
+}
+/* keys for sculpt with a pinch brush */
+static void ed_keymap_gpencil_sculptpainting_pinch(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Pinch)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_pinch_poll;
+}
+/* keys for sculpt with a randomize brush */
+static void ed_keymap_gpencil_sculptpainting_randomize(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Randomize)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_randomize_poll;
+}
+/* keys for sculpt with a clone brush */
+static void ed_keymap_gpencil_sculptpainting_clone(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Sculpt (Clone)", 0, 0);
+ keymap->poll = gp_stroke_sculptmode_clone_poll;
+}
+/* keys for weight with a draw brush */
+static void ed_keymap_gpencil_weightpainting_draw(wmKeyConfig *keyconf)
+{
+ wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Draw)", 0, 0);
+ keymap->poll = gp_stroke_weightmode_draw_poll;
+}
+
/* ==================== */
void ED_keymap_gpencil(wmKeyConfig *keyconf)
@@ -210,8 +477,25 @@ void ED_keymap_gpencil(wmKeyConfig *keyconf)
ed_keymap_gpencil_painting_draw(keyconf);
ed_keymap_gpencil_painting_erase(keyconf);
ed_keymap_gpencil_painting_fill(keyconf);
+ ed_keymap_gpencil_painting_tint(keyconf);
ed_keymap_gpencil_sculpting(keyconf);
+ ed_keymap_gpencil_sculptpainting_smooth(keyconf);
+ ed_keymap_gpencil_sculptpainting_thickness(keyconf);
+ ed_keymap_gpencil_sculptpainting_strength(keyconf);
+ ed_keymap_gpencil_sculptpainting_grab(keyconf);
+ ed_keymap_gpencil_sculptpainting_push(keyconf);
+ ed_keymap_gpencil_sculptpainting_twist(keyconf);
+ ed_keymap_gpencil_sculptpainting_pinch(keyconf);
+ ed_keymap_gpencil_sculptpainting_randomize(keyconf);
+ ed_keymap_gpencil_sculptpainting_clone(keyconf);
ed_keymap_gpencil_weightpainting(keyconf);
+ ed_keymap_gpencil_weightpainting_draw(keyconf);
+ ed_keymap_gpencil_vertexpainting(keyconf);
+ ed_keymap_gpencil_vertexpainting_draw(keyconf);
+ ed_keymap_gpencil_vertexpainting_blur(keyconf);
+ ed_keymap_gpencil_vertexpainting_average(keyconf);
+ ed_keymap_gpencil_vertexpainting_smear(keyconf);
+ ed_keymap_gpencil_vertexpainting_replace(keyconf);
}
/* ****************************************** */
@@ -226,6 +510,12 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_draw);
WM_operatortype_append(GPENCIL_OT_fill);
+ WM_operatortype_append(GPENCIL_OT_vertex_paint);
+ WM_operatortype_append(GPENCIL_OT_vertex_color_brightness_contrast);
+ WM_operatortype_append(GPENCIL_OT_vertex_color_hsv);
+ WM_operatortype_append(GPENCIL_OT_vertex_color_invert);
+ WM_operatortype_append(GPENCIL_OT_vertex_color_levels);
+ WM_operatortype_append(GPENCIL_OT_vertex_color_set);
/* Guides ----------------------- */
@@ -238,6 +528,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_paintmode_toggle);
WM_operatortype_append(GPENCIL_OT_sculptmode_toggle);
WM_operatortype_append(GPENCIL_OT_weightmode_toggle);
+ WM_operatortype_append(GPENCIL_OT_vertexmode_toggle);
WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle);
WM_operatortype_append(GPENCIL_OT_select);
@@ -253,6 +544,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_select_first);
WM_operatortype_append(GPENCIL_OT_select_last);
WM_operatortype_append(GPENCIL_OT_select_alternate);
+ WM_operatortype_append(GPENCIL_OT_select_color);
WM_operatortype_append(GPENCIL_OT_duplicate);
WM_operatortype_append(GPENCIL_OT_delete);
@@ -263,6 +555,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_move_to_layer);
WM_operatortype_append(GPENCIL_OT_layer_change);
+ WM_operatortype_append(GPENCIL_OT_layer_active);
WM_operatortype_append(GPENCIL_OT_set_active_material);
@@ -271,8 +564,10 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
WM_operatortype_append(GPENCIL_OT_reproject);
+ WM_operatortype_append(GPENCIL_OT_recalc_geometry);
WM_operatortype_append(GPENCIL_OT_sculpt_paint);
+ WM_operatortype_append(GPENCIL_OT_weight_paint);
/* Editing (Buttons) ------------ */
@@ -288,6 +583,9 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_duplicate);
WM_operatortype_append(GPENCIL_OT_layer_duplicate_object);
+ WM_operatortype_append(GPENCIL_OT_layer_mask_add);
+ WM_operatortype_append(GPENCIL_OT_layer_mask_remove);
+
WM_operatortype_append(GPENCIL_OT_hide);
WM_operatortype_append(GPENCIL_OT_reveal);
WM_operatortype_append(GPENCIL_OT_lock_all);
@@ -306,6 +604,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_convert);
+ WM_operatortype_append(GPENCIL_OT_image_to_grease_pencil);
+
WM_operatortype_append(GPENCIL_OT_stroke_arrange);
WM_operatortype_append(GPENCIL_OT_stroke_change_color);
WM_operatortype_append(GPENCIL_OT_stroke_lock_color);
@@ -325,8 +625,16 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_stroke_cutter);
WM_operatortype_append(GPENCIL_OT_stroke_trim);
WM_operatortype_append(GPENCIL_OT_stroke_merge_by_distance);
+ WM_operatortype_append(GPENCIL_OT_stroke_merge_material);
+
+ WM_operatortype_append(GPENCIL_OT_material_to_vertex_color);
+ WM_operatortype_append(GPENCIL_OT_extract_palette_vertex);
+
+ WM_operatortype_append(GPENCIL_OT_transform_fill);
+ WM_operatortype_append(GPENCIL_OT_reset_transform_fill);
- WM_operatortype_append(GPENCIL_OT_brush_presets_create);
+ WM_operatortype_append(GPENCIL_OT_brush_reset);
+ WM_operatortype_append(GPENCIL_OT_brush_reset_all);
/* vertex groups */
WM_operatortype_append(GPENCIL_OT_vertex_group_assign);
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index 3d56cb0fcb1..e5b9d902210 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -130,7 +130,6 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
copy_v4_v4(gp_style->fill_rgba, palcolor->fill);
/* set basic settings */
- 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);
@@ -138,13 +137,13 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
gp_style->texture_opacity = 1.0f;
gp_style->texture_pixsize = 100.0f;
- gp_style->flag |= GP_STYLE_STROKE_SHOW;
- gp_style->flag |= GP_STYLE_FILL_SHOW;
+ gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ gp_style->flag |= GP_MATERIAL_FILL_SHOW;
/* fix strokes */
- 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->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) {
gps->mat_nr = ob->totcol - 1;
gps->colorname[0] = '\0';
@@ -174,7 +173,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor;
palcolor = palcolor->next) {
/* fix layers */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* unlock/unhide layer */
gpl->flag &= ~GP_LAYER_LOCKED;
gpl->flag &= ~GP_LAYER_HIDE;
@@ -182,8 +181,8 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
gpl->opacity = 1.0f;
/* disable tint */
gpl->tintcolor[3] = 0.0f;
- 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) {
if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) {
/* copy color settings */
copy_v4_v4(gpl->color, palcolor->color);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index afc0e66a8a6..fea589746c4 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -149,6 +149,8 @@ typedef struct tGPsdata {
/** current object. */
Object *ob;
+ /** Obeject eval. */
+ Object *ob_eval;
/** window where painting originated. */
wmWindow *win;
/** area where painting originated. */
@@ -215,6 +217,8 @@ typedef struct tGPsdata {
float imat[4][4];
float mat[4][4];
+ float diff_mat[4][4];
+
/** custom color - hack for enforcing a particular color for track/mask editing. */
float custom_color[4];
@@ -270,11 +274,6 @@ static void gp_update_cache(bGPdata *gpd)
}
}
-static bool gp_stroke_added_check(tGPsdata *p)
-{
- return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
-}
-
static void gp_stroke_added_enable(tGPsdata *p)
{
BLI_assert(p->gpf->strokes.last != NULL);
@@ -353,7 +352,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3])
if (p->ownerPtr.type == &RNA_Object) {
ob = (Object *)p->ownerPtr.data;
}
- ED_gp_get_drawing_reference(p->scene, ob, p->gpl, *p->align_flag, vec);
+ ED_gpencil_drawing_reference_get(p->scene, ob, p->gpl, *p->align_flag, vec);
}
/* Stroke Editing ---------------------------- */
@@ -483,49 +482,26 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
}
}
-/* apply jitter to stroke */
-static void gp_brush_jitter(bGPdata *gpd,
- Brush *brush,
- tGPspoint *pt,
- const float mval[2],
- const float pressure,
- float r_mval[2],
- RNG *rng)
+/* Apply jitter to stroke point. */
+static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude)
{
- float tmp_pressure = pressure;
- if (brush->gpencil_settings->draw_jitter > 0.0f) {
- float curvef = BKE_curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, pressure);
- tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- }
- /* exponential value */
- const float exfactor = (brush->gpencil_settings->draw_jitter + 2.0f) *
- (brush->gpencil_settings->draw_jitter + 2.0f);
- const float fac = BLI_rng_get_float(rng) * exfactor * tmp_pressure;
- /* Jitter is applied perpendicular to the mouse movement vector (2D space) */
- float mvec[2], svec[2];
- /* mouse movement in ints -> floats */
+ /* Jitter is applied perpendicular to the mouse movement vector (2D space). */
+ float mvec[2];
+ /* Mouse movement in ints -> floats. */
if (gpd->runtime.sbuffer_used > 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ tGPspoint *pt_prev = pt - 1;
+ sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
normalize_v2(mvec);
}
else {
mvec[0] = 0.0f;
mvec[1] = 0.0f;
}
- /* rotate mvec by 90 degrees... */
- svec[0] = -mvec[1];
- svec[1] = mvec[0];
- /* scale the displacement by the random, and apply */
- if (BLI_rng_get_float(rng) > 0.5f) {
- mul_v2_fl(svec, -fac);
- }
- else {
- mul_v2_fl(svec, fac);
- }
-
- r_mval[0] = mval[0] + svec[0];
- r_mval[1] = mval[1] + svec[1];
+ /* Rotate mvec by 90 degrees... */
+ SWAP(float, mvec[0], mvec[1]);
+ mvec[0] -= mvec[0];
+ /* Scale by displacement amount, and apply. */
+ madd_v2_v2fl(&pt->x, mvec, amplitude);
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
@@ -581,6 +557,7 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
{
bGPdata *gpd = p->gpd;
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
const short num_points = gpd->runtime.sbuffer_used;
/* Do nothing if not enough points to smooth out */
@@ -628,9 +605,12 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
strength += ptd->strength * average_fac;
}
- /* Based on influence factor, blend between original and optimal smoothed coordinate. */
- interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ /* Based on influence factor, blend between original and optimal smoothed coordinate but not
+ * for Guide mode. */
+ if (!guide->use_guide) {
+ interp_v2_v2v2(c, c, sco, inf);
+ copy_v2_v2(&ptc->x, c);
+ }
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
/* Interpolate strength. */
@@ -661,140 +641,59 @@ static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int t
tGPspoint *ptd = &points[i];
float sco[2] = {0.0f};
+ float pressure = 0.0f;
+ float strength = 0.0f;
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
madd_v2_v2fl(sco, &pta->x, average_fac);
+ pressure += pta->pressure * average_fac;
+ strength += pta->strength * average_fac;
}
else {
madd_v2_v2fl(sco, &ptc->x, average_fac);
+ pressure += ptc->pressure * average_fac;
+ strength += ptc->strength * average_fac;
}
if (ptb) {
madd_v2_v2fl(sco, &ptb->x, average_fac);
+ pressure += ptb->pressure * average_fac;
+ strength += ptb->strength * average_fac;
}
else {
madd_v2_v2fl(sco, &ptc->x, average_fac);
+ pressure += ptc->pressure * average_fac;
+ strength += ptc->strength * average_fac;
}
madd_v2_v2fl(sco, &ptc->x, average_fac);
+ pressure += ptc->pressure * average_fac;
+ strength += ptc->strength * average_fac;
madd_v2_v2fl(sco, &ptd->x, average_fac);
+ pressure += ptd->pressure * average_fac;
+ strength += ptd->strength * average_fac;
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
- }
-}
-
-/* Smooth all the sections created with fake events to avoid abrupt transitions.
- *
- * As the fake events add points between two real events, this produces a straight line, but if
- * there is 3 or more real points that used fakes, the stroke is not smooth and produces abrupt
- * angles.
- * This function reads these segments and finds the real points and smooth with the surrounding
- * points. */
-static void gp_smooth_fake_segments(tGPsdata *p)
-{
- bGPdata *gpd = p->gpd;
- Brush *brush = p->brush;
- if (brush->gpencil_settings->input_samples < 2) {
- return;
- }
-
- tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
- tGPspoint *pt = NULL;
- /* Index where segment starts. */
- int from_idx = 0;
- /* Index where segment ends. */
- int to_idx = 0;
-
- bool doit = false;
- /* Loop all points except the extremes. */
- for (int i = 1; i < gpd->runtime.sbuffer_used - 1; i++) {
- pt = &points[i];
- bool is_fake = (bool)(pt->tflag & GP_TPOINT_FAKE);
- to_idx = i;
-
- /* Detect fake points in the stroke. */
- if ((!doit) && (is_fake)) {
- from_idx = i;
- doit = true;
- }
- /* If detect control point after fake points, select a segment with same length in both sides,
- * except if it is more than stroke length. */
- if ((doit) && (!is_fake)) {
- if (i + (i - from_idx) < gpd->runtime.sbuffer_used - 1) {
- to_idx = i + (i - from_idx);
- /* Smooth this segments (need loop to get cumulative smooth). */
- for (int r = 0; r < 5; r++) {
- gp_smooth_segment(gpd, 0.1f, from_idx, to_idx);
- }
- }
- else {
- break;
- }
- /* Reset to new segments. */
- from_idx = i;
- doit = false;
- }
- }
-}
-
-/* Smooth the section added with fake events when pen moves very fast. */
-static void gp_smooth_fake_events(tGPsdata *p, int size_before, int size_after)
-{
- bGPdata *gpd = p->gpd;
- const short totpoints = size_after - size_before - 1;
- /* Do nothing if not enough data to smooth out. */
- if (totpoints < 1) {
- return;
- }
-
- /* Back two points to get smoother effect. */
- size_before -= 2;
- CLAMP_MIN(size_before, 1);
-
- tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
- /* Extreme points. */
- const tGPspoint *pta = &points[size_before - 1];
- const tGPspoint *ptb = &points[size_after - 1];
- tGPspoint *pt1, *pt2;
- int i;
-
- /* Get total length of the segment to smooth. */
- float totlen = 0.0f;
- for (i = size_before; i < size_after; i++) {
- pt1 = &points[i - 1];
- pt2 = &points[i];
- totlen += len_v2v2(&pt1->x, &pt2->x);
- }
- /* Smooth interpolating the position of the points. */
- float pointlen = 0.0f;
- for (i = size_before; i < size_after - 1; i++) {
- pt1 = &points[i - 1];
- pt2 = &points[i];
- pointlen += len_v2v2(&pt1->x, &pt2->x);
- pt2->pressure = interpf(ptb->pressure, pta->pressure, pointlen / totlen);
- pt2->strength = interpf(ptb->strength, pta->strength, pointlen / totlen);
+ /* Interpolate pressure. */
+ ptc->pressure = interpf(ptc->pressure, pressure, inf);
+ /* Interpolate strength. */
+ ptc->strength = interpf(ptc->strength, strength, inf);
}
}
/* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(
- tGPsdata *p, const float mval[2], float pressure, double curtime, bool is_fake)
+static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
bGPdata *gpd = p->gpd;
Brush *brush = p->brush;
+ BrushGpencilSettings *brush_settings = p->brush->gpencil_settings;
tGPspoint *pt;
- ToolSettings *ts = p->scene->toolsettings;
Object *obact = (Object *)p->ownerPtr.data;
- Depsgraph *depsgraph = p->depsgraph;
RegionView3D *rv3d = p->region->regiondata;
- View3D *v3d = p->sa->spacedata.first;
- MaterialGPencilStyle *gp_style = p->material->gp_style;
- const int def_nr = obact->actdef - 1;
- const bool have_weight = (bool)BLI_findlink(&obact->defbase, def_nr);
/* check painting mode */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
@@ -843,111 +742,73 @@ static short gp_stroke_addpoint(
return GP_STROKEADD_INVALID;
}
+ /* Set vertex colors for buffer. */
+ ED_gpencil_sbuffer_vertex_color_set(
+ p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material);
+
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
- /* Set if point was created by fake events. */
- if (is_fake) {
- pt->tflag |= GP_TPOINT_FAKE;
- }
- else {
- pt->tflag &= ~GP_TPOINT_FAKE;
- }
-
/* store settings */
+ pt->strength = brush_settings->draw_strength;
+ pt->pressure = 1.0f;
+ pt->uv_rot = 0.0f;
+ copy_v2_v2(&pt->x, mval);
+
/* pressure */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
- float curvef = BKE_curvemapping_evaluateF(
- brush->gpencil_settings->curve_sensitivity, 0, pressure);
- pt->pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- }
- else {
- pt->pressure = 1.0f;
+ if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ pt->pressure *= BKE_curvemapping_evaluateF(brush_settings->curve_sensitivity, 0, pressure);
}
- /* Apply jitter to position */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_jitter > 0.0f)) {
- float r_mval[2];
- const float jitpress = (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) ?
- pressure :
- 1.0f;
- gp_brush_jitter(gpd, brush, pt, mval, jitpress, r_mval, p->rng);
- copy_v2_v2(&pt->x, r_mval);
- }
- else {
- copy_v2_v2(&pt->x, mval);
+ /* color strength */
+ if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ pt->strength *= BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, pressure);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
- /* apply randomness to pressure */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_press > 0.0f)) {
- float curvef = BKE_curvemapping_evaluateF(
- brush->gpencil_settings->curve_sensitivity, 0, pressure);
- float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
- if (BLI_rng_get_float(p->rng) > 0.5f) {
- pt->pressure -= tmp_pressure * brush->gpencil_settings->draw_random_press *
- BLI_rng_get_float(p->rng);
+
+ if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
+ /* Apply jitter to position */
+ if (brush_settings->draw_jitter > 0.0f) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ float jitpress = 1.0f;
+ if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
+ jitpress = BKE_curvemapping_evaluateF(brush_settings->curve_jitter, 0, pressure);
+ }
+ /* FIXME the +2 means minimum jitter is 4 which is a bit strange for UX. */
+ const float exp_factor = brush_settings->draw_jitter + 2.0f;
+ const float fac = rand * square_f(exp_factor) * jitpress;
+ gp_brush_jitter(gpd, pt, fac);
}
- else {
- pt->pressure += tmp_pressure * brush->gpencil_settings->draw_random_press *
- BLI_rng_get_float(p->rng);
+ /* apply randomness to pressure */
+ if (brush_settings->draw_random_press > 0.0f) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ pt->pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press;
+ CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
}
- CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
- }
-
- /* apply randomness to uv texture rotation */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->uv_random > 0.0f)) {
- if (BLI_rng_get_float(p->rng) > 0.5f) {
- pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI * -1) * brush->gpencil_settings->uv_random;
+ /* apply randomness to uv texture rotation */
+ if (brush_settings->uv_random > 0.0f) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ pt->uv_rot += rand * M_PI * brush_settings->uv_random;
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
}
- else {
- pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI) * brush->gpencil_settings->uv_random;
+ /* apply randomness to color strength */
+ if (brush_settings->draw_random_strength) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ pt->strength *= 1.0 + rand * brush_settings->draw_random_strength;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
- CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
- }
- else {
- pt->uv_rot = 0.0f;
}
/* apply angle of stroke to brush size */
- if (brush->gpencil_settings->draw_angle_factor != 0.0f) {
+ if (brush_settings->draw_angle_factor != 0.0f) {
gp_brush_angle(gpd, brush, pt, mval);
}
- /* color strength */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- float curvef = BKE_curvemapping_evaluateF(
- brush->gpencil_settings->curve_strength, 0, pressure);
- float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity;
-
- pt->strength = tmp_pressure * brush->gpencil_settings->draw_strength;
- }
- else {
- pt->strength = brush->gpencil_settings->draw_strength;
- }
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
-
- /* apply randomness to color strength */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_strength > 0.0f)) {
- if (BLI_rng_get_float(p->rng) > 0.5f) {
- pt->strength -= pt->strength * brush->gpencil_settings->draw_random_strength *
- BLI_rng_get_float(p->rng);
- }
- else {
- pt->strength += pt->strength * brush->gpencil_settings->draw_random_strength *
- BLI_rng_get_float(p->rng);
- }
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- }
-
/* point time */
pt->time = (float)(curtime - p->inittime);
/* point uv (only 3d view) */
if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
- float pixsize = gp_style->texture_pixsize / 1000000.0f;
tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
bGPDspoint spt, spt2;
@@ -961,11 +822,8 @@ static short gp_stroke_addpoint(
/* reproject previous */
ED_gpencil_tpoint_to_point(p->region, origin, ptb, &spt2);
ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2);
- p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
+ p->totpixlen += len_v3v3(&spt.x, &spt2.x);
pt->uv_fac = p->totpixlen;
- if ((gp_style) && (gp_style->sima)) {
- pt->uv_fac /= gp_style->sima->gen_x;
- }
}
else {
p->totpixlen = 0.0f;
@@ -975,7 +833,7 @@ static short gp_stroke_addpoint(
/* increment counters */
gpd->runtime.sbuffer_used++;
- /* smooth while drawing previous points with a reduction factor for previous */
+ /* Smooth while drawing previous points with a reduction factor for previous. */
if (brush->gpencil_settings->active_smooth > 0.0f) {
for (int s = 0; s < 3; s++) {
gp_smooth_buffer(p,
@@ -984,100 +842,11 @@ static short gp_stroke_addpoint(
}
}
- return GP_STROKEADD_NORMAL;
- }
- else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
-
- /* enable special flag for drawing engine */
- gpd->flag |= GP_DATA_STROKE_POLYGON;
-
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- /* get pointer to destination point */
- pt = (tGPspoint *)(gpd->runtime.sbuffer);
-
- /* store settings */
- copy_v2_v2(&pt->x, mval);
- /* T44932 - Pressure vals are unreliable, so ignore for now */
- pt->pressure = 1.0f;
- pt->strength = 1.0f;
- pt->time = (float)(curtime - p->inittime);
-
- /* if there's stroke for this poly line session add (or replace last) point
- * to stroke. This allows to draw lines more interactively (see new segment
- * during mouse slide, e.g.)
- */
- if (gp_stroke_added_check(p)) {
- bGPDstroke *gps = p->gpf->strokes.last;
- bGPDspoint *pts;
- MDeformVert *dvert = NULL;
-
- /* First time point is adding to temporary buffer (need to allocate new point in stroke) */
- if (gpd->runtime.sbuffer_used == 0) {
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- if (gps->dvert != NULL) {
- gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
- }
- gps->totpoints++;
- }
-
- pts = &gps->points[gps->totpoints - 1];
- if (gps->dvert != NULL) {
- dvert = &gps->dvert[gps->totpoints - 1];
- }
- /* special case for poly lines: normally,
- * depth is needed only when creating new stroke from buffer,
- * but poly lines are converting to stroke instantly,
- * so initialize depth buffer before converting coordinates
- */
- if (gpencil_project_check(p)) {
- view3d_region_operator_needs_opengl(p->win, p->region);
- ED_view3d_autodist_init(p->depsgraph,
- p->region,
- v3d,
- (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
- }
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
- /* reproject to plane (only in 3d space) */
- gp_reproject_toplane(p, gps);
- /* if parented change position relative to parent object */
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pts);
- /* copy pressure and time */
- pts->pressure = pt->pressure;
- pts->strength = pt->strength;
- pts->time = pt->time;
- pts->uv_fac = pt->uv_fac;
- pts->uv_rot = pt->uv_rot;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- }
- }
-
- /* force fill recalc */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- /* drawing batch cache is dirty now */
- gp_update_cache(p->gpd);
- }
-
- /* increment counters */
- if (gpd->runtime.sbuffer_used == 0) {
- gpd->runtime.sbuffer_used++;
- }
+ /* Update evaluated data. */
+ ED_gpencil_sbuffer_update_eval(gpd, p->ob_eval);
return GP_STROKEADD_NORMAL;
}
-
/* return invalid state for now... */
return GP_STROKEADD_INVALID;
}
@@ -1143,42 +912,25 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
return;
}
- /* special case for poly line -- for already added stroke during session
- * coordinates are getting added to stroke immediately to allow more
- * interactive behavior
- */
- if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
- /* be sure to hide any lazy cursor */
- ED_gpencil_toggle_brush_cursor(p->C, true, NULL);
-
- if (gp_stroke_added_check(p)) {
- return;
- }
- }
-
/* allocate memory for a new stroke */
gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
/* copy appropriate settings for stroke */
gps->totpoints = totelem;
gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
+ gps->fill_opacity_fac = 1.0f;
+ gps->hardeness = brush->gpencil_settings->hardeness;
+ copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
gps->flag = gpd->runtime.sbuffer_sflag;
gps->inittime = p->inittime;
-
- /* enable recalculation flag by default (only used if hq fill) */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->uv_scale = 1.0f;
/* allocate enough memory for a continuous array for storage points */
const int subdivide = brush->gpencil_settings->draw_subdivide;
gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ gps->dvert = NULL;
- /* initialize triangle memory to dummy data */
- gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
/* drawing batch cache is dirty now */
gp_update_cache(p->gpd);
/* set pointer to first non-initialized point */
@@ -1187,6 +939,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
dvert = gps->dvert + (gps->totpoints - totelem);
}
+ /* Apply the vertex color to fill. */
+ ED_gpencil_fill_vertex_color_set(ts, brush, gps);
+
/* copy points from the buffer to the stroke */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only -> only endpoints */
@@ -1201,6 +956,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+ /* Apply the vertex color to point. */
+ ED_gpencil_point_vertex_color_set(ts, brush, pt);
+
pt++;
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
@@ -1231,6 +989,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+ /* Apply the vertex color to point. */
+ ED_gpencil_point_vertex_color_set(ts, brush, pt);
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
BKE_gpencil_dvert_ensure(gps);
@@ -1252,7 +1012,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt = gps->points;
for (i = 0; i < gps->totpoints; i++, pt++) {
/* if parented change position relative to parent object */
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
+ gp_apply_parent_point(depsgraph, obact, gpl, pt);
}
/* if camera view, reproject flat to view to avoid perspective effect */
@@ -1260,40 +1020,6 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
}
}
- else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
- /* first point */
- ptc = gpd->runtime.sbuffer;
-
- /* convert screen-coordinates to appropriate coordinates (and store them) */
- gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* reproject to plane (only in 3d space) */
- gp_reproject_toplane(p, gps);
- /* if parented change position relative to parent object */
- gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt);
- /* if camera view, reproject flat to view to avoid perspective effect */
- if (is_camera) {
- ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
- }
- /* copy pressure and time */
- pt->pressure = ptc->pressure;
- pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- pt->time = ptc->time;
-
- if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
- BKE_gpencil_dvert_ensure(gps);
- MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr);
- if (dw) {
- dw->weight = ts->vgroup_weight;
- }
- }
- else {
- if (dvert != NULL) {
- dvert->totweight = 0;
- dvert->dw = NULL;
- }
- }
- }
else {
float *depth_arr = NULL;
@@ -1370,9 +1096,6 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
}
- /* Smooth any point created with fake events when the mouse/pen move very fast. */
- gp_smooth_fake_segments(p);
-
pt = gps->points;
dvert = gps->dvert;
@@ -1389,6 +1112,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->time = ptc->time;
pt->uv_fac = ptc->uv_fac;
pt->uv_rot = ptc->uv_rot;
+ /* Apply the vertex color to point. */
+ ED_gpencil_point_vertex_color_set(ts, brush, pt);
if (dvert != NULL) {
dvert->totweight = 0;
@@ -1401,11 +1126,6 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) {
gp_subdivide_stroke(gps, subdivide);
}
- /* apply randomness to stroke */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_sub > 0.0f)) {
- gp_randomize_stroke(gps, brush, p->rng);
- }
/* Smooth stroke after subdiv - only if there's something to do for each iteration,
* the factor is reduced to get a better smoothing
@@ -1415,8 +1135,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
float reduce = 0.0f;
for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_smooth_stroke(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
- BKE_gpencil_smooth_stroke_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
+ BKE_gpencil_stroke_smooth(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; /* reduce the factor */
}
@@ -1425,23 +1145,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* Simplify adaptive */
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
(brush->gpencil_settings->simplify_f > 0.0f)) {
- BKE_gpencil_simplify_stroke(gps, brush->gpencil_settings->simplify_f);
- }
-
- /* smooth thickness */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
- (brush->gpencil_settings->thick_smoothfac > 0.0f)) {
- for (int r = 0; r < brush->gpencil_settings->thick_smoothlvl * 2; r++) {
- for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_smooth_stroke_thickness(gps, i, brush->gpencil_settings->thick_smoothfac);
- }
- }
+ BKE_gpencil_stroke_simplify_adaptive(gps, brush->gpencil_settings->simplify_f);
}
/* reproject to plane (only in 3d space) */
gp_reproject_toplane(p, gps);
/* change position relative to parent object */
- gp_apply_parent(depsgraph, obact, gpd, gpl, gps);
+ gp_apply_parent(depsgraph, obact, gpl, gps);
/* if camera view, reproject flat to view to avoid perspective effect */
if (is_camera) {
ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
@@ -1463,15 +1173,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
}
- /* calculate UVs along the stroke */
- ED_gpencil_calc_stroke_uv(obact, gps);
-
/* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke
* is added on listbase head because the drawing order is inverse and the head stroke is the
* first to draw. This is very useful for artist when drawing the background.
*/
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
- (p->paintmode != GP_PAINTMODE_DRAW_POLY)) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) {
BLI_addhead(&p->gpf->strokes, gps);
}
else {
@@ -1492,9 +1198,12 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* post process stroke */
if ((p->brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
p->brush->gpencil_settings->flag & GP_BRUSH_TRIM_STROKE) {
- BKE_gpencil_trim_stroke(gps);
+ BKE_gpencil_stroke_trim(gps);
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+
gp_stroke_added_enable(p);
}
@@ -1540,7 +1249,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
float diff_mat[4][4];
/* calculate difference matrix if parent object */
- ED_gpencil_parent_location(p->depsgraph, obact, p->gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(p->depsgraph, obact, gpl, diff_mat);
if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) {
const float depth_mval = view3d_point_depth(rv3d, mval_3d);
@@ -1642,9 +1351,7 @@ static void gp_stroke_soft_refine(bGPDstroke *gps)
}
/* eraser tool - evaluation per stroke */
-/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
static void gp_stroke_eraser_dostroke(tGPsdata *p,
- bGPDlayer *gpl,
bGPDframe *gpf,
bGPDstroke *gps,
const float mval[2],
@@ -1652,21 +1359,15 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
const int radius,
const rcti *rect)
{
- Depsgraph *depsgraph = p->depsgraph;
- Object *obact = (Object *)p->ownerPtr.data;
Brush *eraser = p->eraser;
bGPDspoint *pt0, *pt1, *pt2;
int pc0[2] = {0};
int pc1[2] = {0};
int pc2[2] = {0};
int i;
- float diff_mat[4][4];
int mval_i[2];
round_v2i_v2fl(mval_i, mval);
- /* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, p->gpd, gpl, diff_mat);
-
if (gps->totpoints == 0) {
/* just free stroke */
gp_free_stroke(p->gpd, gpf, gps);
@@ -1675,7 +1376,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* only process if it hasn't been masked out... */
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_parent_space(gps->points, p->diff_mat, &pt_temp);
gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
@@ -1699,7 +1400,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* get points to work with */
pt1 = gps->points + i;
bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_parent_space(pt1, p->diff_mat, &npt);
gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
/* do boundbox check first */
@@ -1751,7 +1452,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
bGPDspoint npt;
if (pt0) {
- gp_point_to_parent_space(pt0, diff_mat, &npt);
+ gp_point_to_parent_space(pt0, p->diff_mat, &npt);
gp_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
}
else {
@@ -1759,10 +1460,10 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
copy_v2_v2_int(pc0, pc1);
}
- gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_parent_space(pt1, p->diff_mat, &npt);
gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
- gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_parent_space(pt2, p->diff_mat, &npt);
gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
/* Check that point segment of the boundbox of the eraser stroke */
@@ -1862,8 +1563,6 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* erase strokes which fall under the eraser strokes */
static void gp_stroke_doeraser(tGPsdata *p)
{
- bGPDlayer *gpl;
- bGPDstroke *gps, *gpn;
rcti rect;
Brush *brush = p->brush;
Brush *eraser = p->eraser;
@@ -1903,29 +1602,36 @@ static void gp_stroke_doeraser(tGPsdata *p)
* only a subset of layers, it is harder to perform the same erase operation
* on multiple layers...
*/
- for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) {
bGPDframe *gpf = gpl->actframe;
/* only affect layer if it's editable (and visible) */
- if (gpencil_layer_is_editable(gpl) == false) {
+ if (BKE_gpencil_layer_is_editable(gpl) == false) {
continue;
}
else if (gpf == NULL) {
continue;
}
+ /* calculate difference matrix */
+ BKE_gpencil_parent_matrix_get(p->depsgraph, p->ob, gpl, p->diff_mat);
/* loop over strokes, checking segments for intersections */
- for (gps = gpf->strokes.first; gps; gps = gpn) {
- gpn = gps->next;
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
/* check if the color is editable */
if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) {
continue;
}
+
+ /* Check if the stroke collide with mouse. */
+ if (!ED_gpencil_stroke_check_collision(&p->gsc, gps, p->mval, calc_radius, p->diff_mat)) {
+ continue;
+ }
+
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpl, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
}
}
}
@@ -1964,7 +1670,7 @@ static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts)
{
Brush *brush_dft = NULL;
Paint *paint = &ts->gp_paint->paint;
- Brush *brush_old = paint->brush;
+ Brush *brush_prev = paint->brush;
for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) {
if (brush->gpencil_settings == NULL) {
continue;
@@ -1987,15 +1693,15 @@ static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts)
}
/* create a new soft eraser brush */
else {
- brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser");
+ brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser", OB_MODE_PAINT_GPENCIL);
brush_dft->size = 30.0f;
- brush_dft->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER;
brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
brush_dft->gpencil_tool = GPAINT_TOOL_ERASE;
brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
/* reset current brush */
- BKE_paint_brush_set(paint, brush_old);
+ BKE_paint_brush_set(paint, brush_prev);
return brush_dft;
}
@@ -2032,7 +1738,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts);
changed = true;
}
/* be sure curves are initializated */
@@ -2054,10 +1760,7 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* use radius of eraser */
p->radius = (short)p->eraser->size;
- /* GPXX: Need this update to synchronize brush with draw manager.
- * Maybe this update can be removed when the new tool system
- * will be in place, but while, we need this to keep drawing working.
- */
+ /* Need this update to synchronize brush with draw manager. */
if (changed) {
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
@@ -2069,33 +1772,11 @@ static void gp_init_colors(tGPsdata *p)
bGPdata *gpd = p->gpd;
Brush *brush = p->brush;
- MaterialGPencilStyle *gp_style = NULL;
-
/* use brush material */
p->material = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush);
- /* assign color information to temp tGPsdata */
- gp_style = p->material->gp_style;
- if (gp_style) {
-
- /* set colors */
- if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
- copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
- }
- else {
- /* if no stroke, use fill */
- copy_v4_v4(gpd->runtime.scolor, gp_style->fill_rgba);
- }
- copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
- /* add some alpha to make easy the filling without hide strokes */
- if (gpd->runtime.sfill[3] > 0.8f) {
- gpd->runtime.sfill[3] = 0.8f;
- }
-
- gpd->runtime.mode = (short)gp_style->mode;
- gpd->runtime.bstroke_style = gp_style->stroke_style;
- gpd->runtime.bfill_style = gp_style->fill_style;
- }
+ gpd->runtime.matid = BKE_object_material_slot_find_index(p->ob, p->material);
+ gpd->runtime.sbuffer_brush = brush;
}
/* (re)init new painting data */
@@ -2131,9 +1812,6 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
switch (curarea->spacetype) {
/* supported views first */
case SPACE_VIEW3D: {
- /* View3D *v3d = curarea->spacedata.first; */
- /* RegionView3D *rv3d = region->regiondata; */
-
/* set current area
* - must verify that region data is 3D-view (and not something else)
*/
@@ -2162,10 +1840,11 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
local_view_bits = v3d->local_view_uuid;
}
/* create new default object */
- obact = ED_gpencil_add_object(C, p->scene, cur, local_view_bits);
+ obact = ED_gpencil_add_object(C, cur, local_view_bits);
}
/* assign object after all checks to be sure we have one active */
p->ob = obact;
+ p->ob_eval = (Object *)DEG_get_evaluated_object(p->depsgraph, p->ob);
break;
}
@@ -2204,21 +1883,14 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
gp_init_drawing_brush(C, p);
/* setup active color */
- if (curarea->spacetype == SPACE_VIEW3D) {
- /* region where paint was originated */
- p->gpd->runtime.ar = CTX_wm_region(C);
-
- /* NOTE: This is only done for 3D view, as Materials aren't used for
- * annotations in 2D editors
- */
- int totcol = p->ob->totcol;
+ /* region where paint was originated */
+ p->gpd->runtime.ar = CTX_wm_region(C);
+ int totcol = p->ob->totcol;
+ gp_init_colors(p);
- gp_init_colors(p);
-
- /* check whether the material was newly added */
- if (totcol != p->ob->totcol) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
- }
+ /* check whether the material was newly added */
+ if (totcol != p->ob->totcol) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
}
/* lock axis (in some modes, disable) */
@@ -2274,7 +1946,6 @@ static void gp_session_cleanup(tGPsdata *p)
/* free stroke buffer */
if (gpd->runtime.sbuffer) {
- /* printf("\t\tGP - free sbuffer\n"); */
MEM_SAFE_FREE(gpd->runtime.sbuffer);
gpd->runtime.sbuffer = NULL;
}
@@ -2300,12 +1971,13 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
{
Scene *scene = p->scene;
ToolSettings *ts = scene->toolsettings;
+ bool changed = false;
/* get active layer (or add a new one if non-existent) */
- p->gpl = BKE_gpencil_layer_getactive(p->gpd);
+ p->gpl = BKE_gpencil_layer_active_get(p->gpd);
if (p->gpl == NULL) {
p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true);
-
+ changed = true;
if (p->custom_color[3]) {
copy_v3_v3(p->gpl->color, p->custom_color);
}
@@ -2318,46 +1990,28 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
return;
}
- /* get active frame (add a new one if not matching frame) */
+ /* Eraser mode: If no active strokes, just return. */
if (paintmode == GP_PAINTMODE_ERASER) {
- /* Eraser mode:
- * 1) Add new frames to all frames that we might touch,
- * 2) Ensure that p->gpf refers to the frame used for the active layer
- * (to avoid problems with other tools which expect it to exist)
- */
bool has_layer_to_erase = false;
- for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) {
/* Skip if layer not editable */
- if (gpencil_layer_is_editable(gpl) == false) {
+ if (BKE_gpencil_layer_is_editable(gpl) == false) {
continue;
}
- /* Add a new frame if needed (and based off the active frame,
- * as we need some existing strokes to erase)
- *
- * Note: We don't add a new frame if there's nothing there now, so
- * -> If there are no frames at all, don't add one
- * -> If there are no strokes in that frame, don't add a new empty frame
- */
if (gpl->actframe && gpl->actframe->strokes.first) {
- gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
has_layer_to_erase = true;
+ break;
}
-
- /* XXX: we omit GP_FRAME_PAINT here for now,
- * as it is only really useful for doing
- * paintbuffer drawing
- */
}
- /* Ensure this gets set... */
- p->gpf = p->gpl->actframe;
-
if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
return;
}
+ /* Ensure this gets set... */
+ p->gpf = p->gpl->actframe;
}
else {
/* Drawing Modes - Add a new frame if needed on the active layer */
@@ -2370,7 +2024,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
@@ -2397,8 +2051,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* set special fill stroke mode */
if (p->disable_fill == true) {
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_NOFILL;
- /* replace stroke color with fill color */
- copy_v4_v4(p->gpd->runtime.scolor, p->gpd->runtime.sfill);
}
/* set 'initial run' flag, which is only used to denote when a new stroke is starting */
@@ -2443,6 +2095,14 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
}
}
}
+ if (!changed) {
+ /* Copy the brush to avoid a full tag (very slow). */
+ bGPdata *gpd_eval = (bGPdata *)p->ob_eval->data;
+ gpd_eval->runtime.sbuffer_brush = p->gpd->runtime.sbuffer_brush;
+ }
+ else {
+ gp_update_cache(p->gpd);
+ }
}
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
@@ -2487,7 +2147,6 @@ static void gp_paint_cleanup(tGPsdata *p)
p->gpf->flag &= ~GP_FRAME_PAINT;
}
}
-
/* ------------------------------- */
/* Helper callback for drawing the cursor itself */
@@ -2591,10 +2250,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
else {
/* drawing batch cache is dirty now */
bGPdata *gpd = CTX_data_gpencil_data(C);
- if (gpd) {
- gpd->flag &= ~GP_DATA_STROKE_POLYGON;
- gp_update_cache(gpd);
- }
+ gp_update_cache(gpd);
}
/* clear undo stack */
@@ -2665,23 +2321,6 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
/* ------------------------------- */
-/* ensure that the correct cursor icon is set */
-static void gpencil_draw_cursor_set(tGPsdata *p)
-{
- UNUSED_VARS(p);
- return;
- /* Disable while we get a better cursor handling for direct input devices (Cintiq/Ipad)*/
-#if 0
- Brush *brush = p->brush;
- if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
- WM_cursor_modal_set(p->win, WM_CURSOR_CROSS); /* XXX need a better cursor */
- }
- else {
- WM_cursor_modal_set(p->win, WM_CURSOR_NONE);
- }
-#endif
-}
-
/* update UI indicators of status, including cursor and header prints */
static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
{
@@ -2724,13 +2363,6 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
}
break;
}
- case GP_PAINTMODE_DRAW_POLY: {
- ED_workspace_status_text(
- C,
- TIP_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
- "Release Shift/ESC/Enter to end (or click outside this area)"));
- break;
- }
default: /* unhandled future cases */
{
ED_workspace_status_text(
@@ -2753,88 +2385,6 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* ------------------------------- */
-/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(
- bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph, bool is_fake)
-{
- bGPdata *gpd = p->gpd;
- tGPspoint *pt = NULL;
-
- /* handle drawing/erasing -> test for erasing first */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- /* do 'live' erasing now */
- gp_stroke_doeraser(p);
-
- /* store used values */
- copy_v2_v2(p->mvalo, p->mval);
- p->opressure = p->pressure;
- }
- /* Only add current point to buffer if mouse moved
- * (even though we got an event, it might be just noise). */
- else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
-
- /* if lazy mouse, interpolate the last and current mouse positions */
- if (GPENCIL_LAZY_MODE(p->brush, p->shift)) {
- float now_mouse[2];
- float last_mouse[2];
- copy_v2_v2(now_mouse, p->mval);
- copy_v2_v2(last_mouse, p->mvalo);
- interp_v2_v2v2(now_mouse, now_mouse, last_mouse, p->brush->smooth_stroke_factor);
- copy_v2_v2(p->mval, now_mouse);
- }
-
- /* try to add point */
- short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
-
- /* handle errors while adding point */
- if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
- /* finish off old stroke */
- gp_paint_strokeend(p);
- /* And start a new one!!! Else, projection errors! */
- gp_paint_initstroke(p, p->paintmode, depsgraph);
-
- /* start a new stroke, starting from previous point */
- /* XXX Must manually reset inittime... */
- /* XXX We only need to reuse previous point if overflow! */
- if (ok == GP_STROKEADD_OVERFLOW) {
- p->inittime = p->ocurtime;
- gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime, is_fake);
- }
- else {
- p->inittime = p->curtime;
- }
- gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
- }
- else if (ok == GP_STROKEADD_INVALID) {
- /* the painting operation cannot continue... */
- BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
- p->status = GP_STATUS_ERROR;
-
- if (G.debug & G_DEBUG) {
- printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
- }
- return;
- }
-
- /* store used values */
- copy_v2_v2(p->mvalo, p->mval);
- p->opressure = p->pressure;
- p->ocurtime = p->curtime;
-
- pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
- if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
- }
- }
- else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
- (gpd->runtime.sbuffer_used > 0)) {
- pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
- if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
- }
- }
-}
-
/* Helper to rotate point around origin */
static void gp_rotate_v2_v2v2fl(float v[2],
const float p[2],
@@ -2956,66 +2506,151 @@ static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide)
}
/* apply speed guide */
-static void gpencil_speed_guide(tGPsdata *p, GP_Sculpt_Guide *guide)
+static void gpencil_snap_to_guide(const tGPsdata *p, const GP_Sculpt_Guide *guide, float point[2])
{
switch (guide->type) {
default:
case GP_GUIDE_CIRCULAR: {
- dist_ensure_v2_v2fl(p->mval, p->guide.origin, p->guide.origin_distance);
+ dist_ensure_v2_v2fl(point, p->guide.origin, p->guide.origin_distance);
break;
}
case GP_GUIDE_RADIAL: {
if (guide->use_snapping && (guide->angle_snap > 0.0f)) {
- closest_to_line_v2(p->mval, p->mval, p->guide.rot_point, p->guide.origin);
+ closest_to_line_v2(point, point, p->guide.rot_point, p->guide.origin);
}
else {
- closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.origin);
+ closest_to_line_v2(point, point, p->mvali, p->guide.origin);
}
break;
}
case GP_GUIDE_PARALLEL: {
- closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ closest_to_line_v2(point, point, p->mvali, p->guide.rot_point);
if (guide->use_snapping && (guide->spacing > 0.0f)) {
- gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, guide->angle);
+ gp_snap_to_rotated_grid_fl(point, p->guide.origin, p->guide.spacing, guide->angle);
}
break;
}
case GP_GUIDE_ISO: {
- closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ closest_to_line_v2(point, point, p->mvali, p->guide.rot_point);
if (guide->use_snapping && (guide->spacing > 0.0f)) {
- gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, p->guide.rot_angle);
+ gp_snap_to_rotated_grid_fl(point, p->guide.origin, p->guide.spacing, p->guide.rot_angle);
}
break;
}
case GP_GUIDE_GRID: {
if (guide->use_snapping && (guide->spacing > 0.0f)) {
- closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point);
+ closest_to_line_v2(point, point, p->mvali, p->guide.rot_point);
if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = gp_snap_to_grid_fl(p->mval[1], p->guide.origin[1], p->guide.spacing);
+ point[1] = gp_snap_to_grid_fl(point[1], p->guide.origin[1], p->guide.spacing);
}
else {
- p->mval[0] = gp_snap_to_grid_fl(p->mval[0], p->guide.origin[0], p->guide.spacing);
+ point[0] = gp_snap_to_grid_fl(point[0], p->guide.origin[0], p->guide.spacing);
}
}
else if (p->straight == STROKE_HORIZONTAL) {
- p->mval[1] = p->mvali[1]; /* replace y */
+ point[1] = p->mvali[1]; /* replace y */
}
else {
- p->mval[0] = p->mvali[0]; /* replace x */
+ point[0] = p->mvali[0]; /* replace x */
}
break;
}
}
}
+/* create a new stroke point at the point indicated by the painting context */
+static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+{
+ bGPdata *gpd = p->gpd;
+ tGPspoint *pt = NULL;
+
+ /* handle drawing/erasing -> test for erasing first */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ /* do 'live' erasing now */
+ gp_stroke_doeraser(p);
+
+ /* store used values */
+ copy_v2_v2(p->mvalo, p->mval);
+ p->opressure = p->pressure;
+ }
+ /* Only add current point to buffer if mouse moved
+ * (even though we got an event, it might be just noise). */
+ else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
+
+ /* if lazy mouse, interpolate the last and current mouse positions */
+ if (GPENCIL_LAZY_MODE(p->brush, p->shift)) {
+ float now_mouse[2];
+ float last_mouse[2];
+ copy_v2_v2(now_mouse, p->mval);
+ copy_v2_v2(last_mouse, p->mvalo);
+ interp_v2_v2v2(now_mouse, now_mouse, last_mouse, p->brush->smooth_stroke_factor);
+ copy_v2_v2(p->mval, now_mouse);
+
+ GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ bool is_speed_guide = ((guide->use_guide) &&
+ (p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW)));
+ if (is_speed_guide) {
+ gpencil_snap_to_guide(p, guide, p->mval);
+ }
+ }
+
+ /* try to add point */
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+
+ /* handle errors while adding point */
+ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
+ /* finish off old stroke */
+ gp_paint_strokeend(p);
+ /* And start a new one!!! Else, projection errors! */
+ gp_paint_initstroke(p, p->paintmode, depsgraph);
+
+ /* start a new stroke, starting from previous point */
+ /* XXX Must manually reset inittime... */
+ /* XXX We only need to reuse previous point if overflow! */
+ if (ok == GP_STROKEADD_OVERFLOW) {
+ p->inittime = p->ocurtime;
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ }
+ else {
+ p->inittime = p->curtime;
+ }
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ }
+ else if (ok == GP_STROKEADD_INVALID) {
+ /* the painting operation cannot continue... */
+ BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
+ p->status = GP_STATUS_ERROR;
+
+ if (G.debug & G_DEBUG) {
+ printf("Error: Grease-Pencil Paint - Add Point Invalid\n");
+ }
+ return;
+ }
+
+ /* store used values */
+ copy_v2_v2(p->mvalo, p->mval);
+ p->opressure = p->pressure;
+ p->ocurtime = p->curtime;
+
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ }
+ }
+ else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
+ (gpd->runtime.sbuffer_used > 0)) {
+ pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
+ if (p->paintmode != GP_PAINTMODE_ERASER) {
+ ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ }
+ }
+}
+
/* handle draw event */
static void gpencil_draw_apply_event(bContext *C,
wmOperator *op,
const wmEvent *event,
- Depsgraph *depsgraph,
- float x,
- float y,
- const bool is_fake)
+ Depsgraph *depsgraph)
{
tGPsdata *p = op->customdata;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
@@ -3025,13 +2660,12 @@ static void gpencil_draw_apply_event(bContext *C,
(p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW)));
/* convert from window-space to area-space mouse coordinates
- * add any x,y override position for fake events
+ * add any x,y override position
*/
- p->mval[0] = (float)event->mval[0] - x;
- p->mval[1] = (float)event->mval[1] - y;
+ copy_v2fl_v2i(p->mval, event->mval);
p->shift = event->shift;
- /* verify direction for straight lines */
+ /* verify direction for straight lines and guides */
if ((is_speed_guide) ||
((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false))) {
if (p->straight == 0) {
@@ -3099,12 +2733,12 @@ static void gpencil_draw_apply_event(bContext *C,
p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
/* set values */
- copy_v2_v2(p->mvalo, p->mval);
p->opressure = p->pressure;
p->inittime = p->ocurtime = p->curtime;
p->straight = 0;
/* save initial mouse */
+ copy_v2_v2(p->mvalo, p->mval);
copy_v2_v2(p->mvali, p->mval);
if (is_speed_guide && !ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) &&
@@ -3120,7 +2754,7 @@ static void gpencil_draw_apply_event(bContext *C,
}
/* wait for vector then add initial point */
- if (is_speed_guide && p->flags & GP_PAINTFLAG_REQ_VECTOR) {
+ if (is_speed_guide && (p->flags & GP_PAINTFLAG_REQ_VECTOR)) {
if (p->straight == 0) {
return;
}
@@ -3154,23 +2788,13 @@ static void gpencil_draw_apply_event(bContext *C,
p->mvali,
(p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f);
}
-
- /* create fake events */
- float tmp[2];
- copy_v2_v2(tmp, p->mval);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
- if (len_v2v2(p->mval, p->mvalo)) {
- sub_v2_v2v2(pt, p->mval, p->mvalo);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
- }
- copy_v2_v2(p->mval, tmp);
}
/* check if stroke is straight or guided */
if ((p->paintmode != GP_PAINTMODE_ERASER) && ((p->straight) || (is_speed_guide))) {
/* guided stroke */
if (is_speed_guide) {
- gpencil_speed_guide(p, guide);
+ gpencil_snap_to_guide(p, guide, p->mval);
}
else if (p->straight == STROKE_HORIZONTAL) {
p->mval[1] = p->mvali[1]; /* replace y */
@@ -3192,7 +2816,7 @@ static void gpencil_draw_apply_event(bContext *C,
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(C, op, p, depsgraph, is_fake);
+ gpencil_draw_apply(C, op, p, depsgraph);
/* force refresh */
/* just active area for now, since doing whole screen is too slow */
@@ -3207,28 +2831,21 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
tGPsdata *p = NULL;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- /* printf("GPencil - Starting Re-Drawing\n"); */
-
/* try to initialize context data needed while drawing */
if (!gpencil_draw_init(C, op, NULL)) {
MEM_SAFE_FREE(op->customdata);
- /* printf("\tGP - no valid data\n"); */
return OPERATOR_CANCELLED;
}
else {
p = op->customdata;
}
- /* printf("\tGP - Start redrawing stroke\n"); */
-
/* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
* setting the relevant values in context at each step, then applying
*/
RNA_BEGIN (op->ptr, itemptr, "stroke") {
float mousef[2];
- /* printf("\t\tGP - stroke elem\n"); */
-
/* get relevant data for this point from stroke */
RNA_float_get_array(&itemptr, "mouse", mousef);
p->mval[0] = mousef[0];
@@ -3258,12 +2875,10 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(C, op, p, depsgraph, false);
+ gpencil_draw_apply(C, op, p, depsgraph);
}
RNA_END;
- /* printf("\tGP - done\n"); */
-
/* cleanup */
gpencil_draw_exit(C, op);
@@ -3400,9 +3015,9 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
/* don't erase empty frames */
bool has_layer_to_erase = false;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* Skip if layer not editable */
- if (gpencil_layer_is_editable(gpl)) {
+ if (BKE_gpencil_layer_is_editable(gpl)) {
if (gpl->actframe && gpl->actframe->strokes.first) {
has_layer_to_erase = true;
break;
@@ -3430,35 +3045,25 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
/* TODO: set any additional settings that we can take from the events?
- * TODO? if tablet is erasing, force eraser to be on? */
-
- /* if eraser is on, draw radial aid */
+ * if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
}
else {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
}
- /* set cursor
- * NOTE: This may change later (i.e. intentionally via brush toggle,
- * or unintentionally if the user scrolls outside the area)...
- */
- gpencil_draw_cursor_set(p);
/* only start drawing immediately if we're allowed to do so... */
if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
/* hotkey invoked - start drawing */
- /* printf("\tGP - set first spot\n"); */
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(
- C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f, false);
+ gpencil_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C));
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
/* toolbar invoked - don't start drawing yet... */
- /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
@@ -3510,12 +3115,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
p->status = GP_STATUS_ERROR;
}
- /* printf("\t\tGP - start stroke\n"); */
-
/* we may need to set up paint env again if we're resuming */
- /* XXX: watch it with the paintmode! in future,
- * it'd be nice to allow changing paint-mode when in sketching-sessions */
-
if (gp_session_initdata(C, op, p)) {
gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph_pointer(C));
}
@@ -3528,134 +3128,222 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
return op->customdata;
}
-static void gpencil_stroke_end(wmOperator *op)
+/* Add arc points between two mouse events using the previous segment to determine the vertice of
+ * the arc.
+ * /+ CTL
+ * / |
+ * / |
+ * PtA +...|...+ PtB
+ * /
+ * /
+ * + PtA - 1
+ * /
+ * CTL is the vertice of the triangle created between PtA and PtB */
+static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
{
- tGPsdata *p = op->customdata;
+ bGPdata *gpd = p->gpd;
+ if (gpd->runtime.sbuffer_used < 3) {
+ return;
+ }
+
+ int idx_prev = gpd->runtime.sbuffer_used;
+
+ /* Add space for new arc points. */
+ gpd->runtime.sbuffer_used += segments - 1;
+
+ /* Check if still room in buffer or add more. */
+ gpd->runtime.sbuffer = ED_gpencil_sbuffer_ensure(
+ gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ tGPspoint *pt = NULL;
+ tGPspoint *pt_before = &points[idx_prev - 1]; /* current - 2 */
+ tGPspoint *pt_prev = &points[idx_prev - 2]; /* previous */
+
+ /* Create two vectors, previous and half way of the actual to get the vertex of the triangle
+ * for arc curve.
+ */
+ float v_prev[2], v_cur[2], v_half[2];
+ sub_v2_v2v2(v_cur, mval, &pt_prev->x);
+
+ sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x);
+ interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f);
+ sub_v2_v2(v_half, &pt_prev->x);
+
+ /* If angle is too sharp undo all changes and return. */
+ const float min_angle = DEG2RADF(120.0f);
+ float angle = angle_v2v2(v_prev, v_half);
+ if (angle < min_angle) {
+ gpd->runtime.sbuffer_used -= segments - 1;
+ return;
+ }
+
+ /* Project the half vector to the previous vector and calculate the mid projected point. */
+ float dot = dot_v2v2(v_prev, v_half);
+ float l = len_squared_v2(v_prev);
+ if (l > 0.0f) {
+ mul_v2_fl(v_prev, dot / l);
+ }
- gp_paint_cleanup(p);
+ /* Calc the position of the control point. */
+ float ctl[2];
+ add_v2_v2v2(ctl, &pt_prev->x, v_prev);
- gpencil_undo_push(p->gpd);
+ float step = M_PI_2 / (float)(segments + 1);
+ float a = step;
- gp_session_cleanup(p);
+ float midpoint[2], start[2], end[2], cp1[2], corner[2];
+ mid_v2_v2v2(midpoint, &pt_prev->x, mval);
+ copy_v2_v2(start, &pt_prev->x);
+ copy_v2_v2(end, mval);
+ copy_v2_v2(cp1, ctl);
- p->status = GP_STATUS_IDLING;
- op->flag |= OP_IS_MODAL_CURSOR_REGION;
+ corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
+ corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
- p->gpd = NULL;
- p->gpl = NULL;
- p->gpf = NULL;
+ for (int i = 0; i < segments; i++) {
+ pt = &points[idx_prev + i - 1];
+ pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+
+ /* Set pressure and strength equals to previous. It will be smoothed later. */
+ pt->pressure = pt_prev->pressure;
+ pt->strength = pt_prev->strength;
+
+ a += step;
+ }
}
-/* Move last stroke in the listbase to the head
- * to be drawn below all previous strokes in the layer. */
-static void gpencil_move_last_stroke_to_back(bContext *C)
+static void gpencil_add_guide_points(const tGPsdata *p,
+ const GP_Sculpt_Guide *guide,
+ const float start[2],
+ const float end[2],
+ int segments)
{
- /* Move last stroke (the polygon) to head of the listbase stroke
- * to draw on back of all previous strokes. */
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl, gpl->actframe)) {
+ bGPdata *gpd = p->gpd;
+ if ((gpd->runtime.sbuffer_used == 0)) {
return;
}
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps = gpf->strokes.last;
- if (ELEM(NULL, gps)) {
- return;
+ int idx_prev = gpd->runtime.sbuffer_used;
+
+ /* Add space for new points. */
+ gpd->runtime.sbuffer_used += segments - 1;
+
+ /* Check if still room in buffer or add more. */
+ gpd->runtime.sbuffer = ED_gpencil_sbuffer_ensure(
+ gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ tGPspoint *pt = NULL;
+ tGPspoint *pt_before = &points[idx_prev - 1];
+
+ /* Use arc sampling for circular guide */
+ if (guide->type == GP_GUIDE_CIRCULAR) {
+ float cw = cross_tri_v2(start, p->guide.origin, end);
+ float angle = angle_v2v2v2(start, p->guide.origin, end);
+
+ float step = angle / (float)(segments + 1);
+ if (cw < 0.0f) {
+ step = -step;
+ }
+
+ float a = step;
+
+ for (int i = 0; i < segments; i++) {
+ pt = &points[idx_prev + i - 1];
+
+ gp_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a);
+ gpencil_snap_to_guide(p, guide, &pt->x);
+ a += step;
+
+ /* Set pressure and strength equals to previous. It will be smoothed later. */
+ pt->pressure = pt_before->pressure;
+ pt->strength = pt_before->strength;
+ }
}
+ else {
+ float step = 1.0f / (float)(segments + 1);
+ float a = step;
+
+ for (int i = 0; i < segments; i++) {
+ pt = &points[idx_prev + i - 1];
+
+ interp_v2_v2v2(&pt->x, start, end, a);
+ gpencil_snap_to_guide(p, guide, &pt->x);
+ a += step;
- BLI_remlink(&gpf->strokes, gps);
- BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
+ /* Set pressure and strength equals to previous. It will be smoothed later. */
+ pt->pressure = pt_before->pressure;
+ pt->strength = pt_before->strength;
+ }
+ }
}
-/* Add fake events for missing mouse movements when the artist draw very fast */
-static bool gpencil_add_fake_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
+/* Add fake points for missing mouse movements when the artist draw very fast creating an arc
+ * with the vertice in the midle of the segment and using the angle of the previous segment. */
+static void gpencil_add_fake_points(const wmEvent *event, tGPsdata *p)
{
Brush *brush = p->brush;
+ /* Lazy mode do not use fake events. */
+ if (GPENCIL_LAZY_MODE(brush, p->shift)) {
+ return;
+ }
+
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
int input_samples = brush->gpencil_settings->input_samples;
- bool added_events = false;
- /* ensure sampling when using circular guide */
- if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
+ bool is_speed_guide = ((guide->use_guide) &&
+ (p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW)));
+
+ /* TODO: ensure sampling enough points when using circular guide,
+ but the arc must be around the center. (see if above to check other guides only)
+ */
+ if (is_speed_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
input_samples = GP_MAX_INPUT_SAMPLES;
}
if (input_samples == 0) {
- return added_events;
+ return;
}
- RegionView3D *rv3d = p->region->regiondata;
- float defaultpixsize = rv3d->pixsize * 1000.0f;
- int samples = (GP_MAX_INPUT_SAMPLES - input_samples + 1);
- float thickness = (float)brush->size;
+ int samples = GP_MAX_INPUT_SAMPLES - input_samples + 1;
- float pt[2], a[2], b[2];
- float vec[3];
- float scale = 1.0f;
+ float mouse_prv[2], mouse_cur[2];
+ float min_dist = 4.0f * samples;
- /* get pixel scale */
- gp_get_3d_reference(p, vec);
- mul_m4_v3(rv3d->persmat, vec);
- if (rv3d->is_persp) {
- scale = vec[2] * defaultpixsize;
- }
- else {
- scale = defaultpixsize;
- }
+ copy_v2_v2(mouse_prv, p->mvalo);
+ copy_v2fl_v2i(mouse_cur, event->mval);
- /* The thickness of the brush is reduced of thickness to get overlap dots */
- float dot_factor = 0.50f;
- if (samples < 2) {
- dot_factor = 0.05f;
- }
- else if (samples < 4) {
- dot_factor = 0.10f;
- }
- else if (samples < 7) {
- dot_factor = 0.3f;
- }
- else if (samples < 10) {
- dot_factor = 0.4f;
+ /* get distance in pixels */
+ float dist = len_v2v2(mouse_prv, mouse_cur);
+
+ /* get distance for circular guide */
+ if (is_speed_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
+ float middle[2];
+ gpencil_snap_to_guide(p, guide, mouse_prv);
+ gpencil_snap_to_guide(p, guide, mouse_cur);
+ mid_v2_v2v2(middle, mouse_cur, mouse_prv);
+ gpencil_snap_to_guide(p, guide, middle);
+ dist = len_v2v2(mouse_prv, middle) + len_v2v2(middle, mouse_cur);
}
- float factor = ((thickness * dot_factor) / scale) * samples;
- copy_v2_v2(a, p->mvalo);
- b[0] = (float)event->mval[0] + 1.0f;
- b[1] = (float)event->mval[1] + 1.0f;
+ if ((dist > 3.0f) && (dist > min_dist)) {
+ int slices = (dist / min_dist) + 1;
- /* get distance in pixels */
- float dist = len_v2v2(a, b);
-
- /* for very small distances, add a half way point */
- if (dist <= 2.0f) {
- interp_v2_v2v2(pt, a, b, 0.5f);
- sub_v2_v2v2(pt, b, pt);
- /* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
- added_events = true;
- }
- else if (dist >= factor) {
- int slices = 2 + (int)((dist - 1.0) / factor);
- float n = 1.0f / slices;
- for (int i = 1; i < slices; i++) {
- interp_v2_v2v2(pt, a, b, n * i);
- sub_v2_v2v2(pt, b, pt);
- /* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
- added_events = true;
- }
- }
- return added_events;
+ if (is_speed_guide) {
+ gpencil_add_guide_points(p, guide, mouse_prv, mouse_cur, slices);
+ }
+ else {
+ gpencil_add_arc_points(p, mouse_cur, slices);
+ }
+ }
}
/* events handling during interactive drawing part of operator */
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = op->customdata;
- ToolSettings *ts = CTX_data_tool_settings(C);
+ // ToolSettings *ts = CTX_data_tool_settings(C);
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
/* default exit state - pass through to support MMB view nav, etc. */
@@ -3754,98 +3442,26 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- // printf("\tGP - handle modal event...\n");
-
/* Exit painting mode (and/or end current stroke).
*
- * NOTE: cannot do RIGHTMOUSE (as is standard for canceling)
- * as that would break polyline T32647.
*/
- /* if polyline and release shift must cancel */
- if ((ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) ||
- ((p->paintmode == GP_PAINTMODE_DRAW_POLY) && (event->shift == 0))) {
- /* exit() ends the current stroke before cleaning up */
- /* printf("\t\tGP - end of paint op + end of stroke\n"); */
- /* if drawing polygon and enable on back, must move stroke */
- if (ts) {
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
- (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
- }
- }
- }
+ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) {
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
/* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox
- * only)
- * - RIGHTMOUSE = polyline (hotkey) / eraser (all)
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all)
+ * - RIGHTMOUSE = eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
* also making sure we have a valid event value, to not exit too early
*/
if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
/* if painting, end stroke */
if (p->status == GP_STATUS_PAINTING) {
- int sketch = 0;
-
- /* basically, this should be mouse-button up = end stroke
- * BUT, polyline drawing is an exception -- all knots should be added during one session
- */
- sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
-
- if (sketch) {
- /* end stroke only, and then wait to resume painting soon */
- /* printf("\t\tGP - end stroke only\n"); */
- gpencil_stroke_end(op);
-
- /* If eraser mode is on, turn it off after the stroke finishes
- * NOTE: This just makes it nicer to work with drawing sessions
- */
- if (p->paintmode == GP_PAINTMODE_ERASER) {
- p->paintmode = RNA_enum_get(op->ptr, "mode");
-
- /* if the original mode was *still* eraser,
- * we'll let it say for now, since this gives
- * users an opportunity to have visual feedback
- * when adjusting eraser size
- */
- if (p->paintmode != GP_PAINTMODE_ERASER) {
- /* turn off cursor...
- * NOTE: this should be enough for now
- * Just hiding this makes it seem like
- * you can paint again...
- */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
- }
- }
-
- /* we've just entered idling state, so this event was processed (but no others yet) */
- estate = OPERATOR_RUNNING_MODAL;
-
- /* stroke could be smoothed, send notifier to refresh screen */
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
- }
- else {
- /* printf("\t\tGP - end of stroke + op\n"); */
- /* if drawing polygon and enable on back, must move stroke */
- if (ts) {
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
- (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
- }
- }
- }
- /* drawing batch cache is dirty now */
- gp_update_cache(p->gpd);
-
- p->status = GP_STATUS_DONE;
- estate = OPERATOR_FINISHED;
- }
+ p->status = GP_STATUS_DONE;
+ estate = OPERATOR_FINISHED;
}
else if (event->val == KM_PRESS) {
bool in_bounds = false;
@@ -3929,15 +3545,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* NOTE: Don't enter this case if an error occurred while finding the
* region (as above)
*/
- /* if drawing polygon and enable on back, must move stroke */
- if (ts) {
- if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) &&
- (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
- }
- }
- }
p->status = GP_STATUS_DONE;
estate = OPERATOR_FINISHED;
}
@@ -3954,25 +3561,24 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* handle painting mouse-movements? */
if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
/* handle drawing event */
- /* printf("\t\tGP - add point\n"); */
+ bool is_speed_guide = ((guide->use_guide) &&
+ (p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW)));
int size_before = p->gpd->runtime.sbuffer_used;
- bool added_events = false;
- if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) {
- added_events = gpencil_add_fake_events(C, op, event, p);
+ if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER) &&
+ !(is_speed_guide && (p->flags & GP_PAINTFLAG_REQ_VECTOR))) {
+ gpencil_add_fake_points(event, p);
}
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f, false);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C));
int size_after = p->gpd->runtime.sbuffer_used;
- /* Last point of the event is always real (not fake). */
- tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer;
- tGPspoint *pt = &points[size_after - 1];
- pt->tflag &= ~GP_TPOINT_FAKE;
-
- /* Smooth the fake events to get smoother strokes, specially at ends. */
- if (added_events) {
- gp_smooth_fake_events(p, size_before, size_after);
+ /* Smooth segments if some fake points were added (need loop to get cumulative smooth).
+ * the 0.15 value gets a good result in Windows and Linux. */
+ if (!is_speed_guide && (size_after - size_before > 1)) {
+ for (int r = 0; r < 5; r++) {
+ gp_smooth_segment(p->gpd, 0.15f, size_before - 1, size_after - 1);
+ }
}
/* finish painting operation if anything went wrong just now */
@@ -3982,17 +3588,13 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* event handled, so just tag as running modal */
- /* printf("\t\t\t\tGP - add point handled!\n"); */
estate = OPERATOR_RUNNING_MODAL;
}
}
/* eraser size */
else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) {
- /* just resize the brush (local version)
- * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
- */
- /* printf("\t\tGP - resize eraser\n"); */
+ /* Just resize the brush (local version). */
switch (event->type) {
case WHEELDOWNMOUSE: /* larger */
case PADPLUSKEY:
@@ -4032,7 +3634,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* update status indicators - cursor, header, etc. */
gpencil_draw_status_indicators(C, p);
- gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */
}
/* process last operations before exiting */
@@ -4056,12 +3657,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
/* event doesn't need to be handled */
-#if 0
- printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
- event->type,
- event->type == MIDDLEMOUSE,
- event->type == MOUSEMOVE);
-#endif
break;
}
@@ -4078,11 +3673,6 @@ static const EnumPropertyItem prop_gpencil_drawmodes[] = {
0,
"Draw Straight Lines",
"Draw straight line segment(s)"},
- {GP_PAINTMODE_DRAW_POLY,
- "DRAW_POLY",
- 0,
- "Draw Poly Line",
- "Click to place endpoints of straight line segments (connected)"},
{GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Grease Pencil strokes"},
{0, NULL, 0, NULL, NULL},
};
@@ -4094,7 +3684,7 @@ void GPENCIL_OT_draw(wmOperatorType *ot)
/* identifiers */
ot->name = "Grease Pencil Draw";
ot->idname = "GPENCIL_OT_draw";
- ot->description = "Draw a new stroke in the active Grease Pencil Object";
+ ot->description = "Draw mouse_prv new stroke in the active Grease Pencil Object";
/* api callbacks */
ot->exec = gpencil_draw_exec;
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index ad54382dde7..96522d1750c 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -122,6 +122,10 @@ static void gp_session_validatebuffer(tGPDprimitive *p)
gpd->runtime.sbuffer_sflag = 0;
gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
+ /* Set vertex colors for buffer. */
+ ED_gpencil_sbuffer_vertex_color_set(
+ p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material);
+
if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC;
}
@@ -132,34 +136,11 @@ static void gp_init_colors(tGPDprimitive *p)
bGPdata *gpd = p->gpd;
Brush *brush = p->brush;
- MaterialGPencilStyle *gp_style = NULL;
-
/* use brush material */
- p->mat = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush);
-
- /* assign color information to temp data */
- gp_style = p->mat->gp_style;
- if (gp_style) {
-
- /* set colors */
- if (gp_style->flag & GP_STYLE_STROKE_SHOW) {
- copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba);
- }
- else {
- /* if no stroke, use fill */
- copy_v4_v4(gpd->runtime.scolor, gp_style->fill_rgba);
- }
-
- copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba);
- /* add some alpha to make easy the filling without hide strokes */
- if (gpd->runtime.sfill[3] > 0.8f) {
- gpd->runtime.sfill[3] = 0.8f;
- }
+ p->material = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush);
- gpd->runtime.mode = (short)gp_style->mode;
- gpd->runtime.bstroke_style = gp_style->stroke_style;
- gpd->runtime.bfill_style = gp_style->fill_style;
- }
+ gpd->runtime.matid = BKE_object_material_slot_find_index(p->ob, p->material);
+ gpd->runtime.sbuffer_brush = brush;
}
/* Helper to square a primitive */
@@ -254,18 +235,6 @@ static void gp_primitive_update_cps(tGPDprimitive *tgpi)
}
}
-/* Helper to reflect point */
-static void UNUSED_FUNCTION(gp_reflect_point_v2_v2v2v2)(float va[2],
- const float p[2],
- const float a[2],
- const float b[2])
-{
- float point[2];
- closest_to_line_v2(point, p, a, b);
- va[0] = point[0] - (p[0] - point[0]);
- va[1] = point[1] - (p[1] - point[1]);
-}
-
/* Poll callback for primitive operators */
static bool gpencil_primitive_add_poll(bContext *C)
{
@@ -294,7 +263,7 @@ static bool gpencil_primitive_add_poll(bContext *C)
/* don't allow operator to function if the active layer is locked/hidden
* (BUT, if there isn't an active layer, we are free to add new layer when the time comes)
*/
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if ((gpl) && (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE))) {
CTX_wm_operator_poll_msg_set(C,
"Primitives cannot be added as active layer is locked or hidden");
@@ -322,6 +291,8 @@ static void gpencil_primitive_allocate_memory(tGPDprimitive *tgpi)
static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
{
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ Brush *brush = tgpi->brush;
int cfra = CFRA;
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
@@ -339,13 +310,15 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
/* create new temp stroke */
bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke");
gps->thickness = 2.0f;
- 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.0f;
- /* enable recalculation flag by default */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ /* Apply the vertex color to fill. */
+ ED_gpencil_fill_vertex_color_set(ts, brush, gps);
+
gps->flag &= ~GP_STROKE_SELECT;
/* the polygon must be closed, so enabled cyclic */
if (ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
@@ -367,10 +340,11 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
/* allocate memory for storage points, but keep empty */
gps->totpoints = 0;
gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps->dvert = NULL;
+
/* initialize triangle memory to dummy data */
gps->tot_triangles = 0;
gps->triangles = NULL;
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
/* add to strokes */
BLI_addtail(&tgpi->gpf->strokes, gps);
@@ -381,6 +355,8 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
/* Random generator, only init once. */
uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
tgpi->rng = BLI_rng_new(rng_seed);
+
+ DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE);
}
/* add new segment to curve */
@@ -898,7 +874,6 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
if (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
jitter = BKE_curvemapping_evaluateF(
brush->gpencil_settings->curve_jitter, 0, curve_pressure);
- jitter *= brush->gpencil_settings->draw_sensitivity;
}
else {
jitter = brush->gpencil_settings->draw_jitter;
@@ -934,10 +909,10 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
(brush->gpencil_settings->draw_random_press > 0.0f)) {
if (p2d->rnd[0] > 0.5f) {
- pressure -= brush->gpencil_settings->draw_random_press * p2d->rnd[1];
+ pressure -= (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[1];
}
else {
- pressure += brush->gpencil_settings->draw_random_press * p2d->rnd[2];
+ pressure += (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[2];
}
}
@@ -945,7 +920,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
float curvef = BKE_curvemapping_evaluateF(
brush->gpencil_settings->curve_strength, 0, curve_pressure);
- strength *= curvef * brush->gpencil_settings->draw_sensitivity;
+ strength *= curvef;
strength *= brush->gpencil_settings->draw_strength;
}
@@ -973,14 +948,13 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* point uv */
if (gpd->runtime.sbuffer_used > 0) {
- MaterialGPencilStyle *gp_style = tgpi->mat->gp_style;
- const float pixsize = gp_style->texture_pixsize / 1000000.0f;
tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
bGPDspoint spt, spt2;
/* get origin to reproject point */
float origin[3];
- ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(
+ tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
/* reproject current */
ED_gpencil_tpoint_to_point(tgpi->region, origin, tpt, &spt);
ED_gp_project_point_to_plane(
@@ -990,11 +964,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
ED_gpencil_tpoint_to_point(tgpi->region, origin, tptb, &spt2);
ED_gp_project_point_to_plane(
tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2);
- tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize;
+ tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x);
tpt->uv_fac = tgpi->totpixlen;
- if ((gp_style) && (gp_style->sima)) {
- tpt->uv_fac /= gp_style->sima->gen_x;
- }
}
else {
tgpi->totpixlen = 0.0f;
@@ -1028,6 +999,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
pt->time = 0.0f;
pt->flag = 0;
pt->uv_fac = tpt->uv_fac;
+ /* Apply the vertex color to point. */
+ ED_gpencil_point_vertex_color_set(ts, brush, pt);
if (gps->dvert != NULL) {
MDeformVert *dvert = &gps->dvert[i];
@@ -1052,7 +1025,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* reproject to plane */
if (!is_depth) {
float origin[3];
- ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(
+ tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
ED_gp_project_stroke_to_plane(
tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1);
}
@@ -1060,7 +1034,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* if parented change position relative to parent object */
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
- gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpd, tgpi->gpl, pt);
+ gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt);
}
/* if camera view, reproject flat to view to avoid perspective effect */
@@ -1068,8 +1042,11 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps);
}
- /* force fill recalc */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+
+ /* Update evaluated data. */
+ ED_gpencil_sbuffer_update_eval(tgpi->gpd, tgpi->ob_eval);
MEM_SAFE_FREE(depth_arr);
@@ -1162,13 +1139,14 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* set current scene and window info */
tgpi->bmain = CTX_data_main(C);
+ tgpi->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpi->scene = scene;
tgpi->ob = CTX_data_active_object(C);
+ tgpi->ob_eval = (Object *)DEG_get_evaluated_object(tgpi->depsgraph, tgpi->ob);
tgpi->sa = CTX_wm_area(C);
tgpi->region = CTX_wm_region(C);
tgpi->rv3d = tgpi->region->regiondata;
tgpi->v3d = tgpi->sa->spacedata.first;
- tgpi->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpi->win = CTX_wm_window(C);
/* save original type */
@@ -1184,7 +1162,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* if brush doesn't exist, create a new set (fix damaged files from old versions) */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts);
}
/* Set Draw brush. */
@@ -1199,7 +1177,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->gpd->runtime.tot_cp_points = 0;
/* getcolor info */
- tgpi->mat = BKE_gpencil_object_material_ensure_from_active_input_toolsettings(
+ tgpi->material = BKE_gpencil_object_material_ensure_from_active_input_toolsettings(
bmain, tgpi->ob, ts);
/* set parameters */
@@ -1309,20 +1287,17 @@ static void gpencil_primitive_interaction_end(bContext *C,
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, add_frame_mode);
+ gpf = BKE_gpencil_layer_frame_get(tgpi->gpl, tgpi->cframe, add_frame_mode);
/* prepare stroke to get transferred */
gps = tgpi->gpf->strokes.first;
if (gps) {
gps->thickness = brush->size;
- gps->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s);
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
+ gps->hardeness = brush->gpencil_settings->hardeness;
+ copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
- /* calculate UVs along the stroke */
- ED_gpencil_calc_stroke_uv(tgpi->ob, gps);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
/* transfer stroke from temporary buffer to the actual frame */
@@ -1348,7 +1323,7 @@ static void gpencil_primitive_interaction_end(bContext *C,
/* Close stroke with geometry */
if ((tgpi->type == GP_STROKE_BOX) || (tgpi->type == GP_STROKE_CIRCLE)) {
- BKE_gpencil_close_stroke(gps);
+ BKE_gpencil_stroke_close(gps);
}
DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 14354ff38f4..5cf4681c755 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -48,11 +48,13 @@
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -83,8 +85,8 @@
/* Context for brush operators */
typedef struct tGP_BrushEditData {
/* Current editor/region/etc. */
- /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
- struct Main *bmain;
+ Depsgraph *depsgraph;
+ Main *bmain;
Scene *scene;
Object *object;
@@ -96,11 +98,9 @@ typedef struct tGP_BrushEditData {
/* Brush Settings */
GP_Sculpt_Settings *settings;
- GP_Sculpt_Data *gp_brush;
- GP_Sculpt_Data *gp_brush_old;
+ Brush *brush;
+ Brush *brush_prev;
- eGP_Sculpt_Types brush_type;
- eGP_Sculpt_Types brush_type_old;
eGP_Sculpt_Flag flag;
eGP_Sculpt_SelectMaskFlag mask;
@@ -109,7 +109,6 @@ typedef struct tGP_BrushEditData {
/* Is the brush currently painting? */
bool is_painting;
- bool is_weight_mode;
bool is_transformed;
/* Start of new sculpt stroke */
@@ -176,10 +175,6 @@ static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso,
bGPDspoint *pt,
const float save_pt[3])
{
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- return;
- }
-
const ToolSettings *ts = gso->scene->toolsettings;
const View3DCursor *cursor = &gso->scene->cursor;
const int axis = ts->gp_sculpt.lock_axis;
@@ -230,28 +225,13 @@ static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene)
return &scene->toolsettings->gp_sculpt;
}
-/* Get the active brush */
-static GP_Sculpt_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
-{
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- GP_Sculpt_Data *gp_brush = NULL;
- if (is_weight_mode) {
- gp_brush = &gset->brush[gset->weighttype];
- }
- else {
- gp_brush = &gset->brush[gset->brushtype];
- }
-
- return gp_brush;
-}
-
/* Brush Operations ------------------------------- */
/* Invert behavior of brush? */
static bool gp_brush_invert_check(tGP_BrushEditData *gso)
{
/* The basic setting is the brush's setting (from the panel) */
- bool invert = ((gso->gp_brush->flag & GP_SCULPT_FLAG_INVERT) != 0);
+ bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0);
/* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
if (gso->flag & GP_SCULPT_FLAG_INVERT) {
@@ -260,10 +240,10 @@ static bool gp_brush_invert_check(tGP_BrushEditData *gso)
/* set temporary status */
if (invert) {
- gso->gp_brush->flag |= GP_SCULPT_FLAG_TMP_INVERT;
+ gso->brush->gpencil_settings->sculpt_flag |= GP_SCULPT_FLAG_TMP_INVERT;
}
else {
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+ gso->brush->gpencil_settings->sculpt_flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
}
return invert;
@@ -272,28 +252,24 @@ static bool gp_brush_invert_check(tGP_BrushEditData *gso)
/* Compute strength of effect */
static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2])
{
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ Brush *brush = gso->brush;
/* basic strength factor from brush settings */
- float influence = gp_brush->strength;
+ float influence = brush->alpha;
/* use pressure? */
- if (gp_brush->flag & GP_SCULPT_FLAG_USE_PRESSURE) {
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
influence *= gso->pressure;
}
/* distance fading */
- if (gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
- int mval_i[2];
- round_v2i_v2fl(mval_i, gso->mval);
- float distance = (float)len_v2v2_int(mval_i, co);
- float fac;
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ float distance = (float)len_v2v2_int(mval_i, co);
- CLAMP(distance, 0.0f, (float)radius);
- fac = 1.0f - (distance / (float)radius);
-
- influence *= fac;
- }
+ /* Apply Brush curve. */
+ float brush_fallof = BKE_brush_curve_strength(brush, distance, (float)radius);
+ influence *= brush_fallof;
/* apply multiframe falloff */
influence *= gso->mf_falloff;
@@ -302,18 +278,36 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c
return influence;
}
-/* Force recal filling data */
-static void gp_recalc_geometry(bGPDstroke *gps)
+/* Tag stroke to be recalculated. */
+static void gpencil_recalc_geometry_tag(bGPDstroke *gps)
{
- bGPDstroke *gps_orig = gps->runtime.gps_orig;
- if (gps_orig) {
- gps_orig->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps_orig->tot_triangles = 0;
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ gps_active->flag |= GP_STROKE_TAG;
+}
+
+/* Recalc any stroke tagged. */
+static void gpencil_update_geometry(bGPdata *gpd)
+{
+ if (gpd == NULL) {
+ return;
}
- else {
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ if ((gpl->actframe != gpf) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
+ continue;
+ }
+
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_TAG) {
+ BKE_gpencil_stroke_geometry_update(gps);
+ gps->flag &= ~GP_STROKE_TAG;
+ }
+ }
+ }
}
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
/* ************************************************ */
@@ -334,31 +328,22 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso,
const int radius,
const int co[2])
{
- // GP_Sculpt_Data *gp_brush = gso->brush;
float inf = gp_brush_influence_calc(gso, radius, co);
- /* need one flag enabled by default */
- if ((gso->settings->flag &
- (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
- GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
- gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
- }
/* perform smoothing */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
- BKE_gpencil_smooth_stroke(gps, pt_index, inf);
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
+ BKE_gpencil_stroke_smooth(gps, pt_index, inf);
}
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
- BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
+ BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
}
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
- BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
+ BKE_gpencil_stroke_smooth_thickness(gps, pt_index, inf);
}
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
- BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
+ BKE_gpencil_stroke_smooth_uv(gps, pt_index, inf);
}
- gp_recalc_geometry(gps);
-
return true;
}
@@ -440,7 +425,7 @@ static bool gp_brush_strength_apply(tGP_BrushEditData *gso,
CLAMP(pt->strength, 0.0f, 1.0f);
/* smooth the strength */
- BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
return true;
}
@@ -534,38 +519,27 @@ static bool gp_brush_grab_store_points(tGP_BrushEditData *gso,
static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
{
/* Convert mouse-movements to movement vector */
- // TODO: incorporate pressure into this?
- // XXX: screen-space strokes in 3D space will suffer!
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- RegionView3D *rv3d = gso->region->regiondata;
- float *rvec = gso->object->loc;
- float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
-
- float mval_f[2];
-
- /* convert from 2D screenspace to 3D... */
- mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
-
- /* apply evaluated data transformation */
- if (gso->rot_eval != 0.0f) {
- const float cval = cos(gso->rot_eval);
- const float sval = sin(gso->rot_eval);
- float r[2];
- r[0] = (mval_f[0] * cval) - (mval_f[1] * sval);
- r[1] = (mval_f[0] * sval) + (mval_f[1] * cval);
- copy_v2_v2(mval_f, r);
- }
+ RegionView3D *rv3d = gso->region->regiondata;
+ float *rvec = gso->object->loc;
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
- ED_view3d_win_to_delta(gso->region, mval_f, gso->dvec, zfac);
- }
- else {
- /* 2D - just copy */
- // XXX: view2d?
- gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
- gso->dvec[2] = 0.0f; /* unused */
+ float mval_f[2];
+
+ /* convert from 2D screenspace to 3D... */
+ mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ /* apply evaluated data transformation */
+ if (gso->rot_eval != 0.0f) {
+ const float cval = cos(gso->rot_eval);
+ const float sval = sin(gso->rot_eval);
+ float r[2];
+ r[0] = (mval_f[0] * cval) - (mval_f[1] * sval);
+ r[1] = (mval_f[0] * sval) + (mval_f[1] * cval);
+ copy_v2_v2(mval_f, r);
}
+
+ ED_view3d_win_to_delta(gso->region, mval_f, gso->dvec, zfac);
}
/* Apply grab transform to all relevant points of the affected strokes */
@@ -574,7 +548,14 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso,
const float diff_mat[4][4])
{
tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ /* If a new frame is created, could be impossible find the stroke. */
+ if (data == NULL) {
+ return;
+ }
+
int i;
+ float inverse_diff_mat[4][4];
+ invert_m4_m4(inverse_diff_mat, diff_mat);
/* Apply dvec to all of the stored points */
for (i = 0; i < data->size; i++) {
@@ -596,14 +577,11 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso,
/* apply */
add_v3_v3v3(&pt->x, fpt, delta);
/* undo transformation to the init parent position */
- float inverse_diff_mat[4][4];
- invert_m4_m4(inverse_diff_mat, diff_mat);
mul_m4_v3(inverse_diff_mat, &pt->x);
/* compute lock axis */
gpsculpt_compute_lock_axis(gso, pt, save_pt);
}
- gp_recalc_geometry(gps);
}
/* free customdata used for handling this stroke */
@@ -647,8 +625,6 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso,
/* compute lock axis */
gpsculpt_compute_lock_axis(gso, pt, save_pt);
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
/* done */
return true;
}
@@ -658,35 +634,26 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso,
/* Compute reference midpoint for the brush - this is what we'll be moving towards */
static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
{
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- /* Convert mouse position to 3D space
- * See: gpencil_paint.c :: gp_stroke_convertcoords()
- */
- RegionView3D *rv3d = gso->region->regiondata;
- const float *rvec = gso->object->loc;
- float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
-
- float mval_f[2];
- copy_v2_v2(mval_f, gso->mval);
- float mval_prj[2];
- float dvec[3];
-
- if (ED_view3d_project_float_global(gso->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
- V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval_f);
- ED_view3d_win_to_delta(gso->region, mval_f, dvec, zfac);
- sub_v3_v3v3(gso->dvec, rvec, dvec);
- }
- else {
- zero_v3(gso->dvec);
- }
+ /* Convert mouse position to 3D space
+ * See: gpencil_paint.c :: gp_stroke_convertcoords()
+ */
+ RegionView3D *rv3d = gso->region->regiondata;
+ const float *rvec = gso->object->loc;
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2];
+ copy_v2_v2(mval_f, gso->mval);
+ float mval_prj[2];
+ float dvec[3];
+
+ if (ED_view3d_project_float_global(gso->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(gso->region, mval_f, dvec, zfac);
+ sub_v3_v3v3(gso->dvec, rvec, dvec);
}
else {
- /* Just 2D coordinates */
- // XXX: fix View2D offsets later
- gso->dvec[0] = (float)gso->mval[0];
- gso->dvec[1] = (float)gso->mval[1];
- gso->dvec[2] = 0.0f;
+ zero_v3(gso->dvec);
}
}
@@ -738,8 +705,6 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso,
/* compute lock axis */
gpsculpt_compute_lock_axis(gso, pt, save_pt);
- gp_recalc_geometry(gps);
-
/* done */
return true;
}
@@ -826,8 +791,6 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso,
}
}
- gp_recalc_geometry(gps);
-
/* done */
return true;
}
@@ -851,15 +814,9 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso,
*/
const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
const float fac = BLI_rng_get_float(gso->rng) * inf;
- /* need one flag enabled by default */
- if ((gso->settings->flag &
- (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
- GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
- gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
- }
/* apply random to position */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
/* Jitter is applied perpendicular to the mouse movement vector
* - We compute all effects in screenspace (since it's easier)
* and then project these to get the points/distances in
@@ -886,35 +843,20 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso,
/* convert to dataspace */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D: Project to 3D space */
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- bool flip;
- RegionView3D *rv3d = gso->region->regiondata;
- float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
- if (flip == false) {
- float dvec[3];
- ED_view3d_win_to_delta(gso->gsc.region, svec, dvec, zfac);
- add_v3_v3(&pt->x, dvec);
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
- }
- }
- else {
- /* ERROR */
- BLI_assert(!"3D stroke being sculpted in non-3D view");
+ bool flip;
+ RegionView3D *rv3d = gso->region->regiondata;
+ float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
+ if (flip == false) {
+ float dvec[3];
+ ED_view3d_win_to_delta(gso->gsc.region, svec, dvec, zfac);
+ add_v3_v3(&pt->x, dvec);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
}
}
- else {
- /* 2D: As-is */
- // XXX: v2d scaling/offset?
- float nco[2];
- nco[0] = (float)co[0] + svec[0];
- nco[1] = (float)co[1] + svec[1];
-
- copy_v2_v2(&pt->x, nco);
- }
}
/* apply random to strength */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
if (BLI_rng_get_float(gso->rng) > 0.5f) {
pt->strength += fac;
}
@@ -925,7 +867,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso,
CLAMP_MAX(pt->strength, 1.0f);
}
/* apply random to thickness (use pressure) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
if (BLI_rng_get_float(gso->rng) > 0.5f) {
pt->pressure += fac;
}
@@ -936,7 +878,7 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso,
CLAMP_MIN(pt->pressure, 0.0f);
}
/* apply random to UV (use pressure) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
+ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
if (BLI_rng_get_float(gso->rng) > 0.5f) {
pt->uv_rot += fac;
}
@@ -946,69 +888,10 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso,
CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
}
- gp_recalc_geometry(gps);
-
/* done */
return true;
}
-/* Weight Paint Brush */
-/* Change weight paint for vertex groups */
-static bool gp_brush_weight_apply(tGP_BrushEditData *gso,
- bGPDstroke *gps,
- float UNUSED(rot_eval),
- int pt_index,
- const int radius,
- const int co[2])
-{
- /* create dvert */
- BKE_gpencil_dvert_ensure(gps);
-
- MDeformVert *dvert = gps->dvert + pt_index;
- float inf;
-
- /* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
-
- /* need a vertex group */
- if (gso->vrgroup == -1) {
- if (gso->object) {
- BKE_object_defgroup_add(gso->object);
- DEG_relations_tag_update(gso->bmain);
- gso->vrgroup = 0;
- }
- }
- else {
- bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
- if (defgroup->flag & DG_LOCK_WEIGHT) {
- return false;
- }
- }
- /* get current weight */
- MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup);
- float curweight = dw ? dw->weight : 0.0f;
-
- if (gp_brush_invert_check(gso)) {
- curweight -= inf;
- }
- else {
- /* increase weight */
- curweight += inf;
- /* verify maximum target weight */
- CLAMP_MAX(curweight, gso->gp_brush->weight);
- }
-
- CLAMP(curweight, 0.0f, 1.0f);
- if (dw) {
- dw->weight = curweight;
- }
-
- return true;
-}
-
/* ************************************************ */
/* Non Callback-Based Brushes */
/* Clone Brush ------------------------------------- */
@@ -1112,9 +995,9 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
{
tGPSB_CloneBrushData *data = gso->customdata;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = gso->object;
bGPdata *gpd = (bGPdata *)ob->data;
- Scene *scene = CTX_data_scene(C);
+ Scene *scene = gso->scene;
bGPDstroke *gps;
float delta[3];
@@ -1136,31 +1019,24 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
bGPDlayer *gpl = NULL;
/* Try to use original layer. */
if (gps->runtime.tmp_layerinfo != NULL) {
- gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info));
+ gpl = BKE_gpencil_layer_named_get(gpd, gps->runtime.tmp_layerinfo);
}
/* if not available, use active layer. */
if (gpl == NULL) {
gpl = CTX_data_active_gpencil_layer(C);
}
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
/* Make a new stroke */
- new_stroke = MEM_dupallocN(gps);
-
- new_stroke->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- new_stroke->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
- }
- new_stroke->triangles = MEM_dupallocN(gps->triangles);
+ new_stroke = BKE_gpencil_stroke_duplicate(gps, true);
new_stroke->next = new_stroke->prev = NULL;
BLI_addtail(&gpf->strokes, new_stroke);
/* Fix color references */
Material *ma = BLI_ghash_lookup(data->new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
- new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
+ new_stroke->mat_nr = BKE_gpencil_object_material_index_get(ob, ma);
if (!ma || new_stroke->mat_nr < 0) {
new_stroke->mat_nr = 0;
}
@@ -1204,26 +1080,20 @@ static void gp_brush_clone_adjust(tGP_BrushEditData *gso)
int i;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (gso->gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
- /* "Smudge" Effect when falloff is enabled */
- float delta[3] = {0.0f};
- int sco[2] = {0};
- float influence;
+ /* "Smudge" Effect falloff */
+ float delta[3] = {0.0f};
+ int sco[2] = {0};
+ float influence;
- /* compute influence on point */
- gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
- influence = gp_brush_influence_calc(gso, gso->gp_brush->size, sco);
+ /* compute influence on point */
+ gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
+ influence = gp_brush_influence_calc(gso, gso->brush->size, sco);
- /* adjust the amount of displacement to apply */
- mul_v3_v3fl(delta, gso->dvec, influence);
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, influence);
- /* apply */
- add_v3_v3(&pt->x, delta);
- }
- else {
- /* Just apply the offset - All points move perfectly in sync with the cursor */
- add_v3_v3(&pt->x, gso->dvec);
- }
+ /* apply */
+ add_v3_v3(&pt->x, delta);
}
}
}
@@ -1258,17 +1128,15 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
{
- const char *brush_name = NULL;
+ Brush *brush = gso->brush;
char str[UI_MAX_DRAW_STR] = "";
- RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
-
BLI_snprintf(str,
sizeof(str),
TIP_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit"
" | Ctrl to Invert Action | Wheel Up/Down for Size "
" | Shift-Wheel Up/Down for Strength"),
- (brush_name) ? brush_name : "<?>");
+ brush->id.name + 2);
ED_workspace_status_text(C, str);
}
@@ -1281,33 +1149,20 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
+ ToolSettings *ts = scene->toolsettings;
Object *ob = CTX_data_active_object(C);
- const bool is_weight_mode = ob->mode == OB_MODE_WEIGHT_GPENCIL;
/* set the brush using the tool */
-#if 0
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- eGP_Sculpt_Types mode = is_weight_mode ? gset->weighttype : gset->brushtype;
-#endif
tGP_BrushEditData *gso;
/* setup operator data */
gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
op->customdata = gso;
+ gso->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
gso->bmain = CTX_data_main(C);
/* store state */
gso->settings = gpsculpt_get_settings(scene);
- gso->gp_brush = gpsculpt_get_brush(scene, is_weight_mode);
- gso->is_weight_mode = is_weight_mode;
-
- if (is_weight_mode) {
- gso->brush_type = gso->settings->weighttype;
- }
- else {
- gso->brush_type = gso->settings->brushtype;
- }
/* Random generator, only init once. */
uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
@@ -1320,11 +1175,6 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gso->gpd = ED_gpencil_data_get_active(C);
gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
- /* some brushes cannot use pressure for radius */
- if (ELEM(gso->brush_type, GP_SCULPT_TYPE_GRAB, GP_SCULPT_TYPE_CLONE)) {
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_PRESSURE_RADIUS;
- }
-
gso->scene = scene;
gso->object = ob;
if (ob) {
@@ -1345,6 +1195,10 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gso->sa = CTX_wm_area(C);
gso->region = CTX_wm_region(C);
+ Paint *paint = &ts->gp_sculptpaint->paint;
+ gso->brush = paint->brush;
+ BKE_curvemapping_initialize(gso->brush->curve);
+
/* save mask */
gso->mask = ts->gpencil_selectmode_sculpt;
@@ -1359,8 +1213,9 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
}
/* initialise custom data for brushes */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_CLONE: {
+ char tool = gso->brush->gpencil_sculpt_tool;
+ switch (tool) {
+ case GPSCULPT_TOOL_CLONE: {
bGPDstroke *gps;
bool found = false;
@@ -1390,7 +1245,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
break;
}
- case GP_SCULPT_TYPE_GRAB: {
+ case GPSCULPT_TOOL_GRAB: {
/* initialise the cache needed for this brush */
gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
break;
@@ -1407,11 +1262,6 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
/* update header */
gpsculpt_brush_header_set(C, gso);
- /* setup cursor drawing */
- // WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_CROSS);
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- }
return true;
}
@@ -1419,10 +1269,11 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
{
tGP_BrushEditData *gso = op->customdata;
wmWindow *win = CTX_wm_window(C);
+ char tool = gso->brush->gpencil_sculpt_tool;
/* free brush-specific data */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_GRAB: {
+ switch (tool) {
+ case GPSCULPT_TOOL_GRAB: {
/* Free per-stroke customdata
* - Keys don't need to be freed, as those are the strokes
* - Values assigned to those keys do, as they are custom structs
@@ -1431,7 +1282,7 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
break;
}
- case GP_SCULPT_TYPE_CLONE: {
+ case GPSCULPT_TOOL_CLONE: {
/* Free customdata */
gp_brush_clone_free(gso);
break;
@@ -1450,15 +1301,14 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
BLI_rng_free(gso->rng);
}
- /* disable cursor and headerprints */
+ /* Disable headerprints. */
ED_workspace_status_text(C, NULL);
- WM_cursor_modal_restore(win);
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- }
/* disable temp invert flag */
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+ gso->brush->gpencil_settings->sculpt_flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+
+ /* Update geometry data for tagged strokes. */
+ gpencil_update_geometry(gso->gpd);
/* free operator data */
MEM_freeN(gso);
@@ -1468,6 +1318,11 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
/* poll callback for stroke sculpting operator(s) */
static bool gpsculpt_brush_poll(bContext *C)
{
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype != SPACE_VIEW3D) {
+ return false;
+ }
+
/* NOTE: this is a bit slower, but is the most accurate... */
return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
@@ -1478,7 +1333,6 @@ static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso)
{
bGPdata *gpd = gso->gpd;
- bGPDlayer *gpl;
Scene *scene = gso->scene;
int cfra = CFRA;
@@ -1488,9 +1342,9 @@ static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso)
}
/* go through each layer, and ensure that we've got a valid frame to use */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
/* Make a new frame to work on if the layer's frame
@@ -1578,12 +1432,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
{
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
- const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
- gso->gp_brush->size * gso->pressure :
- gso->gp_brush->size;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
- bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ Brush *brush = gso->brush;
+ const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
+ gso->brush->size;
+
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt_active = NULL;
bGPDspoint *pt1, *pt2;
@@ -1595,13 +1448,19 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
bool include_last = false;
bool changed = false;
float rot_eval = 0.0f;
+
+ /* Check if the stroke collide with brush. */
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) {
+ return false;
+ }
+
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
pt = &gps->points[0];
gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
- pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
@@ -1627,7 +1486,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* Skip if neither one is selected
* (and we are only allowed to edit/consider selected points) */
- if ((GPENCIL_ANY_SCULPT_MASK(gso->mask)) && (!gso->is_weight_mode)) {
+ if (GPENCIL_ANY_SCULPT_MASK(gso->mask)) {
if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
include_last = false;
continue;
@@ -1654,8 +1513,8 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* To each point individually... */
pt = &gps->points[i];
- pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
- index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
if (pt_active != NULL) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
@@ -1671,8 +1530,8 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
*/
if (i + 1 == gps->totpoints - 1) {
pt = &gps->points[i + 1];
- pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
- index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1;
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
if (pt_active != NULL) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1);
ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
@@ -1692,8 +1551,8 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
* (but wasn't added then, to avoid double-ups).
*/
pt = &gps->points[i];
- pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
- index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
if (pt_active != NULL) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
@@ -1715,10 +1574,11 @@ static bool gpsculpt_brush_do_frame(bContext *C,
const float diff_mat[4][4])
{
bool changed = false;
- Object *ob = CTX_data_active_object(C);
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ bool redo_geom = false;
+ Object *ob = gso->object;
+ char tool = gso->brush->gpencil_sculpt_tool;
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -1728,28 +1588,29 @@ static bool gpsculpt_brush_do_frame(bContext *C,
continue;
}
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_SMOOTH: /* Smooth strokes */
+ switch (tool) {
+ case GPSCULPT_TOOL_SMOOTH: /* Smooth strokes */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
+ redo_geom |= changed;
break;
}
- case GP_SCULPT_TYPE_THICKNESS: /* Adjust stroke thickness */
+ case GPSCULPT_TOOL_THICKNESS: /* Adjust stroke thickness */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
break;
}
- case GP_SCULPT_TYPE_STRENGTH: /* Adjust stroke color strength */
+ case GPSCULPT_TOOL_STRENGTH: /* Adjust stroke color strength */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
break;
}
- case GP_SCULPT_TYPE_GRAB: /* Grab points */
+ case GPSCULPT_TOOL_GRAB: /* Grab points */
{
- bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
if (gps_active != NULL) {
if (gso->first) {
/* First time this brush stroke is being applied:
@@ -1757,7 +1618,8 @@ static bool gpsculpt_brush_do_frame(bContext *C,
* 2) Use the points now under the cursor
*/
gp_brush_grab_stroke_init(gso, gps_active);
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
+ changed |= gpsculpt_brush_do_stroke(
+ gso, gps_active, diff_mat, gp_brush_grab_store_points);
}
else {
/* Apply effect to the stored points */
@@ -1765,45 +1627,61 @@ static bool gpsculpt_brush_do_frame(bContext *C,
changed |= true;
}
}
+ redo_geom |= changed;
break;
}
- case GP_SCULPT_TYPE_PUSH: /* Push points */
+ case GPSCULPT_TOOL_PUSH: /* Push points */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
+ redo_geom |= changed;
break;
}
- case GP_SCULPT_TYPE_PINCH: /* Pinch points */
+ case GPSCULPT_TOOL_PINCH: /* Pinch points */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
+ redo_geom |= changed;
break;
}
- case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
+ case GPSCULPT_TOOL_TWIST: /* Twist points around midpoint */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
+ redo_geom |= changed;
break;
}
- case GP_SCULPT_TYPE_RANDOMIZE: /* Apply jitter */
+ case GPSCULPT_TOOL_RANDOMIZE: /* Apply jitter */
{
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_WEIGHT: /* Adjust vertex group weight */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
+ redo_geom |= changed;
break;
}
default:
- printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+ printf("ERROR: Unknown type of GPencil Sculpt brush \n");
break;
}
- /* Triangulation must be calculated if changed */
- gp_recalc_geometry(gps);
+
+ /* Triangulation must be calculated. */
+ if (redo_geom) {
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ if (gpl->actframe == gpf) {
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ /* Update active frame now, only if material has fill. */
+ if (gp_style->flag & GP_MATERIAL_FILL_SHOW) {
+ BKE_gpencil_stroke_geometry_update(gps_active);
+ }
+ else {
+ gpencil_recalc_geometry_tag(gps_active);
+ }
+ }
+ else {
+ /* Delay a full recalculation for other frames. */
+ gpencil_recalc_geometry_tag(gps_active);
+ }
+ }
}
return changed;
@@ -1812,17 +1690,19 @@ static bool gpsculpt_brush_do_frame(bContext *C,
/* Perform two-pass brushes which modify the existing strokes */
static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = gso->scene->toolsettings;
+ Depsgraph *depsgraph = gso->depsgraph;
Object *obact = gso->object;
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, obact);
- bGPdata *gpd = gso->gpd;
bool changed = false;
+ Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id);
+ bGPdata *gpd = (bGPdata *)ob_eval->data;
+
/* Calculate brush-specific data which applies equally to all points */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_GRAB: /* Grab points */
- case GP_SCULPT_TYPE_PUSH: /* Push points */
+ char tool = gso->brush->gpencil_sculpt_tool;
+ switch (tool) {
+ case GPSCULPT_TOOL_GRAB: /* Grab points */
+ case GPSCULPT_TOOL_PUSH: /* Push points */
{
/* calculate amount of displacement to apply */
gso->rot_eval = 0.0f;
@@ -1830,15 +1710,15 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
break;
}
- case GP_SCULPT_TYPE_PINCH: /* Pinch points */
- case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
+ case GPSCULPT_TOOL_PINCH: /* Pinch points */
+ case GPSCULPT_TOOL_TWIST: /* Twist points around midpoint */
{
/* calculate midpoint of the brush (in data space) */
gp_brush_calc_midpoint(gso);
break;
}
- case GP_SCULPT_TYPE_RANDOMIZE: /* Random jitter */
+ case GPSCULPT_TOOL_RANDOMIZE: /* Random jitter */
{
/* compute the displacement vector for the cursor (in data space) */
gso->rot_eval = 0.0f;
@@ -1851,21 +1731,15 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
}
/* Find visible strokes, and perform operations on those if hit */
- CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* If no active frame, don't do anything... */
- if (gpl->actframe == NULL) {
- continue;
- }
- /* Get evaluated frames array data */
- int idx_eval = BLI_findindex(&gpd->layers, gpl);
- bGPDframe *gpf_eval = &ob_eval->runtime.gpencil_evaluated_frames[idx_eval];
- if (gpf_eval == NULL) {
+ if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
continue;
}
/* calculate difference matrix */
float diff_mat[4][4];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
/* Active Frame or MultiFrame? */
if (gso->is_multiframe) {
@@ -1874,10 +1748,10 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
int f_end = 0;
if (gso->use_multiframe_falloff) {
- BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
}
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* Always do active frame; Otherwise, only include selected frames */
if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
/* compute multiframe falloff factor */
@@ -1897,12 +1771,13 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
}
}
else {
- /* Apply to active frame's strokes */
- gso->mf_falloff = 1.0f;
- changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf_eval, diff_mat);
+ if (gpl->actframe != NULL) {
+ /* Apply to active frame's strokes */
+ gso->mf_falloff = 1.0f;
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ }
}
}
- CTX_DATA_END;
return changed;
}
@@ -1911,10 +1786,9 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
tGP_BrushEditData *gso = op->customdata;
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
- const int radius = ((gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
- gso->gp_brush->size * gso->pressure :
- gso->gp_brush->size);
+ Brush *brush = gso->brush;
+ const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
+ gso->brush->size;
float mousef[2];
int mouse[2];
bool changed = false;
@@ -1947,7 +1821,8 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
gso->brush_rect.ymax = mouse[1] + radius;
/* Apply brush */
- if (gso->brush_type == GP_SCULPT_TYPE_CLONE) {
+ char tool = gso->brush->gpencil_sculpt_tool;
+ if (tool == GPSCULPT_TOOL_CLONE) {
changed = gpsculpt_brush_apply_clone(C, gso);
}
else {
@@ -1968,13 +1843,18 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
}
/* Running --------------------------------------------- */
+static Brush *gpsculpt_get_smooth_brush(tGP_BrushEditData *gso)
+{
+ Main *bmain = gso->bmain;
+ Brush *brush = BLI_findstring(&bmain->brushes, "Smooth Stroke", offsetof(ID, name) + 2);
+
+ return brush;
+}
/* helper - a record stroke, and apply paint event */
static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
{
tGP_BrushEditData *gso = op->customdata;
- ToolSettings *ts = CTX_data_tool_settings(C);
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
PointerRNA itemptr;
float mouse[2];
@@ -1997,19 +1877,17 @@ static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEven
}
RNA_float_set(&itemptr, "pressure", pressure);
- if (!gso->is_weight_mode) {
- if (event->shift) {
- gso->gp_brush_old = gso->gp_brush;
- gso->brush_type_old = gso->brush_type;
+ if (event->shift) {
+ gso->brush_prev = gso->brush;
- gso->gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
- gso->brush_type = GP_SCULPT_TYPE_SMOOTH;
+ gso->brush = gpsculpt_get_smooth_brush(gso);
+ if (gso->brush == NULL) {
+ gso->brush = gso->brush_prev;
}
- else {
- if (gso->gp_brush_old != NULL) {
- gso->gp_brush = gso->gp_brush_old;
- gso->brush_type = gso->brush_type_old;
- }
+ }
+ else {
+ if (gso->brush_prev != NULL) {
+ gso->brush = gso->brush_prev;
}
}
@@ -2058,25 +1936,26 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
gso = op->customdata;
/* initialise type-specific data (used for the entire session) */
- switch (gso->brush_type) {
+ char tool = gso->brush->gpencil_sculpt_tool;
+ switch (tool) {
/* Brushes requiring timer... */
- case GP_SCULPT_TYPE_THICKNESS:
- brush_rate = 0.01f; // XXX: hardcoded
+ case GPSCULPT_TOOL_THICKNESS:
+ brush_rate = 0.01f;
needs_timer = true;
break;
- case GP_SCULPT_TYPE_STRENGTH:
- brush_rate = 0.01f; // XXX: hardcoded
+ case GPSCULPT_TOOL_STRENGTH:
+ brush_rate = 0.01f;
needs_timer = true;
break;
- case GP_SCULPT_TYPE_PINCH:
- brush_rate = 0.001f; // XXX: hardcoded
+ case GPSCULPT_TOOL_PINCH:
+ brush_rate = 0.001f;
needs_timer = true;
break;
- case GP_SCULPT_TYPE_TWIST:
- brush_rate = 0.01f; // XXX: hardcoded
+ case GPSCULPT_TOOL_TWIST:
+ brush_rate = 0.01f;
needs_timer = true;
break;
@@ -2141,42 +2020,6 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
}
break;
- /* Adjust brush settings */
- /* FIXME: Step increments and modifier keys are hardcoded here! */
- case WHEELUPMOUSE:
- case PADPLUSKEY:
- if (event->shift) {
- /* increase strength */
- gso->gp_brush->strength += 0.05f;
- CLAMP_MAX(gso->gp_brush->strength, 1.0f);
- }
- else {
- /* increase brush size */
- gso->gp_brush->size += 3;
- CLAMP_MAX(gso->gp_brush->size, 300);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- case WHEELDOWNMOUSE:
- case PADMINUS:
- if (event->shift) {
- /* decrease strength */
- gso->gp_brush->strength -= 0.05f;
- CLAMP_MIN(gso->gp_brush->strength, 0.0f);
- }
- else {
- /* decrease brush size */
- gso->gp_brush->size -= 3;
- CLAMP_MIN(gso->gp_brush->size, 1);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
/* Painting mbut release = Stop painting (back to idle) */
case LEFTMOUSE:
// BLI_assert(event->val == KM_RELEASE);
@@ -2232,43 +2075,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
redraw_region = true;
break;
- /* Adjust brush settings */
- /* FIXME: Step increments and modifier keys are hardcoded here! */
- case WHEELUPMOUSE:
- case PADPLUSKEY:
- if (event->shift) {
- /* increase strength */
- gso->gp_brush->strength += 0.05f;
- CLAMP_MAX(gso->gp_brush->strength, 1.0f);
- }
- else {
- /* increase brush size */
- gso->gp_brush->size += 3;
- CLAMP_MAX(gso->gp_brush->size, 300);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- case WHEELDOWNMOUSE:
- case PADMINUS:
- if (event->shift) {
- /* decrease strength */
- gso->gp_brush->strength -= 0.05f;
- CLAMP_MIN(gso->gp_brush->strength, 0.0f);
- }
- else {
- /* decrease brush size */
- gso->gp_brush->size -= 3;
- CLAMP_MIN(gso->gp_brush->size, 1);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- /* Change Frame - Allowed */
+ /* Change Frame - Allowed */
case LEFTARROWKEY:
case RIGHTARROWKEY:
case UPARROWKEY:
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index be265ed4bd5..26b68707d55 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -84,17 +84,40 @@ static int gpencil_select_mode_from_sculpt(eGP_Sculpt_SelectMaskFlag mode)
}
}
+/* Convert vertex mask mode to Select mode */
+static int gpencil_select_mode_from_vertex(eGP_Sculpt_SelectMaskFlag mode)
+{
+ if (mode & GP_VERTEX_MASK_SELECTMODE_POINT) {
+ return GP_SELECTMODE_POINT;
+ }
+ else if (mode & GP_VERTEX_MASK_SELECTMODE_STROKE) {
+ return GP_SELECTMODE_STROKE;
+ }
+ else if (mode & GP_VERTEX_MASK_SELECTMODE_SEGMENT) {
+ return GP_SELECTMODE_SEGMENT;
+ }
+ else {
+ return GP_SELECTMODE_POINT;
+ }
+}
+
static bool gpencil_select_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
if (GPENCIL_SCULPT_MODE(gpd)) {
- ToolSettings *ts = CTX_data_tool_settings(C);
if (!(GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt))) {
return false;
}
}
+ if (GPENCIL_VERTEX_MODE(gpd)) {
+ if (!(GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex))) {
+ return false;
+ }
+ }
+
/* we just need some visible strokes, and to be in editmode or other modes only to catch event */
if (GPENCIL_ANY_MODE(gpd)) {
/* TODO: include a check for visible strokes? */
@@ -350,7 +373,7 @@ static void gp_select_same_layer(bContext *C)
Scene *scene = CTX_data_scene(C);
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
bGPDstroke *gps;
bool found = false;
@@ -832,7 +855,7 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
* from gpencil_paint.c #gp_stroke_eraser_dostroke().
* It would be great to de-duplicate the logic here sometime, but that can wait.
*/
-static bool gp_stroke_do_circle_sel(bGPdata *gpd,
+static bool gp_stroke_do_circle_sel(bGPdata *UNUSED(gpd),
bGPDlayer *gpl,
bGPDstroke *gps,
GP_SpaceConversion *gsc,
@@ -845,13 +868,12 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd,
const int selectmode,
const float scale)
{
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bGPDspoint *pt1 = NULL;
bGPDspoint *pt2 = NULL;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
int i;
bool changed = false;
- bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt_active = NULL;
if (gps->totpoints == 1) {
@@ -910,22 +932,22 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd,
*/
hit = true;
if (select) {
- pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ pt_active = pt1->runtime.pt_orig;
if (pt_active != NULL) {
pt_active->flag |= GP_SPOINT_SELECT;
}
- pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ pt_active = pt2->runtime.pt_orig;
if (pt_active != NULL) {
pt_active->flag |= GP_SPOINT_SELECT;
}
changed = true;
}
else {
- pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ pt_active = pt1->runtime.pt_orig;
if (pt_active != NULL) {
pt_active->flag &= ~GP_SPOINT_SELECT;
}
- pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ pt_active = pt2->runtime.pt_orig;
if (pt_active != NULL) {
pt_active->flag &= ~GP_SPOINT_SELECT;
}
@@ -942,7 +964,7 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd,
/* if stroke mode expand selection */
if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
- pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ pt_active = (pt1->runtime.pt_orig) ? pt1->runtime.pt_orig : pt1;
if (pt_active != NULL) {
if (select) {
pt_active->flag |= GP_SPOINT_SELECT;
@@ -955,7 +977,7 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd,
}
/* expand selection to segment */
- pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ pt_active = (pt1->runtime.pt_orig) ? pt1->runtime.pt_orig : pt1;
if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) {
float r_hita[3], r_hitb[3];
bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
@@ -976,9 +998,17 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
- const int selectmode = (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) ?
- gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) :
- ts->gpencil_selectmode_edit;
+ int selectmode;
+ if (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) {
+ selectmode = gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt);
+ }
+ else if (ob && ob->mode == OB_MODE_VERTEX_GPENCIL) {
+ selectmode = gpencil_select_mode_from_vertex(ts->gpencil_selectmode_vertex);
+ }
+ else {
+ selectmode = ts->gpencil_selectmode_edit;
+ }
+
const float scale = ts->gp_sculpt.isect_threshold;
/* if not edit/sculpt mode, the event is catched but not processed */
@@ -1100,9 +1130,16 @@ static int gpencil_generic_select_exec(bContext *C,
ToolSettings *ts = CTX_data_tool_settings(C);
ScrArea *sa = CTX_wm_area(C);
- const short selectmode = (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) ?
- gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) :
- ts->gpencil_selectmode_edit;
+ int selectmode;
+ if (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) {
+ selectmode = gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt);
+ }
+ else if (ob && ob->mode == OB_MODE_VERTEX_GPENCIL) {
+ selectmode = gpencil_select_mode_from_vertex(ts->gpencil_selectmode_vertex);
+ }
+ else {
+ selectmode = ts->gpencil_selectmode_edit;
+ }
const bool strokemode = ((selectmode == GP_SELECTMODE_STROKE) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
@@ -1145,16 +1182,16 @@ static int gpencil_generic_select_exec(bContext *C,
/* select/deselect points */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
- bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
+ if (pt->runtime.pt_orig == NULL) {
continue;
}
- bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ bGPDspoint *pt_active = pt->runtime.pt_orig;
/* convert point coords to screenspace */
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
@@ -1192,7 +1229,7 @@ static int gpencil_generic_select_exec(bContext *C,
if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
- bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
if (sel_op_result) {
pt_active->flag |= GP_SPOINT_SELECT;
@@ -1419,6 +1456,10 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
whole = (bool)(gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) ==
GP_SELECTMODE_STROKE);
}
+ else if ((ob) && (ob->mode == OB_MODE_VERTEX_GPENCIL)) {
+ whole = (bool)(gpencil_select_mode_from_vertex(ts->gpencil_selectmode_sculpt) ==
+ GP_SELECTMODE_STROKE);
+ }
else {
whole = (bool)(ts->gpencil_selectmode_edit == GP_SELECTMODE_STROKE);
}
@@ -1433,7 +1474,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* XXX: maybe we should go from the top of the stack down instead... */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
- bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
@@ -1526,9 +1567,16 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
hit_stroke->flag |= GP_STROKE_SELECT;
/* expand selection to segment */
- const short selectmode = (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) ?
- gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt) :
- ts->gpencil_selectmode_edit;
+ int selectmode;
+ if (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) {
+ selectmode = gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt);
+ }
+ else if (ob && ob->mode == OB_MODE_VERTEX_GPENCIL) {
+ selectmode = gpencil_select_mode_from_vertex(ts->gpencil_selectmode_vertex);
+ }
+ else {
+ selectmode = ts->gpencil_selectmode_edit;
+ }
if (selectmode == GP_SELECTMODE_SEGMENT) {
float r_hita[3], r_hitb[3];
@@ -1606,4 +1654,108 @@ void GPENCIL_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+/* Select by Vertex Color. */
+static bool gpencil_select_color_poll(bContext *C)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ if (GPENCIL_VERTEX_MODE(gpd)) {
+ if (!(GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex))) {
+ return false;
+ }
+
+ /* Any data to use. */
+ if (gpd->layers.first) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int gpencil_select_color_exec(bContext *C, wmOperator *op)
+{
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (!GPENCIL_VERTEX_MODE(gpd)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Paint *paint = &ts->gp_vertexpaint->paint;
+ Brush *brush = paint->brush;
+ bool done = false;
+
+ float hsv_brush[3], hsv_stroke[3];
+ rgb_to_hsv_compat_v(brush->rgb, hsv_brush);
+
+ /* Select any visible stroke that uses this color */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ bGPDspoint *pt;
+ int i;
+ bool gps_selected = false;
+ /* Check all stroke points. */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->vert_color[3] < 0.03f) {
+ continue;
+ }
+
+ rgb_to_hsv_compat_v(pt->vert_color, hsv_stroke);
+ /* Only check Hue to get full value and saturation ranges. */
+ if (compare_ff(hsv_stroke[0], hsv_brush[0], threshold)) {
+ pt->flag |= GP_SPOINT_SELECT;
+ gps_selected = true;
+ }
+ }
+
+ if (gps_selected) {
+ gps->flag |= GP_STROKE_SELECT;
+ done = true;
+ }
+ }
+ CTX_DATA_END;
+
+ if (done) {
+ /* updates */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+
+ /* copy on write tag is needed, or else no refresh happens */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE);
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_color(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Color";
+ ot->idname = "GPENCIL_OT_select_color";
+ ot->description = "Select all strokes with same color";
+
+ /* callbacks */
+ ot->exec = gpencil_select_color_exec;
+ ot->poll = gpencil_select_color_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_float(ot->srna, "threshold", 0.01f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+ /* avoid re-using last var */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/** \} */
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 7b57dacd3e4..f9403fd94b0 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -90,14 +90,14 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
if (gpd_ptr) {
if (*gpd_ptr) {
bGPdata *gpd = *gpd_ptr;
- bGPDlayer *gpl, *gpld;
+ bGPDlayer *gpld;
BKE_gpencil_free_layers(&gpd->layers);
/* copy layers */
BLI_listbase_clear(&gpd->layers);
- for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* make a copy of source layer and its data */
gpld = BKE_gpencil_layer_duplicate(gpl);
BLI_addtail(&gpd->layers, gpld);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 9c2e0f100cc..a975af1c19a 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -328,7 +328,7 @@ bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
{
if (ob && ob->data && (ob->type == OB_GPENCIL)) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(ob->data);
if (gpl) {
if (gpl->actframe) {
// XXX: assumes that frame has been fetched already
@@ -336,7 +336,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra)
}
else {
/* XXX: disabled as could be too much of a penalty */
- /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
+ /* return BKE_gpencil_layer_frame_find(gpl, cfra); */
}
}
}
@@ -367,7 +367,7 @@ bool gp_active_layer_poll(bContext *C)
return false;
}
bGPdata *gpd = (bGPdata *)ob->data;
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
return (gpl != NULL);
}
@@ -553,10 +553,10 @@ bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstr
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
if (gp_style != NULL) {
- if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
+ if (gp_style->flag & GP_MATERIAL_HIDE) {
return false;
}
- if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_MATERIAL_LOCKED)) {
return false;
}
}
@@ -630,8 +630,7 @@ void gp_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4],
/**
* Change position relative to parent object
*/
-void gp_apply_parent(
- Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
+void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt;
int i;
@@ -641,7 +640,7 @@ void gp_apply_parent(
float inverse_diff_mat[4][4];
float fpt[3];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
for (i = 0; i < gps->totpoints; i++) {
@@ -654,15 +653,14 @@ void gp_apply_parent(
/**
* Change point position relative to parent object
*/
-void gp_apply_parent_point(
- Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt)
+void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDspoint *pt)
{
/* undo matrix */
float diff_mat[4][4];
float inverse_diff_mat[4][4];
float fpt[3];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
@@ -870,7 +868,7 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
const RegionView3D *rv3d = gsc->region->regiondata;
float rvec[3];
- ED_gp_get_drawing_reference(
+ ED_gpencil_drawing_reference_get(
scene, gsc->ob, gsc->gpl, scene->toolsettings->gpencil_v3d_align, rvec);
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
@@ -930,7 +928,7 @@ void gp_stroke_convertcoords_tpoint(Scene *scene,
/* Current method just converts each point in screen-coordinates to
* 3D-coordinates using the 3D-cursor as reference.
*/
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
+ ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
zfac = ED_view3d_calc_zfac(region->regiondata, rvec, NULL);
if (ED_view3d_project_float_global(region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
@@ -949,7 +947,7 @@ void gp_stroke_convertcoords_tpoint(Scene *scene,
* Get drawing reference point for conversion or projection of the stroke
* \param[out] r_vec : Reference point found
*/
-void ED_gp_get_drawing_reference(
+void ED_gpencil_drawing_reference_get(
const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl), char align_flag, float r_vec[3])
{
const float *fp = scene->cursor.location;
@@ -979,7 +977,6 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = (bGPdata *)ob->data;
GP_SpaceConversion gsc = {NULL};
bGPDspoint *pt;
@@ -990,7 +987,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
/* init space conversion stuff */
gp_point_conversion_init(C, &gsc);
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
/* Adjust each point */
@@ -1182,7 +1179,6 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
if (gps->dvert != NULL) {
gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
}
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
/* move points from last to first to new place */
i2 = gps->totpoints - 1;
@@ -1197,6 +1193,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
pt_final->flag = pt->flag;
pt_final->uv_fac = pt->uv_fac;
pt_final->uv_rot = pt->uv_rot;
+ copy_v4_v4(pt_final->vert_color, pt->vert_color);
if (gps->dvert != NULL) {
MDeformVert *dvert = &gps->dvert[i];
@@ -1223,6 +1220,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f);
pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f);
+ interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
if (gps->dvert != NULL) {
MDeformVert *dvert_final = &gps->dvert[i2];
@@ -1251,116 +1249,11 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide)
/* free temp memory */
MEM_SAFE_FREE(temp_points);
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
-/**
- * Add randomness to stroke
- * \param gps: Stroke data
- * \param brush: Brush data
- */
-void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, RNG *rng)
-{
- bGPDspoint *pt1, *pt2, *pt3;
- float v1[3];
- float v2[3];
- if (gps->totpoints < 3) {
- return;
- }
-
- /* get two vectors using 3 points */
- pt1 = &gps->points[0];
- pt2 = &gps->points[1];
- pt3 = &gps->points[(int)(gps->totpoints * 0.75)];
-
- sub_v3_v3v3(v1, &pt2->x, &pt1->x);
- sub_v3_v3v3(v2, &pt3->x, &pt2->x);
- normalize_v3(v1);
- normalize_v3(v2);
-
- /* get normal vector to plane created by two vectors */
- float normal[3];
- cross_v3_v3v3(normal, v1, v2);
- normalize_v3(normal);
-
- /* get orthogonal vector to plane to rotate random effect */
- float ortho[3];
- cross_v3_v3v3(ortho, v1, normal);
- normalize_v3(ortho);
-
- /* Read all points and apply shift vector (first and last point not modified) */
- for (int i = 1; i < gps->totpoints - 1; i++) {
- bGPDspoint *pt = &gps->points[i];
- /* get vector with shift (apply a division because random is too sensitive */
- const float fac = BLI_rng_get_float(rng) * (brush->gpencil_settings->draw_random_sub / 10.0f);
- float svec[3];
- copy_v3_v3(svec, ortho);
- if (BLI_rng_get_float(rng) > 0.5f) {
- mul_v3_fl(svec, -fac);
- }
- else {
- mul_v3_fl(svec, fac);
- }
-
- /* apply shift */
- add_v3_v3(&pt->x, svec);
- }
-}
-
-/* ******************************************************** */
-/* Layer Parenting - Compute Parent Transforms */
-
-/* calculate difference matrix */
-void ED_gpencil_parent_location(const Depsgraph *depsgraph,
- Object *obact,
- bGPdata *UNUSED(gpd),
- 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 */
- }
- }
-}
-
-/* reset parent matrix for all layers */
+/* Reset parent matrix for all layers. */
void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd)
{
bGPDspoint *pt;
@@ -1370,7 +1263,7 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
float gpl_loc[3];
zero_v3(gpl_loc);
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl->parent != NULL) {
/* calculate new matrix */
if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) {
@@ -1390,12 +1283,12 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
/* only redo if any change */
if (!equals_m4m4(gpl->inverse, cur_mat)) {
/* first apply current transformation to all strokes */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
/* undo local object */
sub_v3_v3(diff_mat[3], gpl_loc);
- 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) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
mul_m4_v3(diff_mat, &pt->x);
}
@@ -1411,10 +1304,7 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
/* GP Object Stuff */
/* Helper function to create new OB_GPENCIL Object */
-Object *ED_gpencil_add_object(bContext *C,
- Scene *UNUSED(scene),
- const float loc[3],
- ushort local_view_bits)
+Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
{
float rot[3] = {0.0f};
@@ -1437,7 +1327,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts);
}
/* ensure a color exists and is assigned to object */
@@ -1676,8 +1566,11 @@ static bool gp_check_cursor_region(bContext *C, int mval_i[2])
ScrArea *sa = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) ||
- (!ELEM(ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
+ if ((ob == NULL) || (!ELEM(ob->mode,
+ OB_MODE_PAINT_GPENCIL,
+ OB_MODE_SCULPT_GPENCIL,
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL))) {
return false;
}
@@ -1753,22 +1646,14 @@ static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ARegion *region = CTX_wm_region(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
bGPdata *gpd = ED_gpencil_data_get_active(C);
- GP_Sculpt_Data *gp_brush = NULL;
Brush *brush = NULL;
Material *ma = NULL;
MaterialGPencilStyle *gp_style = NULL;
float *last_mouse_position = customdata;
- if ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) {
- gp_brush = &gset->brush[gset->weighttype];
- }
- else {
- gp_brush = &gset->brush[gset->brushtype];
- }
-
/* default radius and color */
float color[3] = {1.0f, 1.0f, 1.0f};
float darkcolor[3];
@@ -1794,7 +1679,7 @@ static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
return;
}
- if ((brush->gpencil_settings->flag & GP_BRUSH_ENABLE_CURSOR) == 0) {
+ if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
return;
}
@@ -1805,7 +1690,7 @@ static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
}
/* get current drawing color */
- ma = BKE_gpencil_object_material_get_from_brush(ob, brush);
+ ma = BKE_gpencil_object_material_from_brush_get(ob, brush);
if (ma) {
gp_style = ma->gp_style;
@@ -1822,29 +1707,73 @@ static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata)
copy_v3_v3(color, gp_style->stroke_rgba);
}
else {
- radius = 5.0f;
- copy_v3_v3(color, brush->add_col);
+ /* Only Tint tool must show big cursor. */
+ if (brush->gpencil_tool == GPAINT_TOOL_TINT) {
+ radius = brush->size;
+ copy_v3_v3(color, brush->rgb);
+ }
+ else {
+ radius = 5.0f;
+ copy_v3_v3(color, brush->add_col);
+ }
}
}
}
- /* for sculpt use sculpt brush size */
- if (GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd)) {
- if (gp_brush) {
- if ((gp_brush->flag & GP_SCULPT_FLAG_ENABLE_CURSOR) == 0) {
- return;
- }
+ /* Sculpt use sculpt brush size */
+ if (GPENCIL_SCULPT_MODE(gpd)) {
+ brush = scene->toolsettings->gp_sculptpaint->paint.brush;
+ if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
+ return;
+ }
+ if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
+ return;
+ }
- radius = gp_brush->size;
- if (gp_brush->flag & (GP_SCULPT_FLAG_INVERT | GP_SCULPT_FLAG_TMP_INVERT)) {
- copy_v3_v3(color, gp_brush->curcolor_sub);
- }
- else {
- copy_v3_v3(color, gp_brush->curcolor_add);
- }
+ radius = brush->size;
+ if (brush->gpencil_settings->sculpt_flag &
+ (GP_SCULPT_FLAG_INVERT | GP_SCULPT_FLAG_TMP_INVERT)) {
+ copy_v3_v3(color, brush->sub_col);
+ }
+ else {
+ copy_v3_v3(color, brush->add_col);
+ }
+ }
+
+ /* Weight Paint */
+ if (GPENCIL_WEIGHT_MODE(gpd)) {
+ brush = scene->toolsettings->gp_weightpaint->paint.brush;
+ if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
+ return;
+ }
+ if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
+ return;
+ }
+
+ radius = brush->size;
+ if (brush->gpencil_settings->sculpt_flag &
+ (GP_SCULPT_FLAG_INVERT | GP_SCULPT_FLAG_TMP_INVERT)) {
+ copy_v3_v3(color, brush->sub_col);
+ }
+ else {
+ copy_v3_v3(color, brush->add_col);
}
}
+ /* For Vertex Paint use brush size. */
+ if (GPENCIL_VERTEX_MODE(gpd)) {
+ brush = scene->toolsettings->gp_vertexpaint->paint.brush;
+ if ((brush == NULL) || (brush->gpencil_settings == NULL)) {
+ return;
+ }
+ if ((paint->flags & PAINT_SHOW_BRUSH) == 0) {
+ return;
+ }
+
+ radius = brush->size;
+ copy_v3_v3(color, brush->rgb);
+ }
+
/* draw icon */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -1924,30 +1853,6 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
}
}
-/* verify if is using the right brush */
-static void gpencil_verify_brush_type(bContext *C, int newmode)
-{
- ToolSettings *ts = CTX_data_tool_settings(C);
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
-
- switch (newmode) {
- case OB_MODE_SCULPT_GPENCIL:
- gset->flag &= ~GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
- if ((gset->brushtype < 0) || (gset->brushtype >= GP_SCULPT_TYPE_WEIGHT)) {
- gset->brushtype = GP_SCULPT_TYPE_PUSH;
- }
- break;
- case OB_MODE_WEIGHT_GPENCIL:
- gset->flag |= GP_SCULPT_SETT_FLAG_WEIGHT_MODE;
- if ((gset->weighttype < GP_SCULPT_TYPE_WEIGHT) || (gset->weighttype >= GP_SCULPT_TYPE_MAX)) {
- gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
- }
- break;
- default:
- break;
- }
-}
-
/* set object modes */
void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
{
@@ -1961,6 +1866,7 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_VERTEXMODE;
ED_gpencil_toggle_brush_cursor(C, false, NULL);
break;
case OB_MODE_PAINT_GPENCIL:
@@ -1968,6 +1874,7 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
gpd->flag |= GP_DATA_STROKE_PAINTMODE;
gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_VERTEXMODE;
ED_gpencil_toggle_brush_cursor(C, true, NULL);
break;
case OB_MODE_SCULPT_GPENCIL:
@@ -1975,7 +1882,7 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
gpd->flag |= GP_DATA_STROKE_SCULPTMODE;
gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
- gpencil_verify_brush_type(C, OB_MODE_SCULPT_GPENCIL);
+ gpd->flag &= ~GP_DATA_STROKE_VERTEXMODE;
ED_gpencil_toggle_brush_cursor(C, true, NULL);
break;
case OB_MODE_WEIGHT_GPENCIL:
@@ -1983,7 +1890,15 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
gpd->flag |= GP_DATA_STROKE_WEIGHTMODE;
- gpencil_verify_brush_type(C, OB_MODE_WEIGHT_GPENCIL);
+ gpd->flag &= ~GP_DATA_STROKE_VERTEXMODE;
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ break;
+ case OB_MODE_VERTEX_GPENCIL:
+ gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
+ gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ gpd->flag |= GP_DATA_STROKE_VERTEXMODE;
ED_gpencil_toggle_brush_cursor(C, true, NULL);
break;
default:
@@ -1991,6 +1906,7 @@ void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode)
gpd->flag &= ~GP_DATA_STROKE_PAINTMODE;
gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
+ gpd->flag &= ~GP_DATA_STROKE_VERTEXMODE;
ED_gpencil_toggle_brush_cursor(C, false, NULL);
break;
}
@@ -2032,6 +1948,7 @@ void ED_gpencil_tpoint_to_point(ARegion *region,
/* conversion to 3d format */
gpencil_stroke_convertcoords(region, tpt, origin, p3d);
copy_v3_v3(&pt->x, p3d);
+ zero_v4(pt->vert_color);
pt->pressure = tpt->pressure;
pt->strength = tpt->strength;
@@ -2039,63 +1956,6 @@ void ED_gpencil_tpoint_to_point(ARegion *region,
pt->uv_rot = tpt->uv_rot;
}
-/* texture coordinate utilities */
-void ED_gpencil_calc_stroke_uv(Object *ob, bGPDstroke *gps)
-{
- if (gps == NULL) {
- return;
- }
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- float pixsize;
- if (gp_style) {
- pixsize = gp_style->texture_pixsize / 1000000.0f;
- }
- else {
- /* use this value by default */
- pixsize = 0.0001f;
- }
- pixsize = MAX2(pixsize, 0.0000001f);
-
- bGPDspoint *pt = NULL;
- bGPDspoint *ptb = NULL;
- int i;
- float totlen = 0.0f;
-
- /* first read all points and calc distance */
- for (i = 0; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- /* first point */
- if (i == 0) {
- pt->uv_fac = 0.0f;
- continue;
- }
-
- ptb = &gps->points[i - 1];
- totlen += len_v3v3(&pt->x, &ptb->x) / pixsize;
- pt->uv_fac = totlen;
- }
-
- /* normalize the distance using a factor */
- float factor;
-
- /* if image, use texture width */
- if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) &&
- (gp_style->sima)) {
- factor = gp_style->sima->gen_x;
- }
- else if (totlen == 0) {
- return;
- }
- else {
- factor = totlen;
- }
-
- for (i = 0; i < gps->totpoints; i++) {
- pt = &gps->points[i];
- pt->uv_fac /= factor;
- }
-}
-
/* recalc uv for any stroke using the material */
void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
{
@@ -2108,11 +1968,11 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
continue;
}
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl)) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (BKE_gpencil_layer_is_editable(gpl)) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* check if it is editable */
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
@@ -2120,7 +1980,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
gps_ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
/* update */
if ((gps_ma) && (gps_ma == mat)) {
- ED_gpencil_calc_stroke_uv(ob, gps);
+ BKE_gpencil_stroke_uv_update(gps);
}
}
}
@@ -2197,6 +2057,7 @@ static void gp_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final
pt_final->flag = pt->flag;
pt_final->uv_fac = pt->uv_fac;
pt_final->uv_rot = pt->uv_rot;
+ copy_v4_v4(pt_final->vert_color, pt->vert_color);
if (gps->dvert != NULL) {
MDeformVert *dvert = &gps->dvert[i];
@@ -2251,7 +2112,6 @@ static void gp_insert_point(
if (gps->dvert != NULL) {
gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
}
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
/* copy all points */
int i2 = 0;
@@ -2275,6 +2135,8 @@ static void gp_insert_point(
i2++;
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
MEM_SAFE_FREE(temp_points);
}
@@ -2518,10 +2380,9 @@ void ED_gpencil_select_toggle_all(bContext *C, int action)
* nothing should be able to touch it
*/
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf;
/* deselect all strokes on all frames */
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
@@ -2618,6 +2479,18 @@ tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
return buffer_array;
}
+void ED_gpencil_sbuffer_update_eval(bGPdata *gpd, Object *ob_eval)
+{
+ bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
+
+ gpd_eval->runtime.sbuffer = gpd->runtime.sbuffer;
+ gpd_eval->runtime.sbuffer_sflag = gpd->runtime.sbuffer_sflag;
+ gpd_eval->runtime.sbuffer_used = gpd->runtime.sbuffer_used;
+ gpd_eval->runtime.sbuffer_size = gpd->runtime.sbuffer_size;
+ gpd_eval->runtime.tot_cp_points = gpd->runtime.tot_cp_points;
+ gpd_eval->runtime.cp_points = gpd->runtime.cp_points;
+}
+
/* Tag all scene grease pencil object to update. */
void ED_gpencil_tag_scene_gpencil(Scene *scene)
{
@@ -2638,3 +2511,107 @@ void ED_gpencil_tag_scene_gpencil(Scene *scene)
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
+
+void ED_gpencil_fill_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDstroke *gps)
+{
+ if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) {
+ copy_v3_v3(gps->vert_color_fill, brush->rgb);
+ gps->vert_color_fill[3] = brush->gpencil_settings->vertex_factor;
+ srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill);
+ }
+ else {
+ zero_v4(gps->vert_color_fill);
+ }
+}
+
+void ED_gpencil_point_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDspoint *pt)
+{
+ if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
+ copy_v3_v3(pt->vert_color, brush->rgb);
+ pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
+ srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color);
+ }
+ else {
+ zero_v4(pt->vert_color);
+ }
+}
+
+void ED_gpencil_sbuffer_vertex_color_set(
+ Depsgraph *depsgraph, Object *ob, ToolSettings *ts, Brush *brush, Material *material)
+{
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id);
+ bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
+ MaterialGPencilStyle *gp_style = material->gp_style;
+
+ float vertex_color[4];
+ copy_v3_v3(vertex_color, brush->rgb);
+ vertex_color[3] = brush->gpencil_settings->vertex_factor;
+ srgb_to_linearrgb_v4(vertex_color, vertex_color);
+
+ /* Copy fill vertex color. */
+ if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) {
+ copy_v4_v4(gpd->runtime.vert_color_fill, vertex_color);
+ }
+ else {
+ copy_v4_v4(gpd->runtime.vert_color_fill, gp_style->fill_rgba);
+ }
+ /* Copy stroke vertex color. */
+ if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
+ copy_v4_v4(gpd->runtime.vert_color, vertex_color);
+ }
+ else {
+ copy_v4_v4(gpd->runtime.vert_color, gp_style->stroke_rgba);
+ }
+
+ /* Copy to eval data because paint operators don't tag refresh until end for speedup painting. */
+ if (gpd_eval != NULL) {
+ copy_v4_v4(gpd_eval->runtime.vert_color, gpd->runtime.vert_color);
+ copy_v4_v4(gpd_eval->runtime.vert_color_fill, gpd->runtime.vert_color_fill);
+ gpd_eval->runtime.matid = gpd->runtime.matid;
+ }
+}
+
+/* Check if the stroke collides with brush. */
+bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc,
+ bGPDstroke *gps,
+ float mouse[2],
+ const int radius,
+ const float diff_mat[4][4])
+{
+ const int offset = (int)ceil(sqrt((radius * radius) * 2));
+ bGPDspoint pt_dummy, pt_dummy_ps;
+ float boundbox_min[2] = {0.0f};
+ float boundbox_max[2] = {0.0f};
+ float zerov3[3];
+
+ /* Check we have something to use (only for old files). */
+ if (equals_v3v3(zerov3, gps->boundbox_min)) {
+ BKE_gpencil_stroke_boundingbox_calc(gps);
+ }
+
+ /* Convert bound box to 2d */
+ copy_v3_v3(&pt_dummy.x, gps->boundbox_min);
+ gp_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps);
+ gp_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &boundbox_min[0], &boundbox_min[1]);
+
+ copy_v3_v3(&pt_dummy.x, gps->boundbox_max);
+ gp_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps);
+ gp_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &boundbox_max[0], &boundbox_max[1]);
+
+ /* Ensure the bounding box is oriented to axis. */
+ if (boundbox_max[0] < boundbox_min[0]) {
+ SWAP(float, boundbox_min[0], boundbox_max[0]);
+ }
+ if (boundbox_max[1] < boundbox_min[1]) {
+ SWAP(float, boundbox_min[1], boundbox_max[1]);
+ }
+
+ rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]};
+
+ /* For mouse, add a small offet to avoid false negative in corners. */
+ rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset};
+
+ /* Check collision between both rectangles. */
+ return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
+}
diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c
new file mode 100644
index 00000000000..5e397374437
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_uv.c
@@ -0,0 +1,587 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edgpencil
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_unit.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+
+#include "ED_gpencil.h"
+#include "ED_numinput.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+typedef struct GpUvData {
+ Object *ob;
+ bGPdata *gpd;
+ GP_SpaceConversion gsc;
+ float ob_scale;
+
+ float initial_length;
+ float pixel_size; /* use when mouse input is interpreted as spatial distance */
+ bool is_modal;
+
+ /* Arrays of original loc/rot/scale by stroke. */
+ float (*array_loc)[2];
+ float *array_rot;
+ float *array_scale;
+
+ /* modal only */
+ float mcenter[2];
+ float mouse[2];
+
+ /** Vector with the original orientation. */
+ float vinit_rotation[2];
+
+ void *draw_handle_pixel;
+} GpUvData;
+
+enum {
+ GP_UV_ROTATE = 0,
+ GP_UV_TRANSLATE = 1,
+ GP_UV_SCALE = 2,
+ GP_UV_ALL = 3,
+};
+
+#define SMOOTH_FACTOR 0.3f
+
+static void gpencil_uv_transform_update_header(wmOperator *op, bContext *C)
+{
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const char *str = TIP_("Confirm: Enter/LClick, Cancel: (Esc/RClick) %s");
+
+ char msg[UI_MAX_DRAW_STR];
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa) {
+ char flts_str[NUM_STR_REP_LEN * 2];
+ switch (mode) {
+ case GP_UV_TRANSLATE: {
+ float location[2];
+ RNA_float_get_array(op->ptr, "location", location);
+ BLI_snprintf(
+ flts_str, NUM_STR_REP_LEN, ", Translation: (%f, %f)", location[0], location[1]);
+ break;
+ }
+ case GP_UV_ROTATE: {
+ BLI_snprintf(flts_str,
+ NUM_STR_REP_LEN,
+ ", Rotation: %f",
+ RAD2DEG(RNA_float_get(op->ptr, "rotation")));
+ break;
+ }
+ case GP_UV_SCALE: {
+ BLI_snprintf(
+ flts_str, NUM_STR_REP_LEN, ", Scale: %f", RAD2DEG(RNA_float_get(op->ptr, "scale")));
+ break;
+ }
+ default:
+ break;
+ }
+ BLI_snprintf(msg, sizeof(msg), str, flts_str, flts_str + NUM_STR_REP_LEN);
+ ED_area_status_text(sa, msg);
+ }
+}
+
+/* Helper: Get stroke center. */
+static void gpencil_stroke_center(bGPDstroke *gps, float r_center[3])
+{
+ bGPDspoint *pt;
+ int i;
+
+ zero_v3(r_center);
+ if (gps->totpoints > 0) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(r_center, &pt->x);
+ }
+
+ mul_v3_fl(r_center, 1.0f / gps->totpoints);
+ }
+}
+
+static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is_modal)
+{
+ GpUvData *opdata;
+ if (is_modal) {
+ float zero[2] = {0.0f};
+ RNA_float_set_array(op->ptr, "location", zero);
+ RNA_float_set(op->ptr, "rotation", 0.0f);
+ RNA_float_set(op->ptr, "scale", 1.0f);
+ }
+
+ op->customdata = opdata = MEM_mallocN(sizeof(GpUvData), __func__);
+
+ opdata->is_modal = is_modal;
+ opdata->ob = CTX_data_active_object(C);
+ opdata->gpd = (bGPdata *)opdata->ob->data;
+ gp_point_conversion_init(C, &opdata->gsc);
+ opdata->array_loc = NULL;
+ opdata->array_rot = NULL;
+ opdata->array_scale = NULL;
+ opdata->ob_scale = mat4_to_scale(opdata->ob->obmat);
+
+ opdata->vinit_rotation[0] = 1.0f;
+ opdata->vinit_rotation[1] = 0.0f;
+
+ if (is_modal) {
+ ARegion *region = CTX_wm_region(C);
+
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(
+ region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
+ }
+
+ /* Calc selected strokes center. */
+ zero_v2(opdata->mcenter);
+ float center[3] = {0.0f};
+ int i = 0;
+ /* Need use evaluated to get the viewport final position. */
+ GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ float r_center[3];
+ gpencil_stroke_center(gps, r_center);
+ /* Add object location. */
+ add_v3_v3(r_center, opdata->ob->obmat[3]);
+ add_v3_v3(center, r_center);
+ i++;
+ }
+ }
+ GP_EVALUATED_STROKES_END(gpstroke_iter);
+
+ if (i > 0) {
+ mul_v3_fl(center, 1.0f / i);
+ /* Create arrays to save all transformations. */
+ opdata->array_loc = MEM_calloc_arrayN(i, 2 * sizeof(float), __func__);
+ opdata->array_rot = MEM_calloc_arrayN(i, sizeof(float), __func__);
+ opdata->array_scale = MEM_calloc_arrayN(i, sizeof(float), __func__);
+ i = 0;
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ copy_v2_v2(opdata->array_loc[i], gps->uv_translation);
+ opdata->array_rot[i] = gps->uv_rotation;
+ opdata->array_scale[i] = gps->uv_scale;
+ i++;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+ }
+ /* convert to 2D */
+ gp_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter);
+
+ return true;
+}
+
+static void gpencil_uv_transform_exit(bContext *C, wmOperator *op)
+{
+ GpUvData *opdata;
+ ScrArea *sa = CTX_wm_area(C);
+
+ opdata = op->customdata;
+
+ if (opdata->is_modal) {
+ ARegion *region = CTX_wm_region(C);
+
+ ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
+ }
+
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
+
+ if (sa) {
+ ED_area_status_text(sa, NULL);
+ }
+ WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
+
+ MEM_SAFE_FREE(opdata->array_loc);
+ MEM_SAFE_FREE(opdata->array_rot);
+ MEM_SAFE_FREE(opdata->array_scale);
+ MEM_SAFE_FREE(op->customdata);
+}
+
+static void gpencil_transform_fill_cancel(bContext *C, wmOperator *op)
+{
+ GpUvData *opdata = op->customdata;
+ UNUSED_VARS(opdata);
+
+ gpencil_uv_transform_exit(C, op);
+
+ /* need to force redisplay or we may still view the modified result */
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
+static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
+{
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ GpUvData *opdata = op->customdata;
+ bGPdata *gpd = opdata->gpd;
+ bool changed = false;
+ /* Get actual vector. */
+ float vr[2];
+ sub_v2_v2v2(vr, opdata->mouse, opdata->mcenter);
+ normalize_v2(vr);
+
+ float location[2];
+ RNA_float_get_array(op->ptr, "location", location);
+
+ float uv_rotation = (opdata->is_modal) ? angle_signed_v2v2(opdata->vinit_rotation, vr) :
+ RNA_float_get(op->ptr, "rotation");
+ uv_rotation *= SMOOTH_FACTOR;
+
+ if (opdata->is_modal) {
+ RNA_float_set(op->ptr, "rotation", uv_rotation);
+ }
+
+ int i = 0;
+
+ /* Apply transformations to all strokes. */
+ if ((mode == GP_UV_TRANSLATE) || (!opdata->is_modal)) {
+ float mdiff[2];
+ mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
+ mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
+
+ /* Apply a big amount of smooth always for translate to get smooth result. */
+ mul_v2_fl(mdiff, 0.006f);
+
+ /* Apply angle in translation. */
+ mdiff[0] *= cos(uv_rotation);
+ mdiff[1] *= sin(uv_rotation);
+ if (opdata->is_modal) {
+ RNA_float_set_array(op->ptr, "location", mdiff);
+ }
+
+ changed = (bool)((mdiff[0] != 0.0f) || (mdiff[1] != 0.0f));
+ if (changed) {
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ if (opdata->is_modal) {
+ add_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff);
+ }
+ else {
+ copy_v2_v2(gps->uv_translation, location);
+ }
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ i++;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+ }
+ }
+
+ if ((mode == GP_UV_ROTATE) || (!opdata->is_modal)) {
+ changed = (bool)(uv_rotation != 0.0f);
+ if (changed) {
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ gps->uv_rotation = (opdata->is_modal) ? opdata->array_rot[i] + uv_rotation : uv_rotation;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ i++;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+ }
+ }
+
+ if ((mode == GP_UV_SCALE) || (!opdata->is_modal)) {
+ float mdiff[2];
+ mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
+ mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
+ float scale = (opdata->is_modal) ?
+ ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) /
+ opdata->ob_scale :
+ RNA_float_get(op->ptr, "scale");
+ scale *= SMOOTH_FACTOR;
+
+ if (opdata->is_modal) {
+ RNA_float_set(op->ptr, "scale", scale);
+ }
+
+ changed = (bool)(scale != 0.0f);
+ if (changed) {
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ gps->uv_scale = (opdata->is_modal) ? opdata->array_scale[i] + scale : scale;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ i++;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+ }
+ }
+
+ if ((!opdata->is_modal) || (changed)) {
+ /* Update cursor line. */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return changed;
+}
+
+static int gpencil_transform_fill_exec(bContext *C, wmOperator *op)
+{
+ if (!gpencil_uv_transform_init(C, op, false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!gpencil_uv_transform_calc(C, op)) {
+ gpencil_uv_transform_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
+ gpencil_uv_transform_exit(C, op);
+ return OPERATOR_FINISHED;
+}
+
+static bool gpencil_transform_fill_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd == NULL) {
+ return false;
+ }
+
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+
+ if ((gpl == NULL) || (ob->mode != OB_MODE_EDIT_GPENCIL)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float mlen[2];
+ float center_3d[3];
+
+ if (!gpencil_uv_transform_init(C, op, true)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ GpUvData *opdata = op->customdata;
+ /* initialize mouse values */
+ opdata->mouse[0] = event->mval[0];
+ opdata->mouse[1] = event->mval[1];
+
+ copy_v3_v3(center_3d, opdata->ob->loc);
+ mlen[0] = opdata->mcenter[0] - event->mval[0];
+ mlen[1] = opdata->mcenter[1] - event->mval[1];
+ opdata->initial_length = len_v2(mlen);
+
+ opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
+
+ /* Calc init rotation vector. */
+ float mouse[2] = {event->mval[0], event->mval[1]};
+ sub_v2_v2v2(opdata->vinit_rotation, mouse, opdata->mcenter);
+ normalize_v2(opdata->vinit_rotation);
+
+ gpencil_uv_transform_calc(C, op);
+
+ gpencil_uv_transform_update_header(op, C);
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_EW_ARROW);
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gpencil_transform_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ GpUvData *opdata = op->customdata;
+
+ switch (event->type) {
+ case ESCKEY:
+ case RIGHTMOUSE: {
+ gpencil_transform_fill_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ case MOUSEMOVE: {
+ opdata->mouse[0] = event->mval[0];
+ opdata->mouse[1] = event->mval[1];
+
+ if (gpencil_uv_transform_calc(C, op)) {
+ gpencil_uv_transform_update_header(op, C);
+ }
+ else {
+ gpencil_transform_fill_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ }
+ case LEFTMOUSE:
+ case PADENTER:
+ case RETKEY: {
+ if ((event->val == KM_PRESS) ||
+ ((event->val == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm"))) {
+ gpencil_uv_transform_calc(C, op);
+ gpencil_uv_transform_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void GPENCIL_OT_transform_fill(wmOperatorType *ot)
+{
+ static const EnumPropertyItem uv_mode[] = {
+ {GP_UV_TRANSLATE, "TRANSLATE", 0, "Translate", ""},
+ {GP_UV_ROTATE, "ROTATE", 0, "Rotate", ""},
+ {GP_UV_SCALE, "SCALE", 0, "Scale", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Transform Stroke Fill";
+ ot->idname = "GPENCIL_OT_transform_fill";
+ ot->description = "Transform Grease Pencil Stroke Fill";
+
+ /* api callbacks */
+ ot->invoke = gpencil_transform_fill_invoke;
+ ot->modal = gpencil_transform_fill_modal;
+ ot->exec = gpencil_transform_fill_exec;
+ ot->cancel = gpencil_transform_fill_cancel;
+ ot->poll = gpencil_transform_fill_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_XY | OPTYPE_BLOCKING;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", uv_mode, GP_UV_ROTATE, "Mode", "");
+
+ prop = RNA_def_float_vector(
+ ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_float_rotation(ot->srna,
+ "rotation",
+ 0,
+ NULL,
+ DEG2RADF(-360.0f),
+ DEG2RADF(360.0f),
+ "Rotation",
+ "",
+ DEG2RADF(-360.0f),
+ DEG2RADF(360.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(0.0f));
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_float(ot->srna, "scale", 1.0f, 0.001f, 100.0f, "Scale", "", 0.001f, 100.0f);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/* Clear UV transformations. */
+static int gpencil_reset_transform_fill_exec(bContext *C, wmOperator *op)
+{
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bool changed = false;
+
+ /* Loop all selected strokes and reset. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ if ((mode == GP_UV_TRANSLATE) || (mode == GP_UV_ALL)) {
+ zero_v2(gps->uv_translation);
+ }
+ if ((mode == GP_UV_ROTATE) || (mode == GP_UV_ALL)) {
+ gps->uv_rotation = 0.0f;
+ }
+ if ((mode == GP_UV_SCALE) || (mode == GP_UV_ALL)) {
+ gps->uv_scale = 1.0f;
+ }
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ changed = true;
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_reset_transform_fill(wmOperatorType *ot)
+{
+ static const EnumPropertyItem uv_clear_mode[] = {
+ {GP_UV_ALL, "ALL", 0, "All", ""},
+ {GP_UV_TRANSLATE, "TRANSLATE", 0, "Translate", ""},
+ {GP_UV_ROTATE, "ROTATE", 0, "Rotate", ""},
+ {GP_UV_SCALE, "SCALE", 0, "Scale", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Reset Fill Transformations";
+ ot->idname = "GPENCIL_OT_reset_transform_fill";
+ ot->description = "Reset any UV transformation and back to default values";
+
+ /* callbacks */
+ ot->exec = gpencil_reset_transform_fill_exec;
+ ot->poll = gpencil_transform_fill_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", uv_clear_mode, GP_UV_ALL, "Mode", "");
+}
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
new file mode 100644
index 00000000000..6a3eebf1baf
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -0,0 +1,899 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * This is a new part of Blender
+ * Brush based operators for editing Grease Pencil strokes
+ */
+
+/** \file
+ * \ingroup edgpencil
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_paint.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+enum {
+ GP_PAINT_VERTEX_STROKE = 0,
+ GP_PAINT_VERTEX_FILL = 1,
+ GP_PAINT_VERTEX_BOTH = 2,
+};
+
+static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = {
+ {GP_PAINT_VERTEX_STROKE, "STROKE", 0, "Stroke", ""},
+ {GP_PAINT_VERTEX_FILL, "FILL", 0, "Fill", ""},
+ {GP_PAINT_VERTEX_BOTH, "BOTH", 0, "Both", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/* Poll callback for stroke vertex paint operator. */
+static bool gp_vertexpaint_mode_poll(bContext *C)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (GPENCIL_VERTEX_MODE(gpd)) {
+ if (!(GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex))) {
+ return false;
+ }
+
+ /* Any data to use. */
+ if (gpd->layers.first) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int gp_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bool changed = false;
+ int i;
+ bGPDspoint *pt;
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ float gain, offset;
+ {
+ float brightness = RNA_float_get(op->ptr, "brightness");
+ float contrast = RNA_float_get(op->ptr, "contrast");
+ brightness /= 100.0f;
+ float delta = contrast / 200.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ gain = 1.0f - delta * 2.0f;
+ gain = 1.0f / max_ff(gain, FLT_EPSILON);
+ offset = gain * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ gain = max_ff(1.0f - delta * 2.0f, 0.0f);
+ offset = gain * brightness + delta;
+ }
+ }
+
+ /* Loop all selected strokes. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed = true;
+ /* Fill color. */
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed = true;
+ if (mode != GP_PAINT_VERTEX_STROKE) {
+ if (gps->vert_color_fill[3] > 0.0f) {
+ for (int i2 = 0; i2 < 3; i2++) {
+ gps->vert_color_fill[i2] = gain * gps->vert_color_fill[i2] + offset;
+ }
+ }
+ }
+ }
+
+ /* Stroke points. */
+ if (mode != GP_PAINT_VERTEX_FILL) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
+ for (int i2 = 0; i2 < 3; i2++) {
+ pt->vert_color[i2] = gain * pt->vert_color[i2] + offset;
+ }
+ }
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Vertex Paint Bright/Contrast";
+ ot->idname = "GPENCIL_OT_vertex_color_brightness_contrast";
+ ot->description = "Adjust vertex color brightness/contrast";
+
+ /* api callbacks */
+ ot->exec = gp_vertexpaint_brightness_contrast_exec;
+ ot->poll = gp_vertexpaint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
+ const float min = -100, max = +100;
+ prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
+ prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
+ RNA_def_property_ui_range(prop, min, max, 1, 1);
+}
+
+static int gp_vertexpaint_hsv_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ bool changed = false;
+ int i;
+ bGPDspoint *pt;
+ float hsv[3];
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ float hue = RNA_float_get(op->ptr, "h");
+ float sat = RNA_float_get(op->ptr, "s");
+ float val = RNA_float_get(op->ptr, "v");
+
+ /* Loop all selected strokes. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed = true;
+
+ /* Fill color. */
+ if (mode != GP_PAINT_VERTEX_STROKE) {
+ if (gps->vert_color_fill[3] > 0.0f) {
+
+ rgb_to_hsv_v(gps->vert_color_fill, hsv);
+
+ hsv[0] += (hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= sat;
+ hsv[2] *= val;
+
+ hsv_to_rgb_v(hsv, gps->vert_color_fill);
+ }
+ }
+
+ /* Stroke points. */
+ if (mode != GP_PAINT_VERTEX_FILL) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
+ rgb_to_hsv_v(pt->vert_color, hsv);
+
+ hsv[0] += (hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= sat;
+ hsv[2] *= val;
+
+ hsv_to_rgb_v(hsv, pt->vert_color);
+ }
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_vertex_color_hsv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Hue Saturation Value";
+ ot->idname = "GPENCIL_OT_vertex_color_hsv";
+ ot->description = "Adjust vertex color HSV values";
+
+ /* api callbacks */
+ ot->exec = gp_vertexpaint_hsv_exec;
+ ot->poll = gp_vertexpaint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
+ RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
+}
+
+static int gp_vertexpaint_invert_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ bool changed = false;
+ int i;
+ bGPDspoint *pt;
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* Loop all selected strokes. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed = true;
+ /* Fill color. */
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed = true;
+ if (mode != GP_PAINT_VERTEX_STROKE) {
+ if (gps->vert_color_fill[3] > 0.0f) {
+ for (int i2 = 0; i2 < 3; i2++) {
+ gps->vert_color_fill[i2] = 1.0f - gps->vert_color_fill[i2];
+ }
+ }
+ }
+ }
+
+ /* Stroke points. */
+ if (mode != GP_PAINT_VERTEX_FILL) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
+ for (int i2 = 0; i2 < 3; i2++) {
+ pt->vert_color[i2] = 1.0f - pt->vert_color[i2];
+ }
+ }
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_vertex_color_invert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Invert";
+ ot->idname = "GPENCIL_OT_vertex_color_invert";
+ ot->description = "Invert RGB values";
+
+ /* api callbacks */
+ ot->exec = gp_vertexpaint_invert_exec;
+ ot->poll = gp_vertexpaint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
+}
+
+static int gp_vertexpaint_levels_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ bool changed = false;
+ int i;
+ bGPDspoint *pt;
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ float gain = RNA_float_get(op->ptr, "gain");
+ float offset = RNA_float_get(op->ptr, "offset");
+
+ /* Loop all selected strokes. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+
+ /* Fill color. */
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed = true;
+ if (mode != GP_PAINT_VERTEX_STROKE) {
+ if (gps->vert_color_fill[3] > 0.0f) {
+ for (int i2 = 0; i2 < 3; i2++) {
+ gps->vert_color_fill[i2] = gain * (gps->vert_color_fill[i2] + offset);
+ }
+ }
+ }
+ }
+
+ /* Stroke points. */
+ if (mode != GP_PAINT_VERTEX_FILL) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
+ for (int i2 = 0; i < 3; i2++) {
+ pt->vert_color[i2] = gain * (pt->vert_color[i2] + offset);
+ }
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_vertex_color_levels(wmOperatorType *ot)
+{
+
+ /* identifiers */
+ ot->name = "Vertex Paint Levels";
+ ot->idname = "GPENCIL_OT_vertex_color_levels";
+ ot->description = "Adjust levels of vertex colors";
+
+ /* api callbacks */
+ ot->exec = gp_vertexpaint_levels_exec;
+ ot->poll = gp_vertexpaint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
+
+ RNA_def_float(
+ ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
+ RNA_def_float(
+ ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
+}
+
+static int gp_vertexpaint_set_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ Paint *paint = &ts->gp_vertexpaint->paint;
+ Brush *brush = brush = paint->brush;
+
+ bool changed = false;
+ int i;
+ bGPDspoint *pt;
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ float factor = RNA_float_get(op->ptr, "factor");
+
+ /* Loop all selected strokes. */
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+
+ /* Fill color. */
+ if (gps->flag & GP_STROKE_SELECT) {
+ changed = true;
+ if (mode != GP_PAINT_VERTEX_STROKE) {
+ copy_v3_v3(gps->vert_color_fill, brush->rgb);
+ gps->vert_color_fill[3] = factor;
+ }
+ }
+
+ /* Stroke points. */
+ if (mode != GP_PAINT_VERTEX_FILL) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ copy_v3_v3(pt->vert_color, brush->rgb);
+ pt->vert_color[3] = factor;
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_vertex_color_set(wmOperatorType *ot)
+{
+
+ /* identifiers */
+ ot->name = "Vertex Paint Set Color";
+ ot->idname = "GPENCIL_OT_vertex_color_set";
+ ot->description = "Set active color to all selected vertex";
+
+ /* api callbacks */
+ ot->exec = gp_vertexpaint_set_exec;
+ ot->poll = gp_vertexpaint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
+ RNA_def_float(ot->srna, "factor", 1.0f, 0.001f, 1.0f, "Factor", "Mix Factor", 0.001f, 1.0f);
+}
+
+/* Helper to extract color from vertex color to create a palette. */
+static bool gp_extract_palette_from_vertex(bContext *C, const bool selected, const int threshold)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ bool done = false;
+ const float range = pow(10.0f, threshold);
+ float col[3];
+
+ GHash *color_table = BLI_ghash_int_new(__func__);
+
+ /* Extract all colors. */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ if (gp_style == NULL) {
+ continue;
+ }
+
+ if ((selected) && ((gps->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+
+ bool use_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW);
+ bool use_fill = (gp_style->flag & GP_MATERIAL_FILL_SHOW);
+
+ /* Material is disabled. */
+ if ((!use_fill) && (!use_stroke)) {
+ continue;
+ }
+
+ /* Only solid strokes or stencil. */
+ if ((use_stroke) && ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) &&
+ ((gp_style->flag & GP_MATERIAL_STROKE_PATTERN) == 0))) {
+ continue;
+ }
+
+ /* Only solid fill. */
+ if ((use_fill) && (gp_style->fill_style != GP_MATERIAL_FILL_STYLE_SOLID)) {
+ continue;
+ }
+
+ /* Fill color. */
+ if (gps->vert_color_fill[3] > 0.0f) {
+ col[0] = truncf(gps->vert_color_fill[0] * range) / range;
+ col[1] = truncf(gps->vert_color_fill[1] * range) / range;
+ col[2] = truncf(gps->vert_color_fill[2] * range) / range;
+
+ uint key = rgb_to_cpack(col[0], col[1], col[2]);
+
+ if (!BLI_ghash_haskey(color_table, POINTER_FROM_INT(key))) {
+ BLI_ghash_insert(color_table, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
+ }
+ }
+
+ /* Read all points to get all colors. */
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ col[0] = truncf(pt->vert_color[0] * range) / range;
+ col[1] = truncf(pt->vert_color[1] * range) / range;
+ col[2] = truncf(pt->vert_color[2] * range) / range;
+
+ uint key = rgb_to_cpack(col[0], col[1], col[2]);
+ if (!BLI_ghash_haskey(color_table, POINTER_FROM_INT(key))) {
+ BLI_ghash_insert(color_table, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* Create the Palette. */
+ done = BKE_palette_from_hash(bmain, color_table, ob->id.name + 2, true);
+
+ /* Free memory. */
+ BLI_ghash_free(color_table, NULL, NULL);
+
+ return done;
+}
+
+/* Convert Materials to Vertex Color. */
+typedef struct GPMatArray {
+ uint key;
+ Material *ma;
+ int index;
+} GPMatArray;
+
+static uint get_material_type(MaterialGPencilStyle *gp_style,
+ bool use_stroke,
+ bool use_fill,
+ char *name)
+{
+ uint r_i = 0;
+ if ((use_stroke) && (use_fill)) {
+ switch (gp_style->mode) {
+ case GP_MATERIAL_MODE_LINE: {
+ r_i = 1;
+ strcpy(name, "Line Stroke-Fill");
+ break;
+ }
+ case GP_MATERIAL_MODE_DOT: {
+ r_i = 2;
+ strcpy(name, "Dots Stroke-Fill");
+ break;
+ }
+ case GP_MATERIAL_MODE_SQUARE: {
+ r_i = 3;
+ strcpy(name, "Squares Stroke-Fill");
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else if (use_stroke) {
+ switch (gp_style->mode) {
+ case GP_MATERIAL_MODE_LINE: {
+ r_i = 4;
+ strcpy(name, "Line Stroke");
+ break;
+ }
+ case GP_MATERIAL_MODE_DOT: {
+ r_i = 5;
+ strcpy(name, "Dots Stroke");
+ break;
+ }
+ case GP_MATERIAL_MODE_SQUARE: {
+ r_i = 6;
+ strcpy(name, "Squares Stroke");
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else {
+ r_i = 7;
+ strcpy(name, "Solid Fill");
+ }
+
+ /* Create key TSSSSFFFF (T: Type S: Stroke Alpha F: Fill Alpha) */
+ r_i *= 1e8;
+ if (use_stroke) {
+ r_i += gp_style->stroke_rgba[3] * 1e7;
+ }
+ if (use_fill) {
+ r_i += gp_style->fill_rgba[3] * 1e3;
+ }
+
+ return r_i;
+}
+
+static bool gp_material_to_vertex_poll(bContext *C)
+{
+ /* only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int gp_material_to_vertex_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const bool remove = RNA_boolean_get(op->ptr, "remove");
+ const bool palette = RNA_boolean_get(op->ptr, "palette");
+ const bool selected = RNA_boolean_get(op->ptr, "selected");
+
+ char name[32] = "";
+ Material *ma = NULL;
+ GPMatArray *mat_elm = NULL;
+ int i;
+
+ bool changed = false;
+
+ short *totcol = BKE_object_material_len_p(ob);
+ if (totcol == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* These arrays hold all materials and index in the material slots for all combinations. */
+ int totmat = *totcol;
+ GPMatArray *mat_table = MEM_calloc_arrayN(totmat, sizeof(GPMatArray), __func__);
+
+ /* Update stroke material index. */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ if ((selected) && ((gps->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ if (gp_style == NULL) {
+ continue;
+ }
+
+ bool use_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) &&
+ (gp_style->stroke_rgba[3] > 0.0f));
+ bool use_fill = ((gp_style->flag & GP_MATERIAL_FILL_SHOW) &&
+ (gp_style->fill_rgba[3] > 0.0f));
+ bool is_stencil = ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) &&
+ (gp_style->flag & GP_MATERIAL_STROKE_PATTERN));
+ /* Material is disabled. */
+ if ((!use_fill) && (!use_stroke)) {
+ continue;
+ }
+
+ /* Only solid strokes or stencil. */
+ if ((use_stroke) && ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) &&
+ ((gp_style->flag & GP_MATERIAL_STROKE_PATTERN) == 0))) {
+ continue;
+ }
+
+ /* Only solid fill. */
+ if ((use_fill) && (gp_style->fill_style != GP_MATERIAL_FILL_STYLE_SOLID)) {
+ continue;
+ }
+
+ /* Only for no Stencil materials. */
+ if (!is_stencil) {
+ /* Create material type unique key by type and alpha. */
+ uint key = get_material_type(gp_style, use_stroke, use_fill, name);
+
+ /* Check if material exist. */
+ bool found = false;
+ for (i = 0; i < totmat; i++) {
+ mat_elm = &mat_table[i];
+ if (mat_elm->ma == NULL) {
+ break;
+ }
+ if (key == mat_elm->key) {
+ found = true;
+ break;
+ }
+ }
+
+ /* If not found create a new material. */
+ if (!found) {
+ ma = BKE_gpencil_material_add(bmain, name);
+ if (use_stroke) {
+ ma->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ }
+ else {
+ ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ }
+
+ if (use_fill) {
+ ma->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ }
+ else {
+ ma->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
+ }
+
+ ma->gp_style->stroke_rgba[3] = gp_style->stroke_rgba[3];
+ ma->gp_style->fill_rgba[3] = gp_style->fill_rgba[3];
+
+ BKE_object_material_slot_add(bmain, ob);
+ BKE_object_material_assign(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+
+ mat_elm->key = key;
+ mat_elm->ma = ma;
+ mat_elm->index = ob->totcol - 1;
+ }
+ else {
+ mat_elm = &mat_table[i];
+ }
+
+ /* Update stroke */
+ gps->mat_nr = mat_elm->index;
+ }
+
+ changed = true;
+ copy_v3_v3(gps->vert_color_fill, gp_style->fill_rgba);
+ gps->vert_color_fill[3] = 1.0f;
+
+ /* Update all points. */
+ bGPDspoint *pt;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ copy_v3_v3(pt->vert_color, gp_style->stroke_rgba);
+ pt->vert_color[3] = 1.0f;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ /* Free memory. */
+ MEM_SAFE_FREE(mat_table);
+
+ /* Generate a Palette. */
+ if (palette) {
+ gp_extract_palette_from_vertex(C, selected, 1);
+ }
+
+ /* Clean unused materials. */
+ if (remove) {
+ WM_operator_name_call(
+ C, "OBJECT_OT_material_slot_remove_unused", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_material_to_vertex_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Convert Stroke Materials to Vertex Color";
+ ot->idname = "GPENCIL_OT_material_to_vertex_color";
+ ot->description = "Replace materials in strokes with Vertex Color";
+
+ /* api callbacks */
+ ot->exec = gp_material_to_vertex_exec;
+ ot->poll = gp_material_to_vertex_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna,
+ "remove",
+ true,
+ "Remove Unused Materiales",
+ "Remove any unused material after the conversion");
+ RNA_def_boolean(ot->srna, "palette", true, "Create Palette", "Create a new palette with colors");
+ RNA_def_boolean(ot->srna, "selected", false, "Only Selected", "Convert only selected strokes");
+ RNA_def_int(ot->srna, "threshold", 3, 1, 4, "Threshold", "", 1, 4);
+}
+
+/* Extract Palette from Vertex Color. */
+static bool gp_extract_palette_vertex_poll(bContext *C)
+{
+ /* only supported with grease pencil objects */
+ Object *ob = CTX_data_active_object(C);
+ if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ return true;
+}
+
+static int gp_extract_palette_vertex_exec(bContext *C, wmOperator *op)
+{
+ const bool selected = RNA_boolean_get(op->ptr, "selected");
+ const int threshold = RNA_int_get(op->ptr, "threshold");
+
+ if (gp_extract_palette_from_vertex(C, selected, threshold)) {
+ BKE_reportf(op->reports, RPT_INFO, "Palette created");
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Unable to find Vertex Information to create palette");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_extract_palette_vertex(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Extract Palette from Vertex Color";
+ ot->idname = "GPENCIL_OT_extract_palette_vertex";
+ ot->description = "Extract all colors used in Grease Pencil Vertex and create a Palette";
+
+ /* api callbacks */
+ ot->exec = gp_extract_palette_vertex_exec;
+ ot->poll = gp_extract_palette_vertex_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(
+ ot->srna, "selected", false, "Only Selected", "Convert only selected strokes");
+ RNA_def_int(ot->srna, "threshold", 1, 1, 4, "Threshold", "", 1, 4);
+}
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
new file mode 100644
index 00000000000..5b5a306aa25
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -0,0 +1,1414 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * This is a new part of Blender
+ * Brush based operators for editing Grease Pencil strokes
+ */
+
+/** \file
+ * \ingroup edgpencil
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* General Brush Editing Context */
+#define GP_SELECT_BUFFER_CHUNK 256
+#define GP_GRID_PIXEL_SIZE 10.0f
+
+/* Temp Flags while Painting. */
+typedef enum eGPDvertex_brush_Flag {
+ /* invert the effect of the brush */
+ GP_VERTEX_FLAG_INVERT = (1 << 0),
+ /* temporary invert action */
+ GP_VERTEX_FLAG_TMP_INVERT = (1 << 1),
+} eGPDvertex_brush_Flag;
+
+/* Grid of Colors for Smear. */
+typedef struct tGP_Grid {
+ /** Lower right corner of rectangle of grid cell. */
+ float bottom[2];
+ /** Upper left corner of rectangle of grid cell. */
+ float top[2];
+ /** Average Color */
+ float color[4];
+ /** Total points included. */
+ int totcol;
+
+} tGP_Grid;
+
+/* List of points affected by brush. */
+typedef struct tGP_Selected {
+ /** Referenced stroke. */
+ bGPDstroke *gps;
+ /** Point index in points array. */
+ int pt_index;
+ /** Position */
+ int pc[2];
+ /** Color */
+ float color[4];
+} tGP_Selected;
+
+/* Context for brush operators */
+typedef struct tGP_BrushVertexpaintData {
+ Scene *scene;
+ Object *object;
+
+ ARegion *region;
+
+ /* Current GPencil datablock */
+ bGPdata *gpd;
+
+ Brush *brush;
+ eGPDvertex_brush_Flag flag;
+ eGP_Vertex_SelectMaskFlag mask;
+
+ /* Space Conversion Data */
+ GP_SpaceConversion gsc;
+
+ /* Is the brush currently painting? */
+ bool is_painting;
+
+ /* Start of new paint */
+ bool first;
+
+ /* Is multiframe editing enabled, and are we using falloff for that? */
+ bool is_multiframe;
+ bool use_multiframe_falloff;
+
+ /* Brush Runtime Data: */
+ /* - position and pressure
+ * - the *_prev variants are the previous values
+ */
+ float mval[2], mval_prev[2];
+ float pressure, pressure_prev;
+
+ /* - Effect 2D vector */
+ float dvec[2];
+
+ /* - multiframe falloff factor */
+ float mf_falloff;
+
+ /* brush geometry (bounding box) */
+ rcti brush_rect;
+
+ /* Temp data to save selected points */
+ /** Stroke buffer. */
+ tGP_Selected *pbuffer;
+ /** Number of elements currently used in cache. */
+ int pbuffer_used;
+ /** Number of total elements available in cache. */
+ int pbuffer_size;
+
+ /** Grid of average colors */
+ tGP_Grid *grid;
+ /** Total number of rows/cols. */
+ int grid_size;
+ /** Total number of cells elments in the grid array. */
+ int grid_len;
+ /** Grid sample position (used to determine distance of falloff) */
+ int grid_sample[2];
+ /** Grid is ready to use */
+ bool grid_ready;
+
+} tGP_BrushVertexpaintData;
+
+/* Ensure the buffer to hold temp selected point size is enough to save all points selected. */
+static tGP_Selected *gpencil_select_buffer_ensure(tGP_Selected *buffer_array,
+ int *buffer_size,
+ int *buffer_used,
+ const bool clear)
+{
+ tGP_Selected *p = NULL;
+
+ /* By default a buffer is created with one block with a predefined number of free slots,
+ * if the size is not enough, the cache is reallocated adding a new block of free slots.
+ * This is done in order to keep cache small and improve speed. */
+ if (*buffer_used + 1 > *buffer_size) {
+ if ((*buffer_size == 0) || (buffer_array == NULL)) {
+ p = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__);
+ *buffer_size = GP_SELECT_BUFFER_CHUNK;
+ }
+ else {
+ *buffer_size += GP_SELECT_BUFFER_CHUNK;
+ p = MEM_recallocN(buffer_array, sizeof(struct tGP_Selected) * *buffer_size);
+ }
+
+ if (p == NULL) {
+ *buffer_size = *buffer_used = 0;
+ }
+
+ buffer_array = p;
+ }
+
+ /* clear old data */
+ if (clear) {
+ *buffer_used = 0;
+ if (buffer_array != NULL) {
+ memset(buffer_array, 0, sizeof(tGP_Selected) * *buffer_size);
+ }
+ }
+
+ return buffer_array;
+}
+
+/* Brush Operations ------------------------------- */
+
+/* Invert behavior of brush? */
+static bool brush_invert_check(tGP_BrushVertexpaintData *gso)
+{
+ /* The basic setting is no inverted */
+ bool invert = false;
+
+ /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
+ if (gso->flag & GP_VERTEX_FLAG_INVERT) {
+ invert ^= true;
+ }
+
+ return invert;
+}
+
+/* Compute strength of effect. */
+static float brush_influence_calc(tGP_BrushVertexpaintData *gso, const int radius, const int co[2])
+{
+ Brush *brush = gso->brush;
+ float influence = brush->size;
+
+ /* use pressure? */
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ influence *= gso->pressure;
+ }
+
+ /* distance fading */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ float distance = (float)len_v2v2_int(mval_i, co);
+
+ /* Apply Brush curve. */
+ float brush_fallof = BKE_brush_curve_strength(brush, distance, (float)radius);
+ influence *= brush_fallof;
+
+ /* apply multiframe falloff */
+ influence *= gso->mf_falloff;
+
+ /* return influence */
+ return influence;
+}
+
+/* Compute effect vector for directional brushes. */
+static void brush_calc_dvec_2d(tGP_BrushVertexpaintData *gso)
+{
+ gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ normalize_v2(gso->dvec);
+}
+
+/* Init a grid of cells around mouse position.
+ *
+ * For each Cell.
+ *
+ * *--------* Top
+ * | |
+ * | |
+ * Bottom *--------*
+ *
+ * The number of cells is calculated using the brush size and a predefined
+ * number of pixels (see: GP_GRID_PIXEL_SIZE)
+ */
+
+static void gp_grid_cells_init(tGP_BrushVertexpaintData *gso)
+{
+ tGP_Grid *grid;
+ float bottom[2];
+ float top[2];
+ int grid_index = 0;
+
+ /* The grid center is (0,0). */
+ bottom[0] = gso->brush_rect.xmin - gso->mval[0];
+ bottom[1] = gso->brush_rect.ymax - GP_GRID_PIXEL_SIZE - gso->mval[1];
+
+ /* Calc all cell of the grid from top/left. */
+ for (int y = gso->grid_size - 1; y >= 0; y--) {
+ top[1] = bottom[1] + GP_GRID_PIXEL_SIZE;
+
+ for (int x = 0; x < gso->grid_size; x++) {
+ top[0] = bottom[0] + GP_GRID_PIXEL_SIZE;
+
+ grid = &gso->grid[grid_index];
+
+ copy_v2_v2(grid->bottom, bottom);
+ copy_v2_v2(grid->top, top);
+
+ bottom[0] += GP_GRID_PIXEL_SIZE;
+
+ grid_index++;
+ }
+
+ /* Reset for new row. */
+ bottom[0] = gso->brush_rect.xmin - gso->mval[0];
+ bottom[1] -= GP_GRID_PIXEL_SIZE;
+ }
+}
+
+/* Get the index used in the grid base on dvec. */
+static void gp_grid_cell_average_color_idx_get(tGP_BrushVertexpaintData *gso, int r_idx[2])
+{
+ /* Lower direction. */
+ if (gso->dvec[1] < 0.0f) {
+ if ((gso->dvec[0] >= -1.0f) && (gso->dvec[0] < -0.8f)) {
+ r_idx[0] = 0;
+ r_idx[1] = -1;
+ }
+ else if ((gso->dvec[0] >= -0.8f) && (gso->dvec[0] < -0.6f)) {
+ r_idx[0] = -1;
+ r_idx[1] = -1;
+ }
+ else if ((gso->dvec[0] >= -0.6f) && (gso->dvec[0] < 0.6f)) {
+ r_idx[0] = -1;
+ r_idx[1] = 0;
+ }
+ else if ((gso->dvec[0] >= 0.6f) && (gso->dvec[0] < 0.8f)) {
+ r_idx[0] = -1;
+ r_idx[1] = 1;
+ }
+ else if (gso->dvec[0] >= 0.8f) {
+ r_idx[0] = 0;
+ r_idx[1] = 1;
+ }
+ }
+ /* Upper direction. */
+ else {
+ if ((gso->dvec[0] >= -1.0f) && (gso->dvec[0] < -0.8f)) {
+ r_idx[0] = 0;
+ r_idx[1] = -1;
+ }
+ else if ((gso->dvec[0] >= -0.8f) && (gso->dvec[0] < -0.6f)) {
+ r_idx[0] = 1;
+ r_idx[1] = -1;
+ }
+ else if ((gso->dvec[0] >= -0.6f) && (gso->dvec[0] < 0.6f)) {
+ r_idx[0] = 1;
+ r_idx[1] = 0;
+ }
+ else if ((gso->dvec[0] >= 0.6f) && (gso->dvec[0] < 0.8f)) {
+ r_idx[0] = 1;
+ r_idx[1] = 1;
+ }
+ else if (gso->dvec[0] >= 0.8f) {
+ r_idx[0] = 0;
+ r_idx[1] = 1;
+ }
+ }
+}
+
+static int gp_grid_cell_index_get(tGP_BrushVertexpaintData *gso, int pc[2])
+{
+ float bottom[2], top[2];
+
+ for (int i = 0; i < gso->grid_len; i++) {
+ tGP_Grid *grid = &gso->grid[i];
+ add_v2_v2v2(bottom, grid->bottom, gso->mval);
+ add_v2_v2v2(top, grid->top, gso->mval);
+
+ if (pc[0] >= bottom[0] && pc[0] <= top[0] && pc[1] >= bottom[1] && pc[1] <= top[1]) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/* Fill the grid with the color in each cell and assign point cell index. */
+static void gp_grid_colors_calc(tGP_BrushVertexpaintData *gso)
+{
+ tGP_Selected *selected = NULL;
+ bGPDstroke *gps_selected = NULL;
+ bGPDspoint *pt = NULL;
+ tGP_Grid *grid = NULL;
+
+ /* Don't calculate again. */
+ if (gso->grid_ready) {
+ return;
+ }
+
+ /* Extract colors by cell. */
+ for (int i = 0; i < gso->pbuffer_used; i++) {
+ selected = &gso->pbuffer[i];
+ gps_selected = selected->gps;
+ pt = &gps_selected->points[selected->pt_index];
+ int grid_index = gp_grid_cell_index_get(gso, selected->pc);
+
+ if (grid_index > -1) {
+ grid = &gso->grid[grid_index];
+ /* Add stroke mix color (only if used). */
+ if (pt->vert_color[3] > 0.0f) {
+ add_v3_v3(grid->color, selected->color);
+ grid->color[3] = 1.0f;
+ grid->totcol++;
+ }
+ }
+ }
+
+ /* Average colors. */
+ for (int i = 0; i < gso->grid_len; i++) {
+ grid = &gso->grid[i];
+ if (grid->totcol > 0) {
+ mul_v3_fl(grid->color, (1.0f / (float)grid->totcol));
+ }
+ }
+
+ /* Save sample position. */
+ round_v2i_v2fl(gso->grid_sample, gso->mval);
+
+ gso->grid_ready = true;
+
+ return;
+}
+
+/* ************************************************ */
+/* Brush Callbacks
+ * This section defines the callbacks used by each brush to perform their magic.
+ * These are called on each point within the brush's radius. */
+
+/* Tint Brush */
+static bool brush_tint_apply(tGP_BrushVertexpaintData *gso,
+ bGPDstroke *gps,
+ int pt_index,
+ const int radius,
+ const int co[2])
+{
+ Brush *brush = gso->brush;
+
+ /* Attenuate factor to get a smoother tinting. */
+ float inf = (brush_influence_calc(gso, radius, co) * brush->gpencil_settings->draw_strength) /
+ 100.0f;
+ float inf_fill = (gso->pressure * brush->gpencil_settings->draw_strength) / 1000.0f;
+
+ CLAMP(inf, 0.0f, 1.0f);
+ CLAMP(inf_fill, 0.0f, 1.0f);
+
+ bGPDspoint *pt = &gps->points[pt_index];
+
+ /* Apply color to Stroke point. */
+ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) {
+ if (brush_invert_check(gso)) {
+ pt->vert_color[3] -= inf;
+ CLAMP_MIN(pt->vert_color[3], 0.0f);
+ }
+ else {
+ /* Premult. */
+ mul_v3_fl(pt->vert_color, pt->vert_color[3]);
+ /* "Alpha over" blending. */
+ interp_v3_v3v3(pt->vert_color, pt->vert_color, brush->rgb, inf);
+ pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf;
+ /* Un-premult. */
+ if (pt->vert_color[3] > 0.0f) {
+ mul_v3_fl(pt->vert_color, 1.0f / pt->vert_color[3]);
+ }
+ }
+ }
+
+ /* Apply color to Fill area (all with same color and factor). */
+ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
+ if (brush_invert_check(gso)) {
+ gps->vert_color_fill[3] -= inf_fill;
+ CLAMP_MIN(gps->vert_color_fill[3], 0.0f);
+ }
+ else {
+ /* Premult. */
+ mul_v3_fl(gps->vert_color_fill, gps->vert_color_fill[3]);
+ /* "Alpha over" blending. */
+ interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, brush->rgb, inf_fill);
+ gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill;
+ /* Un-premult. */
+ if (gps->vert_color_fill[3] > 0.0f) {
+ mul_v3_fl(gps->vert_color_fill, 1.0f / gps->vert_color_fill[3]);
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Replace Brush (Don't use pressure or invert). */
+static bool brush_replace_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index)
+{
+ Brush *brush = gso->brush;
+ bGPDspoint *pt = &gps->points[pt_index];
+
+ /* Apply color to Stroke point. */
+ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) {
+ copy_v3_v3(pt->vert_color, brush->rgb);
+ /* If not mix color, full replace. */
+ if (pt->vert_color[3] == 0.0f) {
+ pt->vert_color[3] = 1.0f;
+ }
+ }
+
+ /* Apply color to Fill area (all with same color and factor). */
+ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
+ copy_v3_v3(gps->vert_color_fill, brush->rgb);
+ /* If not mix color, full replace. */
+ if (gps->vert_color_fill[3] == 0.0f) {
+ gps->vert_color_fill[3] = 1.0f;
+ }
+ }
+
+ return true;
+}
+
+/* Get surrounding color. */
+static bool get_surrounding_color(tGP_BrushVertexpaintData *gso,
+ bGPDstroke *gps,
+ int pt_index,
+ float r_color[3])
+{
+ tGP_Selected *selected = NULL;
+ bGPDstroke *gps_selected = NULL;
+ bGPDspoint *pt = NULL;
+
+ int totcol = 0;
+ zero_v3(r_color);
+
+ /* Average the surrounding points except current one. */
+ for (int i = 0; i < gso->pbuffer_used; i++) {
+ selected = &gso->pbuffer[i];
+ gps_selected = selected->gps;
+ /* current point is not evaluated. */
+ if ((gps_selected == gps) && (selected->pt_index == pt_index)) {
+ continue;
+ }
+
+ pt = &gps_selected->points[selected->pt_index];
+
+ /* Add stroke mix color (only if used). */
+ if (pt->vert_color[3] > 0.0f) {
+ add_v3_v3(r_color, selected->color);
+ totcol++;
+ }
+ }
+ if (totcol > 0) {
+ mul_v3_fl(r_color, (1.0f / (float)totcol));
+ return true;
+ }
+
+ return false;
+}
+
+/* Blur Brush */
+static bool brush_blur_apply(tGP_BrushVertexpaintData *gso,
+ bGPDstroke *gps,
+ int pt_index,
+ const int radius,
+ const int co[2])
+{
+ Brush *brush = gso->brush;
+
+ /* Attenuate factor to get a smoother tinting. */
+ float inf = (brush_influence_calc(gso, radius, co) * brush->gpencil_settings->draw_strength) /
+ 100.0f;
+ float inf_fill = (gso->pressure * brush->gpencil_settings->draw_strength) / 1000.0f;
+
+ bGPDspoint *pt = &gps->points[pt_index];
+
+ /* Get surrounding color. */
+ float blur_color[3];
+ if (get_surrounding_color(gso, gps, pt_index, blur_color)) {
+ /* Apply color to Stroke point. */
+ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) {
+ interp_v3_v3v3(pt->vert_color, pt->vert_color, blur_color, inf);
+ }
+
+ /* Apply color to Fill area (all with same color and factor). */
+ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
+ interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, blur_color, inf_fill);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/* Average Brush */
+static bool brush_average_apply(tGP_BrushVertexpaintData *gso,
+ bGPDstroke *gps,
+ int pt_index,
+ const int radius,
+ const int co[2],
+ float average_color[3])
+{
+ Brush *brush = gso->brush;
+
+ /* Attenuate factor to get a smoother tinting. */
+ float inf = (brush_influence_calc(gso, radius, co) * brush->gpencil_settings->draw_strength) /
+ 100.0f;
+ float inf_fill = (gso->pressure * brush->gpencil_settings->draw_strength) / 1000.0f;
+
+ bGPDspoint *pt = &gps->points[pt_index];
+
+ float alpha = pt->vert_color[3];
+ float alpha_fill = gps->vert_color_fill[3];
+
+ if (brush_invert_check(gso)) {
+ alpha -= inf;
+ alpha_fill -= inf_fill;
+ }
+ else {
+ alpha += inf;
+ alpha_fill += inf_fill;
+ }
+
+ /* Apply color to Stroke point. */
+ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) {
+ CLAMP(alpha, 0.0f, 1.0f);
+ interp_v3_v3v3(pt->vert_color, pt->vert_color, average_color, inf);
+ pt->vert_color[3] = alpha;
+ }
+
+ /* Apply color to Fill area (all with same color and factor). */
+ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
+ CLAMP(alpha_fill, 0.0f, 1.0f);
+ copy_v3_v3(gps->vert_color_fill, average_color);
+ gps->vert_color_fill[3] = alpha_fill;
+ }
+
+ return true;
+}
+
+/* Smear Brush */
+static bool brush_smear_apply(tGP_BrushVertexpaintData *gso,
+ bGPDstroke *gps,
+ int pt_index,
+ tGP_Selected *selected)
+{
+ Brush *brush = gso->brush;
+ tGP_Grid *grid = NULL;
+ int average_idx[2];
+ ARRAY_SET_ITEMS(average_idx, 0, 0);
+
+ bool changed = false;
+
+ /* Need some movement, so first input is not done. */
+ if (gso->first) {
+ return false;
+ }
+
+ bGPDspoint *pt = &gps->points[pt_index];
+
+ /* Need get average colors in the grid. */
+ if ((!gso->grid_ready) && (gso->pbuffer_used > 0)) {
+ gp_grid_colors_calc(gso);
+ }
+
+ /* The influence is equal to strength and no decay around brush radius. */
+ float inf = brush->gpencil_settings->draw_strength;
+ if (brush->flag & GP_BRUSH_USE_PRESSURE) {
+ inf *= gso->pressure;
+ }
+
+ /* Calc distance from initial sample location and add a fallof effect. */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ float distance = (float)len_v2v2_int(mval_i, gso->grid_sample);
+ float fac = 1.0f - (distance / (float)(brush->size * 2));
+ CLAMP(fac, 0.0f, 1.0f);
+ inf *= fac;
+
+ /* Retry row and col for average color. */
+ gp_grid_cell_average_color_idx_get(gso, average_idx);
+
+ /* Retry average color cell. */
+ int grid_index = gp_grid_cell_index_get(gso, selected->pc);
+ if (grid_index > -1) {
+ int row = grid_index / gso->grid_size;
+ int col = grid_index - (gso->grid_size * row);
+ row += average_idx[0];
+ col += average_idx[1];
+ CLAMP(row, 0, gso->grid_size);
+ CLAMP(col, 0, gso->grid_size);
+
+ int new_index = (row * gso->grid_size) + col;
+ CLAMP(new_index, 0, gso->grid_len - 1);
+ grid = &gso->grid[new_index];
+ }
+
+ /* Apply color to Stroke point. */
+ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) {
+ if (grid_index > -1) {
+ if (grid->color[3] > 0.0f) {
+ // copy_v3_v3(pt->vert_color, grid->color);
+ interp_v3_v3v3(pt->vert_color, pt->vert_color, grid->color, inf);
+ changed = true;
+ }
+ }
+ }
+
+ /* Apply color to Fill area (all with same color and factor). */
+ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
+ if (grid_index > -1) {
+ if (grid->color[3] > 0.0f) {
+ interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, grid->color, inf);
+ changed = true;
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* ************************************************ */
+/* Header Info */
+static void gp_vertexpaint_brush_header_set(bContext *C)
+{
+ ED_workspace_status_text(C,
+ TIP_("GPencil Vertex Paint: LMB to paint | RMB/Escape to Exit"
+ " | Ctrl to Invert Action"));
+}
+
+/* ************************************************ */
+/* Grease Pencil Vertex Paint Operator */
+
+/* Init/Exit ----------------------------------------------- */
+
+static bool gp_vertexpaint_brush_init(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ Paint *paint = ob->mode == OB_MODE_VERTEX_GPENCIL ? &ts->gp_vertexpaint->paint :
+ &ts->gp_paint->paint;
+
+ /* set the brush using the tool */
+ tGP_BrushVertexpaintData *gso;
+
+ /* setup operator data */
+ gso = MEM_callocN(sizeof(tGP_BrushVertexpaintData), "tGP_BrushVertexpaintData");
+ op->customdata = gso;
+
+ gso->brush = paint->brush;
+ BKE_curvemapping_initialize(gso->brush->curve);
+
+ gso->is_painting = false;
+ gso->first = true;
+
+ gso->pbuffer = NULL;
+ gso->pbuffer_size = 0;
+ gso->pbuffer_used = 0;
+
+ /* Alloc grid array */
+ gso->grid_size = (int)(((gso->brush->size * 2.0f) / GP_GRID_PIXEL_SIZE) + 1.0);
+ /* Square value. */
+ gso->grid_len = gso->grid_size * gso->grid_size;
+ gso->grid = MEM_callocN(sizeof(tGP_Grid) * gso->grid_len, "tGP_Grid");
+ gso->grid_ready = false;
+
+ gso->gpd = ED_gpencil_data_get_active(C);
+ gso->scene = scene;
+ gso->object = ob;
+
+ gso->region = CTX_wm_region(C);
+
+ /* Save mask. */
+ gso->mask = ts->gpencil_selectmode_vertex;
+
+ /* Multiframe settings. */
+ gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ /* Init multi-edit falloff curve data before doing anything,
+ * so we won't have to do it again later. */
+ if (gso->is_multiframe) {
+ BKE_curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
+ /* Setup space conversions. */
+ gp_point_conversion_init(C, &gso->gsc);
+
+ /* Update header. */
+ gp_vertexpaint_brush_header_set(C);
+
+ return true;
+}
+
+static void gp_vertexpaint_brush_exit(bContext *C, wmOperator *op)
+{
+ tGP_BrushVertexpaintData *gso = op->customdata;
+
+ /* Disable headerprints. */
+ ED_workspace_status_text(C, NULL);
+
+ /* Disable temp invert flag. */
+ gso->brush->flag &= ~GP_VERTEX_FLAG_TMP_INVERT;
+
+ /* Free operator data */
+ MEM_SAFE_FREE(gso->pbuffer);
+ MEM_SAFE_FREE(gso->grid);
+ MEM_SAFE_FREE(gso);
+ op->customdata = NULL;
+}
+
+/* Poll callback for stroke vertex paint operator. */
+static bool gp_vertexpaint_brush_poll(bContext *C)
+{
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+}
+
+/* Helper to save the points selected by the brush. */
+static void gp_save_selected_point(tGP_BrushVertexpaintData *gso,
+ bGPDstroke *gps,
+ int index,
+ int pc[2])
+{
+ tGP_Selected *selected;
+ bGPDspoint *pt = &gps->points[index];
+
+ /* Ensure the array to save the list of selected points is big enough. */
+ gso->pbuffer = gpencil_select_buffer_ensure(
+ gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, false);
+
+ selected = &gso->pbuffer[gso->pbuffer_used];
+ selected->gps = gps;
+ selected->pt_index = index;
+ copy_v2_v2_int(selected->pc, pc);
+ copy_v4_v4(selected->color, pt->vert_color);
+
+ gso->pbuffer_used++;
+}
+
+/* Select points in this stroke and add to an array to be used later. */
+static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
+ bGPDstroke *gps,
+ const float diff_mat[4][4])
+{
+ GP_SpaceConversion *gsc = &gso->gsc;
+ rcti *rect = &gso->brush_rect;
+ Brush *brush = gso->brush;
+ const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
+ gso->brush->size;
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
+
+ bGPDspoint *pt1, *pt2;
+ bGPDspoint *pt = NULL;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+ int index;
+ bool include_last = false;
+
+ /* Check if the stroke collide with brush. */
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) {
+ return;
+ }
+
+ if (gps->totpoints == 1) {
+ bGPDspoint pt_temp;
+ pt = &gps->points[0];
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ /* apply operation to this point */
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, 0, pc1);
+ }
+ }
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* Get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* Skip if neither one is selected
+ * (and we are only allowed to edit/consider selected points) */
+ if ((GPENCIL_ANY_VERTEX_MASK(gso->mask)) && (GPENCIL_VERTEX_MODE(gso->gpd))) {
+ if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
+ include_last = false;
+ continue;
+ }
+ }
+
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the selection stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ /* Check if point segment of stroke had anything to do with
+ * brush region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(
+ gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+
+ /* To each point individually... */
+ pt = &gps->points[i];
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, index, pc1);
+ }
+
+ /* Only do the second point if this is the last segment,
+ * and it is unlikely that the point will get handled
+ * otherwise.
+ *
+ * NOTE: There is a small risk here that the second point wasn't really
+ * actually in-range. In that case, it only got in because
+ * the line linking the points was!
+ */
+ if (i + 1 == gps->totpoints - 1) {
+ pt = &gps->points[i + 1];
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, index, pc2);
+ include_last = false;
+ }
+ }
+ else {
+ include_last = true;
+ }
+ }
+ else if (include_last) {
+ /* This case is for cases where for whatever reason the second vert (1st here)
+ * doesn't get included because the whole edge isn't in bounds,
+ * but it would've qualified since it did with the previous step
+ * (but wasn't added then, to avoid double-ups).
+ */
+ pt = &gps->points[i];
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, index, pc1);
+
+ include_last = false;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Apply vertex paint brushes to strokes in the given frame. */
+static bool gp_vertexpaint_brush_do_frame(bContext *C,
+ tGP_BrushVertexpaintData *gso,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ const float diff_mat[4][4])
+{
+ Object *ob = CTX_data_active_object(C);
+ char tool = ob->mode == OB_MODE_VERTEX_GPENCIL ? gso->brush->gpencil_vertex_tool :
+ gso->brush->gpencil_tool;
+ const int radius = (gso->brush->flag & GP_BRUSH_USE_PRESSURE) ?
+ gso->brush->size * gso->pressure :
+ gso->brush->size;
+ tGP_Selected *selected = NULL;
+ int i;
+
+ /*---------------------------------------------------------------------
+ * First step: select the points affected. This step is required to have
+ * all selected points before apply the effect, because it could be
+ * required to average data.
+ *--------------------------------------------------------------------- */
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ /* Skip strokes that are invalid for current view. */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ /* Check points below the brush. */
+ gp_vertexpaint_select_stroke(gso, gps, diff_mat);
+ }
+
+ /* For Average tool, need calculate the average resulting color from all colors
+ * under the brush. */
+ float average_color[3] = {0};
+ int totcol = 0;
+ if ((tool == GPVERTEX_TOOL_AVERAGE) && (gso->pbuffer_used > 0)) {
+ for (i = 0; i < gso->pbuffer_used; i++) {
+ selected = &gso->pbuffer[i];
+ bGPDstroke *gps = selected->gps;
+ bGPDspoint *pt = &gps->points[selected->pt_index];
+
+ /* Add stroke mix color (only if used). */
+ if (pt->vert_color[3] > 0.0f) {
+ add_v3_v3(average_color, pt->vert_color);
+ totcol++;
+ }
+
+ /* If Fill color mix, add to average. */
+ if (gps->vert_color_fill[3] > 0.0f) {
+ add_v3_v3(average_color, gps->vert_color_fill);
+ totcol++;
+ }
+ }
+
+ /* Get average. */
+ if (totcol > 0) {
+ mul_v3_fl(average_color, (1.0f / (float)totcol));
+ }
+ }
+
+ /*---------------------------------------------------------------------
+ * Second step: Apply effect.
+ *--------------------------------------------------------------------- */
+ bool changed = false;
+ for (i = 0; i < gso->pbuffer_used; i++) {
+ changed = true;
+ selected = &gso->pbuffer[i];
+
+ switch (tool) {
+ case GPAINT_TOOL_TINT:
+ case GPVERTEX_TOOL_DRAW: {
+ brush_tint_apply(gso, selected->gps, selected->pt_index, radius, selected->pc);
+ changed |= true;
+ break;
+ }
+ case GPVERTEX_TOOL_BLUR: {
+ brush_blur_apply(gso, selected->gps, selected->pt_index, radius, selected->pc);
+ changed |= true;
+ break;
+ }
+ case GPVERTEX_TOOL_AVERAGE: {
+ brush_average_apply(
+ gso, selected->gps, selected->pt_index, radius, selected->pc, average_color);
+ changed |= true;
+ break;
+ }
+ case GPVERTEX_TOOL_SMEAR: {
+ brush_smear_apply(gso, selected->gps, selected->pt_index, selected);
+ changed |= true;
+ break;
+ }
+ case GPVERTEX_TOOL_REPLACE: {
+ brush_replace_apply(gso, selected->gps, selected->pt_index);
+ changed |= true;
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown type of GPencil Vertex Paint brush\n");
+ break;
+ }
+ }
+ /* Clear the selected array, but keep the memory allocation.*/
+ gso->pbuffer = gpencil_select_buffer_ensure(
+ gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, true);
+
+ return changed;
+}
+
+/* Apply brush effect to all layers. */
+static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpaintData *gso)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Object *obact = gso->object;
+ bool changed = false;
+
+ Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id);
+ bGPdata *gpd = (bGPdata *)ob_eval->data;
+
+ /* Find visible strokes, and perform operations on those if hit */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* If locked or no active frame, don't do anything. */
+ if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* calculate difference matrix */
+ float diff_mat[4][4];
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+
+ /* Active Frame or MultiFrame? */
+ if (gso->is_multiframe) {
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (gso->use_multiframe_falloff) {
+ BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
+ }
+
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ /* Always do active frame; Otherwise, only include selected frames */
+ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
+ /* compute multiframe falloff factor */
+ if (gso->use_multiframe_falloff) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range)
+ */
+ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
+ }
+ else {
+ /* No falloff */
+ gso->mf_falloff = 1.0f;
+ }
+
+ /* affect strokes in this frame */
+ changed |= gp_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat);
+ }
+ }
+ }
+ else {
+ /* Apply to active frame's strokes */
+ if (gpl->actframe != NULL) {
+ gso->mf_falloff = 1.0f;
+ changed |= gp_vertexpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Calculate settings for applying brush */
+static void gp_vertexpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
+{
+ tGP_BrushVertexpaintData *gso = op->customdata;
+ Brush *brush = gso->brush;
+ const int radius = ((brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
+ gso->brush->size);
+ float mousef[2];
+ int mouse[2];
+ bool changed = false;
+
+ /* Get latest mouse coordinates */
+ RNA_float_get_array(itemptr, "mouse", mousef);
+ gso->mval[0] = mouse[0] = (int)(mousef[0]);
+ gso->mval[1] = mouse[1] = (int)(mousef[1]);
+
+ gso->pressure = RNA_float_get(itemptr, "pressure");
+
+ if (RNA_boolean_get(itemptr, "pen_flip")) {
+ gso->flag |= GP_VERTEX_FLAG_INVERT;
+ }
+ else {
+ gso->flag &= ~GP_VERTEX_FLAG_INVERT;
+ }
+
+ /* Store coordinates as reference, if operator just started running */
+ if (gso->first) {
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ }
+
+ /* Update brush_rect, so that it represents the bounding rectangle of brush. */
+ gso->brush_rect.xmin = mouse[0] - radius;
+ gso->brush_rect.ymin = mouse[1] - radius;
+ gso->brush_rect.xmax = mouse[0] + radius;
+ gso->brush_rect.ymax = mouse[1] + radius;
+
+ /* Calc 2D direction vector and relative angle. */
+ brush_calc_dvec_2d(gso);
+
+ /* Calc grid for smear tool. */
+ gp_grid_cells_init(gso);
+
+ changed = gp_vertexpaint_brush_apply_to_layers(C, gso);
+
+ /* Updates */
+ if (changed) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ /* Store values for next step */
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ gso->first = false;
+}
+
+/* Running --------------------------------------------- */
+
+/* helper - a record stroke, and apply paint event */
+static void gp_vertexpaint_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushVertexpaintData *gso = op->customdata;
+ PointerRNA itemptr;
+ float mouse[2];
+
+ mouse[0] = event->mval[0] + 1;
+ mouse[1] = event->mval[1] + 1;
+
+ /* fill in stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
+ RNA_boolean_set(&itemptr, "is_start", gso->first);
+
+ /* Handle pressure sensitivity (which is supplied by tablets). */
+ float pressure = event->tablet.pressure;
+ CLAMP(pressure, 0.0f, 1.0f);
+ RNA_float_set(&itemptr, "pressure", pressure);
+
+ /* apply */
+ gp_vertexpaint_brush_apply(C, op, &itemptr);
+}
+
+/* reapply */
+static int gp_vertexpaint_brush_exec(bContext *C, wmOperator *op)
+{
+ if (!gp_vertexpaint_brush_init(C, op)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ gp_vertexpaint_brush_apply(C, op, &itemptr);
+ }
+ RNA_END;
+
+ gp_vertexpaint_brush_exit(C, op);
+
+ return OPERATOR_FINISHED;
+}
+
+/* start modal painting */
+static int gp_vertexpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushVertexpaintData *gso = NULL;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
+
+ /* the operator cannot work while play animation */
+ if (is_playing) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot Paint while play animation");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init painting data */
+ if (!gp_vertexpaint_brush_init(C, op)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ gso = op->customdata;
+
+ /* register modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ /* start drawing immediately? */
+ if (is_modal == false) {
+ ARegion *region = CTX_wm_region(C);
+
+ /* apply first dab... */
+ gso->is_painting = true;
+ gp_vertexpaint_brush_apply_event(C, op, event);
+
+ /* redraw view with feedback */
+ ED_region_tag_redraw(region);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* painting - handle events */
+static int gp_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushVertexpaintData *gso = op->customdata;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ bool redraw_region = false;
+ bool redraw_toolsettings = false;
+
+ /* The operator can be in 2 states: Painting and Idling */
+ if (gso->is_painting) {
+ /* Painting */
+ switch (event->type) {
+ /* Mouse Move = Apply somewhere else */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ /* apply brush effect at new position */
+ gp_vertexpaint_brush_apply_event(C, op, event);
+
+ /* force redraw, so that the cursor will at least be valid */
+ redraw_region = true;
+ break;
+
+ /* Painting mbut release = Stop painting (back to idle) */
+ case LEFTMOUSE:
+ if (is_modal) {
+ /* go back to idling... */
+ gso->is_painting = false;
+ }
+ else {
+ /* end painting, since we're not modal */
+ gso->is_painting = false;
+
+ gp_vertexpaint_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ /* Abort painting if any of the usual things are tried */
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gp_vertexpaint_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ /* Idling */
+ BLI_assert(is_modal == true);
+
+ switch (event->type) {
+ /* Painting mbut press = Start painting (switch to painting state) */
+ case LEFTMOUSE:
+ /* do initial "click" apply */
+ gso->is_painting = true;
+ gso->first = true;
+
+ gp_vertexpaint_brush_apply_event(C, op, event);
+ break;
+
+ /* Exit modal operator, based on the "standard" ops */
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gp_vertexpaint_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+
+ /* MMB is often used for view manipulations */
+ case MIDDLEMOUSE:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Mouse movements should update the brush cursor - Just redraw the active region */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ redraw_region = true;
+ break;
+
+ /* Change Frame - Allowed */
+ case LEFTARROWKEY:
+ case RIGHTARROWKEY:
+ case UPARROWKEY:
+ case DOWNARROWKEY:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Camera/View Gizmo's - Allowed */
+ /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
+ case PAD0:
+ case PAD1:
+ case PAD2:
+ case PAD3:
+ case PAD4:
+ case PAD5:
+ case PAD6:
+ case PAD7:
+ case PAD8:
+ case PAD9:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Unhandled event */
+ default:
+ break;
+ }
+ }
+
+ /* Redraw region? */
+ if (redraw_region) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
+
+ /* Redraw toolsettings (brush settings)? */
+ if (redraw_toolsettings) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void GPENCIL_OT_vertex_paint(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stroke Vertex Paint";
+ ot->idname = "GPENCIL_OT_vertex_paint";
+ ot->description = "Paint stroke points with a color";
+
+ /* api callbacks */
+ ot->exec = gp_vertexpaint_brush_exec;
+ ot->invoke = gp_vertexpaint_brush_invoke;
+ ot->modal = gp_vertexpaint_brush_modal;
+ ot->cancel = gp_vertexpaint_brush_exit;
+ ot->poll = gp_vertexpaint_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
new file mode 100644
index 00000000000..6b337afa559
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -0,0 +1,901 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * This is a new part of Blender
+ * Brush based operators for editing Grease Pencil strokes
+ */
+
+/** \file
+ * \ingroup edgpencil
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "DNA_meshdata_types.h"
+#include "BKE_object_deform.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* General Brush Editing Context */
+#define GP_SELECT_BUFFER_CHUNK 256
+
+/* Grid of Colors for Smear. */
+typedef struct tGP_Grid {
+ /** Lower right corner of rectangle of grid cell. */
+ float bottom[2];
+ /** Upper left corner of rectangle of grid cell. */
+ float top[2];
+ /** Average Color */
+ float color[4];
+ /** Total points included. */
+ int totcol;
+
+} tGP_Grid;
+
+/* List of points affected by brush. */
+typedef struct tGP_Selected {
+ /** Referenced stroke. */
+ bGPDstroke *gps;
+ /** Point index in points array. */
+ int pt_index;
+ /** Position */
+ int pc[2];
+ /** Color */
+ float color[4];
+} tGP_Selected;
+
+/* Context for brush operators */
+typedef struct tGP_BrushWeightpaintData {
+ struct Main *bmain;
+ Scene *scene;
+ Object *object;
+
+ ARegion *region;
+
+ /* Current GPencil datablock */
+ bGPdata *gpd;
+
+ Brush *brush;
+
+ /* Space Conversion Data */
+ GP_SpaceConversion gsc;
+
+ /* Is the brush currently painting? */
+ bool is_painting;
+
+ /* Start of new paint */
+ bool first;
+
+ /* Is multiframe editing enabled, and are we using falloff for that? */
+ bool is_multiframe;
+ bool use_multiframe_falloff;
+
+ /* active vertex group */
+ int vrgroup;
+
+ /* Brush Runtime Data: */
+ /* - position and pressure
+ * - the *_prev variants are the previous values
+ */
+ float mval[2], mval_prev[2];
+ float pressure, pressure_prev;
+
+ /* - Effect 2D vector */
+ float dvec[2];
+
+ /* - multiframe falloff factor */
+ float mf_falloff;
+
+ /* brush geometry (bounding box) */
+ rcti brush_rect;
+
+ /* Temp data to save selected points */
+ /** Stroke buffer. */
+ tGP_Selected *pbuffer;
+ /** Number of elements currently used in cache. */
+ int pbuffer_used;
+ /** Number of total elements available in cache. */
+ int pbuffer_size;
+} tGP_BrushWeightpaintData;
+
+/* Ensure the buffer to hold temp selected point size is enough to save all points selected. */
+static tGP_Selected *gpencil_select_buffer_ensure(tGP_Selected *buffer_array,
+ int *buffer_size,
+ int *buffer_used,
+ const bool clear)
+{
+ tGP_Selected *p = NULL;
+
+ /* By default a buffer is created with one block with a predefined number of free slots,
+ * if the size is not enough, the cache is reallocated adding a new block of free slots.
+ * This is done in order to keep cache small and improve speed. */
+ if (*buffer_used + 1 > *buffer_size) {
+ if ((*buffer_size == 0) || (buffer_array == NULL)) {
+ p = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__);
+ *buffer_size = GP_SELECT_BUFFER_CHUNK;
+ }
+ else {
+ *buffer_size += GP_SELECT_BUFFER_CHUNK;
+ p = MEM_recallocN(buffer_array, sizeof(struct tGP_Selected) * *buffer_size);
+ }
+
+ if (p == NULL) {
+ *buffer_size = *buffer_used = 0;
+ }
+
+ buffer_array = p;
+ }
+
+ /* clear old data */
+ if (clear) {
+ *buffer_used = 0;
+ if (buffer_array != NULL) {
+ memset(buffer_array, 0, sizeof(tGP_Selected) * *buffer_size);
+ }
+ }
+
+ return buffer_array;
+}
+
+/* Brush Operations ------------------------------- */
+
+/* Compute strength of effect. */
+static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radius, const int co[2])
+{
+ Brush *brush = gso->brush;
+
+ /* basic strength factor from brush settings */
+ float influence = brush->alpha;
+
+ /* use pressure? */
+ if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
+ influence *= gso->pressure;
+ }
+
+ /* distance fading */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ float distance = (float)len_v2v2_int(mval_i, co);
+ influence *= 1.0f - (distance / max_ff(radius, 1e-8));
+
+ /* Apply Brush curve. */
+ float brush_fallof = BKE_brush_curve_strength(brush, distance, (float)radius);
+ influence *= brush_fallof;
+
+ /* apply multiframe falloff */
+ influence *= gso->mf_falloff;
+
+ /* return influence */
+ return influence;
+}
+
+/* Compute effect vector for directional brushes. */
+static void brush_calc_dvec_2d(tGP_BrushWeightpaintData *gso)
+{
+ gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ normalize_v2(gso->dvec);
+}
+
+/* ************************************************ */
+/* Brush Callbacks
+ * This section defines the callbacks used by each brush to perform their magic.
+ * These are called on each point within the brush's radius. */
+
+/* Draw Brush */
+static bool brush_draw_apply(tGP_BrushWeightpaintData *gso,
+ bGPDstroke *gps,
+ int pt_index,
+ const int radius,
+ const int co[2])
+{
+ /* create dvert */
+ BKE_gpencil_dvert_ensure(gps);
+
+ MDeformVert *dvert = gps->dvert + pt_index;
+ float inf;
+
+ /* Compute strength of effect */
+ inf = brush_influence_calc(gso, radius, co);
+
+ /* need a vertex group */
+ if (gso->vrgroup == -1) {
+ if (gso->object) {
+ BKE_object_defgroup_add(gso->object);
+ DEG_relations_tag_update(gso->bmain);
+ gso->vrgroup = 0;
+ }
+ }
+ else {
+ bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
+ if (defgroup->flag & DG_LOCK_WEIGHT) {
+ return false;
+ }
+ }
+ /* Get current weight and blend. */
+ MDeformWeight *dw = BKE_defvert_ensure_index(dvert, gso->vrgroup);
+ if (dw) {
+ dw->weight = interpf(gso->brush->weight, dw->weight, inf);
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ return true;
+}
+
+/* ************************************************ */
+/* Header Info */
+static void gp_weightpaint_brush_header_set(bContext *C)
+{
+ ED_workspace_status_text(C, TIP_("GPencil Weight Paint: LMB to paint | RMB/Escape to Exit"));
+}
+
+/* ************************************************ */
+/* Grease Pencil Weight Paint Operator */
+
+/* Init/Exit ----------------------------------------------- */
+
+static bool gp_weightpaint_brush_init(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
+ Paint *paint = &ts->gp_weightpaint->paint;
+
+ /* set the brush using the tool */
+ tGP_BrushWeightpaintData *gso;
+
+ /* setup operator data */
+ gso = MEM_callocN(sizeof(tGP_BrushWeightpaintData), "tGP_BrushWeightpaintData");
+ op->customdata = gso;
+
+ gso->bmain = CTX_data_main(C);
+
+ gso->brush = paint->brush;
+ BKE_curvemapping_initialize(gso->brush->curve);
+
+ gso->is_painting = false;
+ gso->first = true;
+
+ gso->pbuffer = NULL;
+ gso->pbuffer_size = 0;
+ gso->pbuffer_used = 0;
+
+ gso->gpd = ED_gpencil_data_get_active(C);
+ gso->scene = scene;
+ gso->object = ob;
+ if (ob) {
+ gso->vrgroup = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
+ gso->vrgroup = -1;
+ }
+ }
+ else {
+ gso->vrgroup = -1;
+ }
+
+ gso->region = CTX_wm_region(C);
+
+ /* Multiframe settings. */
+ gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ /* Init multi-edit falloff curve data before doing anything,
+ * so we won't have to do it again later. */
+ if (gso->is_multiframe) {
+ BKE_curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
+ /* Setup space conversions. */
+ gp_point_conversion_init(C, &gso->gsc);
+
+ /* Update header. */
+ gp_weightpaint_brush_header_set(C);
+
+ return true;
+}
+
+static void gp_weightpaint_brush_exit(bContext *C, wmOperator *op)
+{
+ tGP_BrushWeightpaintData *gso = op->customdata;
+
+ /* Disable headerprints. */
+ ED_workspace_status_text(C, NULL);
+
+ /* Free operator data */
+ MEM_SAFE_FREE(gso->pbuffer);
+ MEM_SAFE_FREE(gso);
+ op->customdata = NULL;
+}
+
+/* Poll callback for stroke weight paint operator. */
+static bool gp_weightpaint_brush_poll(bContext *C)
+{
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+}
+
+/* Helper to save the points selected by the brush. */
+static void gp_save_selected_point(tGP_BrushWeightpaintData *gso,
+ bGPDstroke *gps,
+ int index,
+ int pc[2])
+{
+ tGP_Selected *selected;
+ bGPDspoint *pt = &gps->points[index];
+
+ /* Ensure the array to save the list of selected points is big enough. */
+ gso->pbuffer = gpencil_select_buffer_ensure(
+ gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, false);
+
+ selected = &gso->pbuffer[gso->pbuffer_used];
+ selected->gps = gps;
+ selected->pt_index = index;
+ copy_v2_v2_int(selected->pc, pc);
+ copy_v4_v4(selected->color, pt->vert_color);
+
+ gso->pbuffer_used++;
+}
+
+/* Select points in this stroke and add to an array to be used later. */
+static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
+ bGPDstroke *gps,
+ const float diff_mat[4][4])
+{
+ GP_SpaceConversion *gsc = &gso->gsc;
+ rcti *rect = &gso->brush_rect;
+ Brush *brush = gso->brush;
+ const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
+ gso->brush->size;
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
+
+ bGPDspoint *pt1, *pt2;
+ bGPDspoint *pt = NULL;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+ int index;
+ bool include_last = false;
+
+ /* Check if the stroke collide with brush. */
+ if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) {
+ return;
+ }
+
+ if (gps->totpoints == 1) {
+ bGPDspoint pt_temp;
+ pt = &gps->points[0];
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ /* apply operation to this point */
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, 0, pc1);
+ }
+ }
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* Get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the selection stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ /* Check if point segment of stroke had anything to do with
+ * brush region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(
+ gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+
+ /* To each point individually... */
+ pt = &gps->points[i];
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, index, pc1);
+ }
+
+ /* Only do the second point if this is the last segment,
+ * and it is unlikely that the point will get handled
+ * otherwise.
+ *
+ * NOTE: There is a small risk here that the second point wasn't really
+ * actually in-range. In that case, it only got in because
+ * the line linking the points was!
+ */
+ if (i + 1 == gps->totpoints - 1) {
+ pt = &gps->points[i + 1];
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, index, pc2);
+ include_last = false;
+ }
+ }
+ else {
+ include_last = true;
+ }
+ }
+ else if (include_last) {
+ /* This case is for cases where for whatever reason the second vert (1st here)
+ * doesn't get included because the whole edge isn't in bounds,
+ * but it would've qualified since it did with the previous step
+ * (but wasn't added then, to avoid double-ups).
+ */
+ pt = &gps->points[i];
+ pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
+ index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ gp_save_selected_point(gso, gps_active, index, pc1);
+
+ include_last = false;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Apply weight paint brushes to strokes in the given frame. */
+static bool gp_weightpaint_brush_do_frame(bContext *C,
+ tGP_BrushWeightpaintData *gso,
+ bGPDlayer *gpl,
+ bGPDframe *gpf,
+ const float diff_mat[4][4])
+{
+ Object *ob = CTX_data_active_object(C);
+ char tool = gso->brush->gpencil_weight_tool;
+ const int radius = (gso->brush->flag & GP_BRUSH_USE_PRESSURE) ?
+ gso->brush->size * gso->pressure :
+ gso->brush->size;
+ tGP_Selected *selected = NULL;
+ int i;
+
+ /*---------------------------------------------------------------------
+ * First step: select the points affected. This step is required to have
+ * all selected points before apply the effect, because it could be
+ * required to do some step. Now is not used, but the operator is ready.
+ *--------------------------------------------------------------------- */
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ /* Skip strokes that are invalid for current view. */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ /* Check points below the brush. */
+ gp_weightpaint_select_stroke(gso, gps, diff_mat);
+ }
+
+ /*---------------------------------------------------------------------
+ * Second step: Apply effect.
+ *--------------------------------------------------------------------- */
+ bool changed = false;
+ for (i = 0; i < gso->pbuffer_used; i++) {
+ changed = true;
+ selected = &gso->pbuffer[i];
+
+ switch (tool) {
+ case GPWEIGHT_TOOL_DRAW: {
+ brush_draw_apply(gso, selected->gps, selected->pt_index, radius, selected->pc);
+ changed |= true;
+ break;
+ }
+ default:
+ printf("ERROR: Unknown type of GPencil Weight Paint brush\n");
+ break;
+ }
+ }
+ /* Clear the selected array, but keep the memory allocation.*/
+ gso->pbuffer = gpencil_select_buffer_ensure(
+ gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, true);
+
+ return changed;
+}
+
+/* Apply brush effect to all layers. */
+static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpaintData *gso)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Object *obact = gso->object;
+ bool changed = false;
+
+ Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id);
+ bGPdata *gpd = (bGPdata *)ob_eval->data;
+
+ /* Find visible strokes, and perform operations on those if hit */
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* If locked or no active frame, don't do anything. */
+ if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
+ continue;
+ }
+
+ /* calculate difference matrix */
+ float diff_mat[4][4];
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+
+ /* Active Frame or MultiFrame? */
+ if (gso->is_multiframe) {
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (gso->use_multiframe_falloff) {
+ BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
+ }
+
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ /* Always do active frame; Otherwise, only include selected frames */
+ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
+ /* compute multiframe falloff factor */
+ if (gso->use_multiframe_falloff) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range)
+ */
+ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
+ }
+ else {
+ /* No falloff */
+ gso->mf_falloff = 1.0f;
+ }
+
+ /* affect strokes in this frame */
+ changed |= gp_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat);
+ }
+ }
+ }
+ else {
+ if (gpl->actframe != NULL) {
+ /* Apply to active frame's strokes */
+ gso->mf_falloff = 1.0f;
+ changed |= gp_weightpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Calculate settings for applying brush */
+static void gp_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
+{
+ tGP_BrushWeightpaintData *gso = op->customdata;
+ Brush *brush = gso->brush;
+ const int radius = ((brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
+ gso->brush->size);
+ float mousef[2];
+ int mouse[2];
+ bool changed = false;
+
+ /* Get latest mouse coordinates */
+ RNA_float_get_array(itemptr, "mouse", mousef);
+ gso->mval[0] = mouse[0] = (int)(mousef[0]);
+ gso->mval[1] = mouse[1] = (int)(mousef[1]);
+
+ gso->pressure = RNA_float_get(itemptr, "pressure");
+
+ /* Store coordinates as reference, if operator just started running */
+ if (gso->first) {
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ }
+
+ /* Update brush_rect, so that it represents the bounding rectangle of brush. */
+ gso->brush_rect.xmin = mouse[0] - radius;
+ gso->brush_rect.ymin = mouse[1] - radius;
+ gso->brush_rect.xmax = mouse[0] + radius;
+ gso->brush_rect.ymax = mouse[1] + radius;
+
+ /* Calc 2D direction vector and relative angle. */
+ brush_calc_dvec_2d(gso);
+
+ changed = gp_weightpaint_brush_apply_to_layers(C, gso);
+
+ /* Updates */
+ if (changed) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ /* Store values for next step */
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ gso->first = false;
+}
+
+/* Running --------------------------------------------- */
+
+/* helper - a record stroke, and apply paint event */
+static void gp_weightpaint_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushWeightpaintData *gso = op->customdata;
+ PointerRNA itemptr;
+ float mouse[2];
+
+ mouse[0] = event->mval[0] + 1;
+ mouse[1] = event->mval[1] + 1;
+
+ /* fill in stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
+ RNA_boolean_set(&itemptr, "is_start", gso->first);
+
+ /* Handle pressure sensitivity (which is supplied by tablets). */
+ float pressure = event->tablet.pressure;
+ CLAMP(pressure, 0.0f, 1.0f);
+ RNA_float_set(&itemptr, "pressure", pressure);
+
+ /* apply */
+ gp_weightpaint_brush_apply(C, op, &itemptr);
+}
+
+/* reapply */
+static int gp_weightpaint_brush_exec(bContext *C, wmOperator *op)
+{
+ if (!gp_weightpaint_brush_init(C, op)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ gp_weightpaint_brush_apply(C, op, &itemptr);
+ }
+ RNA_END;
+
+ gp_weightpaint_brush_exit(C, op);
+
+ return OPERATOR_FINISHED;
+}
+
+/* start modal painting */
+static int gp_weightpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushWeightpaintData *gso = NULL;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
+
+ /* the operator cannot work while play animation */
+ if (is_playing) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot Paint while play animation");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init painting data */
+ if (!gp_weightpaint_brush_init(C, op)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ gso = op->customdata;
+
+ /* register modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ /* start drawing immediately? */
+ if (is_modal == false) {
+ ARegion *region = CTX_wm_region(C);
+
+ /* apply first dab... */
+ gso->is_painting = true;
+ gp_weightpaint_brush_apply_event(C, op, event);
+
+ /* redraw view with feedback */
+ ED_region_tag_redraw(region);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* painting - handle events */
+static int gp_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushWeightpaintData *gso = op->customdata;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ bool redraw_region = false;
+ bool redraw_toolsettings = false;
+
+ /* The operator can be in 2 states: Painting and Idling */
+ if (gso->is_painting) {
+ /* Painting */
+ switch (event->type) {
+ /* Mouse Move = Apply somewhere else */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ /* apply brush effect at new position */
+ gp_weightpaint_brush_apply_event(C, op, event);
+
+ /* force redraw, so that the cursor will at least be valid */
+ redraw_region = true;
+ break;
+
+ /* Painting mbut release = Stop painting (back to idle) */
+ case LEFTMOUSE:
+ if (is_modal) {
+ /* go back to idling... */
+ gso->is_painting = false;
+ }
+ else {
+ /* end painting, since we're not modal */
+ gso->is_painting = false;
+
+ gp_weightpaint_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ /* Abort painting if any of the usual things are tried */
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gp_weightpaint_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ /* Idling */
+ BLI_assert(is_modal == true);
+
+ switch (event->type) {
+ /* Painting mbut press = Start painting (switch to painting state) */
+ case LEFTMOUSE:
+ /* do initial "click" apply */
+ gso->is_painting = true;
+ gso->first = true;
+
+ gp_weightpaint_brush_apply_event(C, op, event);
+ break;
+
+ /* Exit modal operator, based on the "standard" ops */
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gp_weightpaint_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+
+ /* MMB is often used for view manipulations */
+ case MIDDLEMOUSE:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Mouse movements should update the brush cursor - Just redraw the active region */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ redraw_region = true;
+ break;
+
+ /* Change Frame - Allowed */
+ case LEFTARROWKEY:
+ case RIGHTARROWKEY:
+ case UPARROWKEY:
+ case DOWNARROWKEY:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Camera/View Gizmo's - Allowed */
+ /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
+ case PAD0:
+ case PAD1:
+ case PAD2:
+ case PAD3:
+ case PAD4:
+ case PAD5:
+ case PAD6:
+ case PAD7:
+ case PAD8:
+ case PAD9:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Unhandled event */
+ default:
+ break;
+ }
+ }
+
+ /* Redraw region? */
+ if (redraw_region) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
+
+ /* Redraw toolsettings (brush settings)? */
+ if (redraw_toolsettings) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void GPENCIL_OT_weight_paint(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Stroke Weight Paint";
+ ot->idname = "GPENCIL_OT_weight_paint";
+ ot->description = "Paint stroke points with a color";
+
+ /* api callbacks */
+ ot->exec = gp_weightpaint_brush_exec;
+ ot->invoke = gp_weightpaint_brush_invoke;
+ ot->modal = gp_weightpaint_brush_modal;
+ ot->cancel = gp_weightpaint_brush_exit;
+ ot->poll = gp_weightpaint_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 8d2d9b934d4..8dd162ea538 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -39,6 +39,7 @@ struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
struct tGPspoint;
+struct GP_SpaceConversion;
struct ARegion;
struct Depsgraph;
@@ -46,6 +47,7 @@ struct Main;
struct RegionView3D;
struct ReportList;
struct Scene;
+struct ToolSettings;
struct ScrArea;
struct View3D;
struct ViewLayer;
@@ -75,23 +77,8 @@ typedef struct tGPspoint {
float uv_rot; /* uv rotation for dor mode */
float rnd[3]; /* rnd value */
bool rnd_dirty; /* rnd flag */
- short tflag; /* Internal flag */
} tGPspoint;
-/* tGPspoint->flag */
-typedef enum etGPspoint_tFlag {
- /* Created by Fake event (used when mouse/pen move very fast while drawing). */
- GP_TPOINT_FAKE = (1 << 0),
-} etGPspoint_tFlag;
-
-/* used to sort by zdepth gpencil objects in viewport */
-/* TODO: this could be a system parameter in userprefs screen */
-#define GP_CACHE_BLOCK_SIZE 16
-typedef struct tGPencilSort {
- struct Base *base;
- float zdepth;
-} tGPencilSort;
-
/* ----------- Grease Pencil Tools/Context ------------- */
/* Context-dependent */
@@ -210,12 +197,6 @@ bool ED_gpencil_add_lattice_modifier(const struct bContext *C,
/* ------------ Transformation Utilities ------------ */
-/* get difference matrix */
-void ED_gpencil_parent_location(const struct Depsgraph *depsgraph,
- struct Object *obact,
- struct bGPdata *gpd,
- struct bGPDlayer *gpl,
- float diff_mat[4][4]);
/* reset parent matrix for all layers */
void ED_gpencil_reset_layers_parent(struct Depsgraph *depsgraph,
struct Object *obact,
@@ -231,7 +212,6 @@ void ED_gpencil_create_stroke(struct bContext *C, struct Object *ob, float mat[4
/* ------------ Object Utilities ------------ */
struct Object *ED_gpencil_add_object(struct bContext *C,
- struct Scene *scene,
const float loc[3],
unsigned short local_view_bits);
void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob);
@@ -251,11 +231,11 @@ void ED_gp_project_point_to_plane(const struct Scene *scene,
const float origin[3],
const int axis,
struct bGPDspoint *pt);
-void ED_gp_get_drawing_reference(const struct Scene *scene,
- const struct Object *ob,
- struct bGPDlayer *gpl,
- char align_flag,
- float vec[3]);
+void ED_gpencil_drawing_reference_get(const struct Scene *scene,
+ const struct Object *ob,
+ struct bGPDlayer *gpl,
+ char align_flag,
+ float vec[3]);
void ED_gpencil_project_stroke_to_view(struct bContext *C,
struct bGPDlayer *gpl,
struct bGPDstroke *gps);
@@ -277,7 +257,6 @@ void ED_gpencil_tpoint_to_point(struct ARegion *region,
float origin[3],
const struct tGPspoint *tpt,
struct bGPDspoint *pt);
-void ED_gpencil_calc_stroke_uv(struct Object *ob, struct bGPDstroke *gps);
void ED_gpencil_update_color_uv(struct Main *bmain, struct Material *mat);
/* extend selection to stroke intersections
@@ -303,9 +282,30 @@ struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
const bool clear);
+void ED_gpencil_sbuffer_update_eval(struct bGPdata *gpd, struct Object *ob_eval);
+
/* Tag all scene grease pencil object to update. */
void ED_gpencil_tag_scene_gpencil(struct Scene *scene);
+/* Vertex color set. */
+void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts,
+ struct Brush *brush,
+ struct bGPDstroke *gps);
+void ED_gpencil_point_vertex_color_set(struct ToolSettings *ts,
+ struct Brush *brush,
+ struct bGPDspoint *pt);
+void ED_gpencil_sbuffer_vertex_color_set(struct Depsgraph *depsgraph,
+ struct Object *ob,
+ struct ToolSettings *ts,
+ struct Brush *brush,
+ struct Material *material);
+
+bool ED_gpencil_stroke_check_collision(struct GP_SpaceConversion *gsc,
+ struct bGPDstroke *gps,
+ float mouse[2],
+ const int radius,
+ const float diff_mat[4][4]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 165a53203f3..a0a3d0a3b85 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4115,9 +4115,9 @@ static void ui_def_but_rna__panel_type(bContext *C, uiLayout *layout, void *but_
void ui_but_rna_menu_convert_to_panel_type(uiBut *but, const char *panel_type)
{
- BLI_assert(but->type == UI_BTYPE_MENU);
- BLI_assert(but->menu_create_func == ui_def_but_rna__menu);
- BLI_assert((void *)but->poin == but);
+ BLI_assert(ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_COLOR));
+ // BLI_assert(but->menu_create_func == ui_def_but_rna__menu);
+ // BLI_assert((void *)but->poin == but);
but->menu_create_func = ui_def_but_rna__panel_type;
but->func_argN = BLI_strdup(panel_type);
}
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
index 790609a17d8..f9f5c745e94 100644
--- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
@@ -39,6 +39,7 @@
#include "BKE_gpencil.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "UI_interface.h"
@@ -65,6 +66,8 @@ typedef struct EyedropperGPencil {
struct ColorManagedDisplay *display;
/** color under cursor RGB */
float color[3];
+ /** Mode */
+ int mode;
} EyedropperGPencil;
/* Helper: Draw status message while the user is running the operator */
@@ -89,6 +92,7 @@ static bool eyedropper_gpencil_init(bContext *C, wmOperator *op)
display_device = scene->display_settings.display_device;
eye->display = IMB_colormanagement_display_get_named(display_device);
+ eye->mode = RNA_enum_get(op->ptr, "mode");
return true;
}
@@ -101,31 +105,15 @@ static void eyedropper_gpencil_exit(bContext *C, wmOperator *op)
MEM_SAFE_FREE(op->customdata);
}
-/* Set the material. */
-static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, EyedropperGPencil *eye)
+static void eyedropper_add_material(
+ bContext *C, float col_conv[4], const bool only_stroke, const bool only_fill, const bool both)
{
Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
Material *ma = NULL;
- const bool only_stroke = ((!event->ctrl) && (!event->shift));
- const bool only_fill = ((!event->ctrl) && (event->shift));
- const bool both = ((event->ctrl) && (event->shift));
-
- float col_conv[4];
bool found = false;
- /* Convert from linear rgb space to display space because grease pencil colors are in display
- * space, and this conversion is needed to undo the conversion to linear performed by
- * eyedropper_color_sample_fl. */
- if (eye->display) {
- copy_v3_v3(col_conv, eye->color);
- IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
- }
- else {
- copy_v3_v3(col_conv, eye->color);
- }
-
/* Look for a similar material in grease pencil slots. */
short *totcol = BKE_object_material_len_p(ob);
for (short i = 0; i < *totcol; i++) {
@@ -138,15 +126,15 @@ static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, Eyed
if (gp_style != NULL) {
/* Check stroke color. */
bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) &&
- (gp_style->flag & GP_STYLE_STROKE_SHOW);
+ (gp_style->flag & GP_MATERIAL_STROKE_SHOW);
/* Check fill color. */
bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) &&
- (gp_style->flag & GP_STYLE_FILL_SHOW);
+ (gp_style->flag & GP_MATERIAL_FILL_SHOW);
- if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) {
+ if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
found = true;
}
- else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0)) {
+ else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0)) {
found = true;
}
else if ((both) && (found_stroke) && (found_fill)) {
@@ -180,22 +168,22 @@ static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, Eyed
/* Only create Stroke (default option). */
if (only_stroke) {
/* Stroke color. */
- gp_style_new->flag |= GP_STYLE_STROKE_SHOW;
- gp_style_new->flag &= ~GP_STYLE_FILL_SHOW;
+ gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW;
+ gp_style_new->flag &= ~GP_MATERIAL_FILL_SHOW;
copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
zero_v4(gp_style_new->fill_rgba);
}
/* Fill Only. */
else if (only_fill) {
/* Fill color. */
- gp_style_new->flag &= ~GP_STYLE_STROKE_SHOW;
- gp_style_new->flag |= GP_STYLE_FILL_SHOW;
+ gp_style_new->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ gp_style_new->flag |= GP_MATERIAL_FILL_SHOW;
zero_v4(gp_style_new->stroke_rgba);
copy_v3_v3(gp_style_new->fill_rgba, col_conv);
}
/* Stroke and Fill. */
else if (both) {
- gp_style_new->flag |= GP_STYLE_STROKE_SHOW | GP_STYLE_FILL_SHOW;
+ gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW | GP_MATERIAL_FILL_SHOW;
copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
copy_v3_v3(gp_style_new->fill_rgba, col_conv);
}
@@ -203,6 +191,69 @@ static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, Eyed
ED_undo_push(C, "Add Grease Pencil Material");
}
+/* Create a new palette color and palette if needed. */
+static void eyedropper_add_palette_color(bContext *C, float col_conv[4])
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ GpPaint *gp_paint = ts->gp_paint;
+ GpVertexPaint *gp_vertexpaint = ts->gp_vertexpaint;
+ Paint *paint = &gp_paint->paint;
+ Paint *vertexpaint = &gp_vertexpaint->paint;
+
+ /* Check for Palette in Draw and Vertex Paint Mode. */
+ if (paint->palette == NULL) {
+ paint->palette = BKE_palette_add(bmain, "Grease Pencil");
+ if (vertexpaint->palette == NULL) {
+ vertexpaint->palette = paint->palette;
+ }
+ }
+ /* Check if the color exist already. */
+ Palette *palette = paint->palette;
+ for (PaletteColor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ if (compare_v3v3(palcolor->rgb, col_conv, 0.01f)) {
+ return;
+ }
+ }
+
+ /* Create Colors. */
+ PaletteColor *palcol = BKE_palette_color_add(palette);
+ if (palcol) {
+ copy_v3_v3(palcol->rgb, col_conv);
+ }
+}
+
+/* Set the material or the palette color. */
+static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, EyedropperGPencil *eye)
+{
+
+ const bool only_stroke = ((!event->ctrl) && (!event->shift));
+ const bool only_fill = ((!event->ctrl) && (event->shift));
+ const bool both = ((event->ctrl) && (event->shift));
+
+ float col_conv[4];
+
+ /* Convert from linear rgb space to display space because grease pencil colors are in display
+ * space, and this conversion is needed to undo the conversion to linear performed by
+ * eyedropper_color_sample_fl. */
+ if (eye->display) {
+ copy_v3_v3(col_conv, eye->color);
+ IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
+ }
+ else {
+ copy_v3_v3(col_conv, eye->color);
+ }
+
+ /* Add material or Palette color*/
+ if (eye->mode == 0) {
+ eyedropper_add_material(C, col_conv, only_stroke, only_fill, both);
+ }
+ else {
+ eyedropper_add_palette_color(C, col_conv);
+ }
+}
+
/* Sample the color below cursor. */
static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, int mx, int my)
{
@@ -307,6 +358,12 @@ static bool eyedropper_gpencil_poll(bContext *C)
void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot)
{
+ static const EnumPropertyItem items_mode[] = {
+ {0, "MATERIAL", 0, "Material", ""},
+ {1, "PALETTE", 0, "Palette", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
/* identifiers */
ot->name = "Grease Pencil Eyedropper";
ot->idname = "UI_OT_eyedropper_gpencil_color";
@@ -321,4 +378,7 @@ void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "mode", items_mode, 0, "Mode", "");
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 6a9632f54bb..088a904ec78 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -3994,7 +3994,12 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
copy_v3_v3(data->vec, data->origvec);
but->editvec = data->vec;
- handlefunc = ui_block_func_COLOR;
+ if (ui_but_menu_draw_as_popover(but)) {
+ popoverfunc = but->menu_create_func;
+ }
+ else {
+ handlefunc = ui_block_func_COLOR;
+ }
arg = but;
break;
@@ -4063,8 +4068,8 @@ int ui_but_menu_direction(uiBut *but)
}
/**
- * Hack for #uiList #UI_BTYPE_LISTROW buttons to "give" events to overlaying #UI_BTYPE_TEXT buttons
- * (Ctrl-Click rename feature & co).
+ * Hack for #uiList #UI_BTYPE_LISTROW buttons to "give" events to overlaying #UI_BTYPE_TEXT
+ * buttons (Ctrl-Click rename feature & co).
*/
static uiBut *ui_but_list_row_text_activate(bContext *C,
uiBut *but,
@@ -5553,14 +5558,13 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
button_activate_state(C, but, BUTTON_STATE_EXIT);
ui_apply_but(C, but->block, but, data, true);
- /* Button's state need to be changed to EXIT so moving mouse away from this mouse wouldn't
- * lead to cancel changes made to this button, but changing state to EXIT also makes no
- * button active for a while which leads to triggering operator
- * when doing fast scrolling mouse wheel.
- * using post activate stuff from button allows to make button be active again after
- * checking for all all that mouse leave and cancel stuff,
- * so quick scroll wouldn't be an issue anymore.
- * Same goes for scrolling wheel in another direction below (sergey).
+ /* Button's state need to be changed to EXIT so moving mouse away from this mouse
+ * wouldn't lead to cancel changes made to this button, but changing state to EXIT also
+ * makes no button active for a while which leads to triggering operator when doing fast
+ * scrolling mouse wheel. using post activate stuff from button allows to make button be
+ * active again after checking for all all that mouse leave and cancel stuff, so quick
+ * scroll wouldn't be an issue anymore. Same goes for scrolling wheel in another
+ * direction below (sergey).
*/
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_OVER;
@@ -5797,15 +5801,27 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
else {
Scene *scene = CTX_data_scene(C);
+ bool updated = false;
if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
BKE_brush_color_set(scene, brush, color);
+ updated = true;
}
else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
IMB_colormanagement_scene_linear_to_srgb_v3(color);
BKE_brush_color_set(scene, brush, color);
+ updated = true;
+ }
+
+ if (updated) {
+ PointerRNA brush_ptr;
+ PropertyRNA *brush_color_prop;
+
+ RNA_id_pointer_create(&brush->id, &brush_ptr);
+ brush_color_prop = RNA_struct_find_property(&brush_ptr, "color");
+ RNA_property_update(C, &brush_ptr, brush_color_prop);
}
}
@@ -9519,7 +9535,8 @@ static int ui_handle_menu_event(bContext *C,
/* Closing sub-levels of pull-downs.
*
* The actual event is handled by the button under the cursor.
- * This is done so we can right click on menu items even when they have sub-menus open. */
+ * This is done so we can right click on menu items even when they have sub-menus open.
+ */
case RIGHTMOUSE:
if (inside == false) {
if (event->val == KM_PRESS && (block->flag & UI_BLOCK_LOOP)) {
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index c1018a67fb3..3e07023e52d 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -2050,7 +2050,10 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
}
/* reset the icon */
- if ((ob != NULL) && (ob->mode & OB_MODE_PAINT_GPENCIL) && (br->gpencil_settings != NULL)) {
+ if ((ob != NULL) &&
+ (ob->mode & (OB_MODE_PAINT_GPENCIL | OB_MODE_VERTEX_GPENCIL | OB_MODE_SCULPT_GPENCIL |
+ OB_MODE_WEIGHT_GPENCIL)) &&
+ (br->gpencil_settings != NULL)) {
switch (br->gpencil_settings->icon_id) {
case GP_BRUSH_ICON_PENCIL:
br->id.icon_id = ICON_GPBRUSH_PENCIL;
@@ -2088,6 +2091,54 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
case GP_BRUSH_ICON_ERASE_STROKE:
br->id.icon_id = ICON_GPBRUSH_ERASE_STROKE;
break;
+ case GP_BRUSH_ICON_TINT:
+ br->id.icon_id = ICON_BRUSH_TEXDRAW;
+ break;
+ case GP_BRUSH_ICON_VERTEX_DRAW:
+ br->id.icon_id = ICON_BRUSH_MIX;
+ break;
+ case GP_BRUSH_ICON_VERTEX_BLUR:
+ br->id.icon_id = ICON_BRUSH_BLUR;
+ break;
+ case GP_BRUSH_ICON_VERTEX_AVERAGE:
+ br->id.icon_id = ICON_BRUSH_BLUR;
+ break;
+ case GP_BRUSH_ICON_VERTEX_SMEAR:
+ br->id.icon_id = ICON_BRUSH_BLUR;
+ break;
+ case GP_BRUSH_ICON_VERTEX_REPLACE:
+ br->id.icon_id = ICON_BRUSH_MIX;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_SMOOTH:
+ br->id.icon_id = ICON_GPBRUSH_SMOOTH;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_THICKNESS:
+ br->id.icon_id = ICON_GPBRUSH_THICKNESS;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_STRENGTH:
+ br->id.icon_id = ICON_GPBRUSH_STRENGTH;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_RANDOMIZE:
+ br->id.icon_id = ICON_GPBRUSH_RANDOMIZE;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_GRAB:
+ br->id.icon_id = ICON_GPBRUSH_GRAB;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_PUSH:
+ br->id.icon_id = ICON_GPBRUSH_PUSH;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_TWIST:
+ br->id.icon_id = ICON_GPBRUSH_TWIST;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_PINCH:
+ br->id.icon_id = ICON_GPBRUSH_PINCH;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_CLONE:
+ br->id.icon_id = ICON_GPBRUSH_CLONE;
+ break;
+ case GP_BRUSH_ICON_GPBRUSH_WEIGHT:
+ br->id.icon_id = ICON_GPBRUSH_WEIGHT;
+ break;
default:
br->id.icon_id = ICON_GPBRUSH_PEN;
break;
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 8e65b818314..dd002f4e77f 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -2325,7 +2325,7 @@ void uiItemFullR_with_popover(uiLayout *layout,
uiItemFullR(layout, ptr, prop, index, value, flag, name, icon);
but = but->next;
while (but) {
- if (but->rnaprop == prop && but->type == UI_BTYPE_MENU) {
+ if (but->rnaprop == prop && ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_COLOR)) {
ui_but_rna_menu_convert_to_panel_type(but, panel_type);
break;
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index c80c5317735..b752a1a1429 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -5385,6 +5385,21 @@ void uiTemplateColorPicker(uiLayout *layout,
}
}
+static void ui_template_palette_menu(bContext *UNUSED(C), uiLayout *layout, void *UNUSED(but_p))
+{
+ uiLayout *row;
+
+ uiItemL(layout, IFACE_("Sort by:"), ICON_NONE);
+ row = uiLayoutRow(layout, false);
+ uiItemEnumO_value(row, IFACE_("Hue"), ICON_NONE, "PALETTE_OT_sort", "type", 1);
+ row = uiLayoutRow(layout, false);
+ uiItemEnumO_value(row, IFACE_("Saturation"), ICON_NONE, "PALETTE_OT_sort", "type", 2);
+ row = uiLayoutRow(layout, false);
+ uiItemEnumO_value(row, IFACE_("Value"), ICON_NONE, "PALETTE_OT_sort", "type", 3);
+ row = uiLayoutRow(layout, false);
+ uiItemEnumO_value(row, IFACE_("Luminance"), ICON_NONE, "PALETTE_OT_sort", "type", 4);
+}
+
void uiTemplatePalette(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -5396,6 +5411,8 @@ void uiTemplatePalette(uiLayout *layout,
PaletteColor *color;
uiBlock *block;
uiLayout *col;
+ uiBut *but = NULL;
+
int row_cols = 0, col_id = 0;
int cols_per_row = MAX2(uiLayoutGetWidth(layout) / UI_UNIT_X, 1);
@@ -5437,6 +5454,37 @@ void uiTemplatePalette(uiLayout *layout,
UI_UNIT_X,
UI_UNIT_Y,
NULL);
+ if (color) {
+ but = uiDefIconButO(block,
+ UI_BTYPE_BUT,
+ "PALETTE_OT_color_move",
+ WM_OP_INVOKE_DEFAULT,
+ ICON_TRIA_UP,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL);
+ UI_but_operator_ptr_get(but);
+ RNA_enum_set(but->opptr, "type", -1);
+
+ but = uiDefIconButO(block,
+ UI_BTYPE_BUT,
+ "PALETTE_OT_color_move",
+ WM_OP_INVOKE_DEFAULT,
+ ICON_TRIA_DOWN,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL);
+ UI_but_operator_ptr_get(but);
+ RNA_enum_set(but->opptr, "type", 1);
+
+ /* Menu. */
+ uiDefIconMenuBut(
+ block, ui_template_palette_menu, NULL, ICON_SORTSIZE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
+ }
col = uiLayoutColumn(layout, true);
uiLayoutRow(col, true);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 06f532f99e3..17b6bfdb956 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1537,7 +1537,7 @@ static int object_delete_exec(bContext *C, wmOperator *op)
* Will also remove parent from grease pencil from other scenes,
* even when use_global is false... */
for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl->parent != NULL) {
if (gpl->parent == ob) {
gpl->parent = NULL;
@@ -2394,7 +2394,7 @@ static int convert_exec(bContext *C, wmOperator *op)
* Nurbs Surface are not supported.
*/
ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
- gpencil_ob = ED_gpencil_add_object(C, scene, ob->loc, local_view_bits);
+ gpencil_ob = ED_gpencil_add_object(C, ob->loc, local_view_bits);
copy_v3_v3(gpencil_ob->rot, ob->rot);
copy_v3_v3(gpencil_ob->scale, ob->scale);
BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index f9ac0474d44..def93db2537 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1370,7 +1370,8 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
OB_MODE_EDIT_GPENCIL,
OB_MODE_PAINT_GPENCIL,
OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL) &&
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL) &&
(ob->type == OB_GPENCIL)) ||
(input->value == OB_MODE_OBJECT)) {
RNA_enum_item_add(&item, &totitem, input);
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index 9138e65dd2f..4543f1a19b3 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -91,6 +91,11 @@ GpencilModifierData *ED_object_gpencil_modifier_add(
/* make sure modifier data has unique name */
BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md);
+ /* Enable edit mode visible by default. */
+ if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) {
+ new_md->mode |= eGpencilModifierMode_Editmode;
+ }
+
bGPdata *gpd = ob->data;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -362,7 +367,7 @@ void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Grease Pencil Modifier";
+ ot->name = "Add Modifier";
ot->description = "Add a procedural operation/effect to the active grease pencil object";
ot->idname = "OBJECT_OT_gpencil_modifier_add";
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 80e7e6312aa..edc2f15813c 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -88,6 +88,9 @@ static const char *object_mode_op_string(eObjectMode mode)
if (mode == OB_MODE_WEIGHT_GPENCIL) {
return "GPENCIL_OT_weightmode_toggle";
}
+ if (mode == OB_MODE_VERTEX_GPENCIL) {
+ return "GPENCIL_OT_vertexmode_toggle";
+ }
return NULL;
}
@@ -129,7 +132,7 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
break;
case OB_GPENCIL:
if (mode & (OB_MODE_EDIT | OB_MODE_EDIT_GPENCIL | OB_MODE_PAINT_GPENCIL |
- OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL)) {
+ OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL)) {
return true;
}
break;
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 039714ca3ec..3b1fb49c383 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -696,7 +696,7 @@ static int apply_objects_internal(bContext *C,
/* Unsupported configuration */
bool has_unparented_layers = false;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* Parented layers aren't supported as we can't easily re-evaluate
* the scene to sample parent movement */
if (gpl->parent == NULL) {
@@ -1394,13 +1394,13 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* recalculate all strokes
* (all layers are considered without evaluating lock attributes) */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
/* undo matrix */
invert_m4_m4(inverse_diff_mat, diff_mat);
- 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) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
float mpt[3];
mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e72818479c4..444413a757f 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1723,9 +1723,81 @@ static void ed_default_handlers(
wm->defaultconf, "Grease Pencil Stroke Paint (Fill)", 0, 0);
WM_event_add_keymap_handler(handlers, keymap_paint_fill);
+ wmKeyMap *keymap_paint_tint = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Paint (Tint)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_paint_tint);
+
wmKeyMap *keymap_sculpt = WM_keymap_ensure(
wm->defaultconf, "Grease Pencil Stroke Sculpt Mode", 0, 0);
WM_event_add_keymap_handler(handlers, keymap_sculpt);
+
+ wmKeyMap *keymap_vertex = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Vertex Mode", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_vertex);
+
+ wmKeyMap *keymap_vertex_draw = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Vertex (Draw)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_vertex_draw);
+
+ wmKeyMap *keymap_vertex_blur = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Vertex (Blur)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_vertex_blur);
+
+ wmKeyMap *keymap_vertex_average = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Vertex (Average)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_vertex_average);
+
+ wmKeyMap *keymap_vertex_smear = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Vertex (Smear)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_vertex_smear);
+
+ wmKeyMap *keymap_vertex_replace = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Vertex (Replace)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_vertex_replace);
+
+ wmKeyMap *keymap_sculpt_smooth = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Smooth)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_smooth);
+
+ wmKeyMap *keymap_sculpt_thickness = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Thickness)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_thickness);
+
+ wmKeyMap *keymap_sculpt_strength = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Strength)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_strength);
+
+ wmKeyMap *keymap_sculpt_grab = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Grab)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_grab);
+
+ wmKeyMap *keymap_sculpt_push = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Push)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_push);
+
+ wmKeyMap *keymap_sculpt_twist = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Twist)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_twist);
+
+ wmKeyMap *keymap_sculpt_pinch = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Pinch)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_pinch);
+
+ wmKeyMap *keymap_sculpt_randomize = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Randomize)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_randomize);
+
+ wmKeyMap *keymap_sculpt_clone = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Sculpt (Clone)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_sculpt_clone);
+
+ wmKeyMap *keymap_weight = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Weight Mode", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_weight);
+
+ wmKeyMap *keymap_weight_draw = WM_keymap_ensure(
+ wm->defaultconf, "Grease Pencil Stroke Weight (Draw)", 0, 0);
+ WM_event_add_keymap_handler(handlers, keymap_weight_draw);
}
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index a840d199823..540a4c05247 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -555,7 +555,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
if (gpd) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
@@ -567,7 +567,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene);
if (gpd) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
@@ -579,7 +579,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
if (gpd) {
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe);
@@ -609,7 +609,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpencil_layer_is_editable(gpl)) {
+ if (BKE_gpencil_layer_is_editable(gpl)) {
CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
}
}
@@ -625,7 +625,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe)) {
bGPDframe *gpf;
bGPDstroke *gps;
bGPDframe *init_gpf = gpl->actframe;
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index ee1cb09ae94..6fe1ba0b817 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -26,6 +26,9 @@
#include "BLI_math_vector.h"
#include "BLI_string.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
#include "DNA_customdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -33,9 +36,11 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -294,6 +299,315 @@ static void PALETTE_OT_color_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* --- Extract Palette from Image. */
+static bool palette_extract_img_poll(bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ if (sl->spacetype == SPACE_IMAGE) {
+ return true;
+ }
+
+ return false;
+}
+
+static int palette_extract_img_exec(bContext *C, wmOperator *op)
+{
+ const int threshold = RNA_int_get(op->ptr, "threshold");
+
+ Main *bmain = CTX_data_main(C);
+ bool done = false;
+
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *image = sima->image;
+ ImageUser iuser = sima->iuser;
+ void *lock;
+ ImBuf *ibuf;
+ GHash *color_table = BLI_ghash_int_new(__func__);
+
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf->rect) {
+ /* Extract all colors. */
+ for (int row = 0; row < ibuf->y; row++) {
+ for (int col = 0; col < ibuf->x; col++) {
+ float color[4];
+ IMB_sampleImageAtLocation(ibuf, (float)col, (float)row, false, color);
+ const float range = pow(10.0f, threshold);
+ color[0] = truncf(color[0] * range) / range;
+ color[1] = truncf(color[1] * range) / range;
+ color[2] = truncf(color[2] * range) / range;
+
+ uint key = rgb_to_cpack(color[0], color[1], color[2]);
+ if (!BLI_ghash_haskey(color_table, POINTER_FROM_INT(key))) {
+ BLI_ghash_insert(color_table, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
+ }
+ }
+ }
+
+ done = BKE_palette_from_hash(bmain, color_table, image->id.name + 2, false);
+ }
+
+ /* Free memory. */
+ BLI_ghash_free(color_table, NULL, NULL);
+ BKE_image_release_ibuf(image, ibuf, lock);
+
+ if (done) {
+ BKE_reportf(op->reports, RPT_INFO, "Palette created");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_extract_from_image(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Extract Palette from Image";
+ ot->idname = "PALETTE_OT_extract_from_image";
+ ot->description = "Extract all colors used in Image and create a Palette";
+
+ /* api callbacks */
+ ot->exec = palette_extract_img_exec;
+ ot->poll = palette_extract_img_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "threshold", 1, 1, 4, "Threshold", "", 1, 4);
+}
+
+/* Sort Palette color by Hue and Saturation. */
+static bool palette_sort_poll(bContext *C)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ if (palette) {
+ return true;
+ }
+
+ return false;
+}
+
+static int palette_sort_exec(bContext *C, wmOperator *op)
+{
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+
+ if (palette == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ tPaletteColorHSV *color_array = NULL;
+ tPaletteColorHSV *col_elm = NULL;
+
+ const int totcol = BLI_listbase_count(&palette->colors);
+
+ if (totcol > 0) {
+ color_array = MEM_calloc_arrayN(totcol, sizeof(tPaletteColorHSV), __func__);
+ /* Put all colors in an array. */
+ int t = 0;
+ for (PaletteColor *color = palette->colors.first; color; color = color->next) {
+ float h, s, v;
+ rgb_to_hsv(color->rgb[0], color->rgb[1], color->rgb[2], &h, &s, &v);
+ col_elm = &color_array[t];
+ copy_v3_v3(col_elm->rgb, color->rgb);
+ col_elm->value = color->value;
+ col_elm->h = h;
+ col_elm->s = s;
+ col_elm->v = v;
+ t++;
+ }
+ /* Sort */
+ if (type == 1) {
+ BKE_palette_sort_hsv(color_array, totcol);
+ }
+ else if (type == 2) {
+ BKE_palette_sort_svh(color_array, totcol);
+ }
+ else if (type == 3) {
+ BKE_palette_sort_vhs(color_array, totcol);
+ }
+ else {
+ BKE_palette_sort_luminance(color_array, totcol);
+ }
+
+ /* Clear old color swatches. */
+ PaletteColor *color_next = NULL;
+ for (PaletteColor *color = palette->colors.first; color; color = color_next) {
+ color_next = color->next;
+ BKE_palette_color_remove(palette, color);
+ }
+
+ /* Recreate swatches sorted. */
+ for (int i = 0; i < totcol; i++) {
+ col_elm = &color_array[i];
+ PaletteColor *palcol = BKE_palette_color_add(palette);
+ if (palcol) {
+ copy_v3_v3(palcol->rgb, col_elm->rgb);
+ }
+ }
+ }
+
+ /* Free memory. */
+ if (totcol > 0) {
+ MEM_SAFE_FREE(color_array);
+ }
+
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_sort(wmOperatorType *ot)
+{
+ static const EnumPropertyItem sort_type[] = {
+ {1, "HSV", 0, "Hue, Saturation, Value", ""},
+ {2, "SVH", 0, "Saturation, Value, Hue", ""},
+ {3, "VHS", 0, "Value, Hue, Saturation", ""},
+ {4, "LUMINANCE", 0, "Luminance", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Sort Palette";
+ ot->idname = "PALETTE_OT_sort";
+ ot->description = "Sort Palette Colors";
+
+ /* api callbacks */
+ ot->exec = palette_sort_exec;
+ ot->poll = palette_sort_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", sort_type, 1, "Type", "");
+}
+
+/* Move colors in palette. */
+static int palette_color_move_exec(bContext *C, wmOperator *op)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ PaletteColor *palcolor = BLI_findlink(&palette->colors, palette->active_color);
+
+ if (palcolor == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int direction = RNA_enum_get(op->ptr, "type");
+
+ BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
+ if (BLI_listbase_link_move(&palette->colors, palcolor, direction)) {
+ palette->active_color += direction;
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_color_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem slot_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Move Palette Color";
+ ot->idname = "PALETTE_OT_color_move";
+ ot->description = "Move the active Color up/down in the list";
+
+ /* api callbacks */
+ ot->exec = palette_color_move_exec;
+ ot->poll = palette_sort_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
+
+/* Join Palette swatches. */
+static bool palette_join_poll(bContext *C)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ if (palette) {
+ return true;
+ }
+
+ return false;
+}
+
+static int palette_join_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ Palette *palette_join = NULL;
+ bool done = false;
+
+ char name[MAX_ID_NAME - 2];
+ RNA_string_get(op->ptr, "palette", name);
+
+ if ((palette == NULL) || (name[0] == '\0')) {
+ return OPERATOR_CANCELLED;
+ }
+
+ palette_join = (Palette *)BKE_libblock_find_name(bmain, ID_PAL, name);
+ if (palette_join == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int totcol = BLI_listbase_count(&palette_join->colors);
+
+ if (totcol > 0) {
+ for (PaletteColor *color = palette_join->colors.first; color; color = color->next) {
+ PaletteColor *palcol = BKE_palette_color_add(palette);
+ if (palcol) {
+ copy_v3_v3(palcol->rgb, color->rgb);
+ palcol->value = color->value;
+ done = true;
+ }
+ }
+ }
+
+ if (done) {
+ /* Clear old color swatches. */
+ PaletteColor *color_next = NULL;
+ for (PaletteColor *color = palette_join->colors.first; color; color = color_next) {
+ color_next = color->next;
+ BKE_palette_color_remove(palette_join, color);
+ }
+
+ /* Notifier. */
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_join(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Join Palette Swatches";
+ ot->idname = "PALETTE_OT_join";
+ ot->description = "Join Palette Swatches";
+
+ /* api callbacks */
+ ot->exec = palette_join_exec;
+ ot->poll = palette_join_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_string(ot->srna, "palette", NULL, MAX_ID_NAME - 2, "Palette", "Name of the Palette");
+}
+
static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -456,6 +770,9 @@ static const ePaintMode brush_select_paint_modes[] = {
PAINT_MODE_WEIGHT,
PAINT_MODE_TEXTURE_3D,
PAINT_MODE_GPENCIL,
+ PAINT_MODE_VERTEX_GPENCIL,
+ PAINT_MODE_SCULPT_GPENCIL,
+ PAINT_MODE_WEIGHT_GPENCIL,
};
static int brush_select_exec(bContext *C, wmOperator *op)
@@ -965,6 +1282,11 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PALETTE_OT_color_add);
WM_operatortype_append(PALETTE_OT_color_delete);
+ WM_operatortype_append(PALETTE_OT_extract_from_image);
+ WM_operatortype_append(PALETTE_OT_sort);
+ WM_operatortype_append(PALETTE_OT_color_move);
+ WM_operatortype_append(PALETTE_OT_join);
+
/* paint curve */
WM_operatortype_append(PAINTCURVE_OT_new);
WM_operatortype_append(PAINTCURVE_OT_add_point);
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index e01986181bc..e17bf00106a 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -803,7 +803,7 @@ static void insert_gpencil_keys(bAnimContext *ac, short mode)
/* insert gp frames */
for (ale = anim_data.first; ale; ale = ale->next) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
- BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
+ BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
}
ANIM_animdata_update(ac, &anim_data);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 458c8690e3c..4322e4277ad 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -1759,8 +1759,8 @@ static int mouse_action_keys(bAnimContext *ac,
gpl->flag |= GP_LAYER_SELECT;
/* Update other layer status. */
- if (BKE_gpencil_layer_getactive(gpd) != gpl) {
- BKE_gpencil_layer_setactive(gpd, gpl);
+ if (BKE_gpencil_layer_active_get(gpd) != gpl) {
+ BKE_gpencil_layer_active_set(gpd, gpl);
BKE_gpencil_layer_autolock_set(gpd, false);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 1c26dc8f834..3e88a7a7b88 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -817,7 +817,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
bGPDlayer *gpl = te->directdata;
/* always make layer active */
- BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_active_set(gpd, gpl);
// XXX: name needs translation stuff
BLI_uniquename(
@@ -2252,6 +2252,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eGpencilModifierType_Armature:
data.icon = ICON_MOD_ARMATURE;
break;
+ case eGpencilModifierType_Vertexcolor:
+ data.icon = ICON_MOD_NORMALEDIT;
+ break;
/* Default */
default:
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 6d449e98c7e..8ddacfc84c2 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -561,7 +561,7 @@ static eOLDrawState tree_element_active_gplayer(bContext *C,
*/
if (set != OL_SETSEL_NONE) {
if (gpl) {
- BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_active_set(gpd, gpl);
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd);
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index a8514967748..8c884783913 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -1215,6 +1215,9 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C,
case CTX_MODE_WEIGHT_GPENCIL:
ARRAY_SET_ITEMS(contexts, ".greasepencil_weight");
break;
+ case CTX_MODE_VERTEX_GPENCIL:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_vertex");
+ break;
default:
break;
}
@@ -1232,6 +1235,9 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C,
case CTX_MODE_EDIT_GPENCIL:
ARRAY_SET_ITEMS(contexts, ".greasepencil_edit");
break;
+ case CTX_MODE_VERTEX_GPENCIL:
+ ARRAY_SET_ITEMS(contexts, ".greasepencil_vertex");
+ break;
default:
break;
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 6fbae1d8cb1..83539900f36 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -409,7 +409,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
/* Helper: Find the layer created as ruler. */
static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd)
{
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl->flag & GP_LAYER_IS_RULER) {
return gpl;
}
@@ -445,7 +445,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER;
}
- gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
BKE_gpencil_free_strokes(gpf);
for (ruler_item = gzgroup->gizmos.first; ruler_item;
@@ -477,9 +477,10 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
}
gps->flag = GP_STROKE_3DSPACE;
gps->thickness = 3;
- gps->gradient_f = 1.0f;
- gps->gradient_s[0] = 1.0f;
- gps->gradient_s[1] = 1.0f;
+ gps->hardeness = 1.0f;
+ gps->fill_opacity_fac = 1.0f;
+ copy_v2_fl(gps->aspect_ratio, 1.0f);
+ gps->uv_scale = 1.0f;
BLI_addtail(&gpf->strokes, gps);
changed = true;
@@ -498,7 +499,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
gpl = view3d_ruler_layer_get(scene->gpd);
if (gpl) {
bGPDframe *gpf;
- gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
if (gpf) {
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 7649bd45a1a..bd92193206f 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -2265,7 +2265,8 @@ static bool ed_object_select_pick(bContext *C,
if (ELEM(basact->object->mode,
OB_MODE_PAINT_GPENCIL,
OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL)) {
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL)) {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
}
else {
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 009164057ce..f93a3ec260b 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -887,7 +887,7 @@ static void posttrans_gpd_clean(bGPdata *gpd)
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
gpfn = gpf->next;
if (gpfn && gpf->framenum == gpfn->framenum) {
- BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_frame_delete(gpl, gpf);
}
}
}
@@ -2740,9 +2740,11 @@ void createTransData(bContext *C, TransInfo *t)
has_transform_context = false;
}
}
- else if ((ob) &&
- (ELEM(
- ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
+ else if ((ob) && (ELEM(ob->mode,
+ OB_MODE_PAINT_GPENCIL,
+ OB_MODE_SCULPT_GPENCIL,
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL))) {
/* In grease pencil all transformations must be canceled if not Object or Edit. */
has_transform_context = false;
}
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index c61961e46d1..17e69ff38b8 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -83,6 +83,8 @@ void createTransGPencil(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_scale_thickness = ((t->mode == TFM_GPENCIL_SHRINKFATTEN) ||
+ (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS));
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -108,7 +110,7 @@ void createTransGPencil(bContext *C, TransInfo *t)
*/
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf;
bGPDstroke *gps;
bGPDframe *init_gpf = gpl->actframe;
@@ -180,7 +182,7 @@ void createTransGPencil(bContext *C, TransInfo *t)
/* Second Pass: Build transdata array */
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
@@ -196,11 +198,11 @@ void createTransGPencil(bContext *C, TransInfo *t)
int f_end = 0;
if (use_multiframe_falloff) {
- BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
}
/* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
/* undo matrix */
invert_m4_m4(inverse_diff_mat, diff_mat);
@@ -312,9 +314,9 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
/* for other transform modes (e.g. shrink-fatten), need to additional data
- * but never for scale or mirror
+ * but never for mirror
*/
- if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
+ if ((t->mode != TFM_MIRROR) && (is_scale_thickness)) {
if (t->mode != TFM_GPENCIL_OPACITY) {
td->val = &pt->pressure;
td->ival = pt->pressure;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 3fe1b99adfb..bb4d50fcf54 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1149,12 +1149,15 @@ static void recalcData_sequencer(TransInfo *t)
static void recalcData_gpencil_strokes(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ bGPDstroke *gps_prev = NULL;
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
bGPDstroke *gps = td->extra;
- if (gps != NULL) {
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ if ((gps != NULL) && (gps != gps_prev)) {
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ gps_prev = gps;
}
}
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 02767156ef4..0548cc4e503 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -792,13 +792,13 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (is_gp_edit) {
float diff_mat[4][4];
const bool use_mat_local = true;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
/* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 5b5d1338637..cb4f4dfa46c 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -202,7 +202,8 @@ static int ed_undo_step_impl(
if (ELEM(obact->mode,
OB_MODE_PAINT_GPENCIL,
OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL)) {
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL)) {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
}
else {
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 87743911add..709674e6b43 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
intern/MOD_gpencilthick.c
intern/MOD_gpenciltime.c
intern/MOD_gpenciltint.c
+ intern/MOD_gpencilvertexcolor.c
MOD_gpencil_modifiertypes.h
)
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index f5c064c1c07..b8e8e8fc87f 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -43,6 +43,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Offset;
extern GpencilModifierTypeInfo modifierType_Gpencil_Armature;
extern GpencilModifierTypeInfo modifierType_Gpencil_Time;
extern GpencilModifierTypeInfo modifierType_Gpencil_Multiply;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Vertexcolor;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 6f37cedba49..1462b6f72c9 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -72,6 +72,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(Armature);
INIT_GP_TYPE(Time);
INIT_GP_TYPE(Multiply);
+ INIT_GP_TYPE(Vertexcolor);
#undef INIT_GP_TYPE
}
@@ -186,44 +187,3 @@ float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
return weight;
}
-
-/* set material when apply modifiers (used in tint and color modifier) */
-void gpencil_apply_modifier_material(
- Main *bmain, Object *ob, Material *mat, GHash *gh_color, bGPDstroke *gps, bool crt_material)
-{
- MaterialGPencilStyle *gp_style = mat->gp_style;
-
- /* look for color */
- if (crt_material) {
- Material *newmat = BLI_ghash_lookup(gh_color, mat->id.name);
- if (newmat == NULL) {
- BKE_object_material_slot_add(bmain, ob);
- newmat = BKE_material_copy(bmain, mat);
- newmat->preview = NULL;
-
- BKE_object_material_assign(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
-
- copy_v4_v4(newmat->gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
- copy_v4_v4(newmat->gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
-
- BLI_ghash_insert(gh_color, mat->id.name, newmat);
- DEG_id_tag_update(&newmat->id, ID_RECALC_COPY_ON_WRITE);
- }
- /* Reassign color index. */
- gps->mat_nr = BKE_gpencil_object_material_get_index(ob, newmat);
- }
- else {
- /* reuse existing color (but update only first time) */
- if (BLI_ghash_lookup(gh_color, mat->id.name) == NULL) {
- copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba);
- copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba);
- BLI_ghash_insert(gh_color, mat->id.name, mat);
- }
- /* update previews (icon and thumbnail) */
- if (mat->preview != NULL) {
- mat->preview->flag[ICON_SIZE_ICON] |= PRV_CHANGED;
- mat->preview->flag[ICON_SIZE_PREVIEW] |= PRV_CHANGED;
- }
- DEG_id_tag_update(&mat->id, ID_RECALC_COPY_ON_WRITE);
- }
-}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 2b1f8dbc71a..fc4522bc028 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -47,11 +47,4 @@ bool is_stroke_affected_by_modifier(struct Object *ob,
float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr);
-void gpencil_apply_modifier_material(struct Main *bmain,
- struct Object *ob,
- struct Material *mat,
- struct GHash *gh_color,
- struct bGPDstroke *gps,
- bool crt_material);
-
#endif /* __MOD_GPENCIL_UTIL_H__ */
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index eceb45780cf..a8aad763422 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -23,6 +23,7 @@
#include <stdio.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -116,6 +117,8 @@ static void deformStroke(GpencilModifierData *md,
}
gpencil_deform_verts(mmd, ob, gps);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
@@ -131,8 +134,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
return;
}
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* apply armature effects on this frame
* NOTE: this assumes that we don't want armature animation on non-keyframed frames
*/
@@ -140,7 +143,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
/* compute armature effects on this frame */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
deformStroke(md_eval, depsgraph, object_eval, gpl, gpf, gps);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index 11ba639fa83..1fc8c19b542 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -27,6 +27,10 @@
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
+#include "BLI_rand.h"
+
#include "BLI_blenlib.h"
#include "BLI_rand.h"
#include "BLI_math.h"
@@ -54,26 +58,24 @@
#include "MOD_gpencil_util.h"
#include "MOD_gpencil_modifiertypes.h"
+typedef struct tmpStrokes {
+ struct tmpStrokes *next, *prev;
+ bGPDframe *gpf;
+ bGPDstroke *gps;
+} tmpStrokes;
+
static void initData(GpencilModifierData *md)
{
ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md;
gpmd->count = 2;
- gpmd->offset[0] = 1.0f;
- gpmd->offset[1] = 0.0f;
- gpmd->offset[2] = 0.0f;
- gpmd->shift[0] = 0.0f;
+ gpmd->shift[0] = 1.0f;
gpmd->shift[1] = 0.0f;
gpmd->shift[2] = 0.0f;
- gpmd->scale[0] = 1.0f;
- gpmd->scale[1] = 1.0f;
- gpmd->scale[2] = 1.0f;
- gpmd->rnd_rot = 0.5f;
- gpmd->rnd_size = 0.5f;
+ zero_v3(gpmd->offset);
+ zero_v3(gpmd->rnd_scale);
gpmd->object = NULL;
-
- /* fill random values */
- BLI_array_frand(gpmd->rnd, 20, 1);
- gpmd->rnd[0] = 1;
+ gpmd->flag |= GP_ARRAY_USE_RELATIVE;
+ gpmd->seed = 1;
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
@@ -90,46 +92,24 @@ static void BKE_gpencil_instance_modifier_instance_tfm(Object *ob,
float r_offset[4][4])
{
float offset[3], rot[3], scale[3];
- int ri = mmd->rnd[0];
- float factor;
-
- offset[0] = mmd->offset[0] * elem_idx;
- offset[1] = mmd->offset[1] * elem_idx;
- offset[2] = mmd->offset[2] * elem_idx;
-
- /* rotation */
- if (mmd->flag & GP_ARRAY_RANDOM_ROT) {
- factor = mmd->rnd_rot * mmd->rnd[ri];
- mul_v3_v3fl(rot, mmd->rot, factor);
- add_v3_v3(rot, mmd->rot);
- }
- else {
- copy_v3_v3(rot, mmd->rot);
- }
+ ARRAY_SET_ITEMS(scale, 1.0f, 1.0f, 1.0f);
+ zero_v3(rot);
- /* scale */
- if (mmd->flag & GP_ARRAY_RANDOM_SIZE) {
- factor = mmd->rnd_size * mmd->rnd[ri];
- mul_v3_v3fl(scale, mmd->scale, factor);
- add_v3_v3(scale, mmd->scale);
+ if (mmd->flag & GP_ARRAY_USE_OFFSET) {
+ offset[0] = mmd->offset[0] * elem_idx;
+ offset[1] = mmd->offset[1] * elem_idx;
+ offset[2] = mmd->offset[2] * elem_idx;
}
else {
- copy_v3_v3(scale, mmd->scale);
+ zero_v3(offset);
}
- /* advance random index */
- mmd->rnd[0]++;
- if (mmd->rnd[0] > 19) {
- mmd->rnd[0] = 1;
- }
-
- /* calculate matrix */
+ /* Calculate matrix */
loc_eul_size_to_mat4(r_mat, offset, rot, scale);
-
copy_m4_m4(r_offset, r_mat);
/* offset object */
- if (mmd->object) {
+ if ((mmd->flag & GP_ARRAY_USE_OB_OFFSET) && (mmd->object)) {
float mat_offset[4][4];
float obinv[4][4];
@@ -147,140 +127,158 @@ static void BKE_gpencil_instance_modifier_instance_tfm(Object *ob,
/* array modifier - generate geometry callback (for viewport/rendering) */
static void generate_geometry(GpencilModifierData *md,
- Depsgraph *UNUSED(depsgraph),
- Object *ob,
- bGPDlayer *gpl,
- bGPDframe *gpf)
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
{
ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
ListBase stroke_cache = {NULL, NULL};
- bGPDstroke *gps;
- int idx;
-
- /* Check which strokes we can use once, and store those results in an array
- * for quicker checking of what's valid (since string comparisons are expensive)
- */
- const int num_strokes = BLI_listbase_count(&gpf->strokes);
- int num_valid = 0;
+ /* Load the strokes to be duplicated. */
+ bGPdata *gpd = (bGPdata *)ob->data;
+ bool found = false;
+
+ /* Get bounbox for relative offset. */
+ float size[3] = {0.0f, 0.0f, 0.0f};
+ if (mmd->flag & GP_ARRAY_USE_RELATIVE) {
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
+ BKE_boundbox_init_from_minmax(bb, min, max);
+ BKE_boundbox_calc_size_aabb(bb, size);
+ mul_v3_fl(size, 2.0f);
+ /* Need a minimum size (for flat drawings). */
+ CLAMP3_MIN(size, 0.01f);
+ }
- bool *valid_strokes = MEM_callocN(sizeof(bool) * num_strokes, __func__);
+ int seed = mmd->seed;
+ /* Make sure different modifiers get different seeds. */
+ seed += BLI_hash_string(ob->id.name + 2);
+ seed += BLI_hash_string(md->name);
- for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) {
- /* Record whether this stroke can be used
- * ATTENTION: The logic here is the inverse of what's used everywhere else!
- */
- if (is_stroke_affected_by_modifier(ob,
- mmd->layername,
- mmd->materialname,
- mmd->pass_index,
- mmd->layer_pass,
- 1,
- gpl,
- gps,
- mmd->flag & GP_ARRAY_INVERT_LAYER,
- mmd->flag & GP_ARRAY_INVERT_PASS,
- mmd->flag & GP_ARRAY_INVERT_LAYERPASS,
- mmd->flag & GP_ARRAY_INVERT_MATERIAL)) {
- valid_strokes[idx] = true;
- num_valid++;
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+ if (gpf == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->materialname,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_ARRAY_INVERT_LAYER,
+ mmd->flag & GP_ARRAY_INVERT_PASS,
+ mmd->flag & GP_ARRAY_INVERT_LAYERPASS,
+ mmd->flag & GP_ARRAY_INVERT_MATERIAL)) {
+ tmpStrokes *tmp = MEM_callocN(sizeof(tmpStrokes), __func__);
+ tmp->gpf = gpf;
+ tmp->gps = gps;
+ BLI_addtail(&stroke_cache, tmp);
+
+ found = true;
+ }
}
}
- /* Early exit if no strokes can be copied */
- if (num_valid == 0) {
- if (G.debug & G_DEBUG) {
- printf("GP Array Mod - No strokes to be included\n");
- }
+ if (found) {
+ /* Generate new instances of all existing strokes,
+ * keeping each instance together so they maintain
+ * the correct ordering relative to each other
+ */
+ float current_offset[4][4];
+ unit_m4(current_offset);
- MEM_SAFE_FREE(valid_strokes);
- return;
- }
+ float rand_offset = BLI_hash_int_01(seed);
- /* Generate new instances of all existing strokes,
- * keeping each instance together so they maintain
- * the correct ordering relative to each other
- */
- float current_offset[4][4];
- unit_m4(current_offset);
+ for (int x = 0; x < mmd->count; x++) {
+ /* original strokes are at index = 0 */
+ if (x == 0) {
+ continue;
+ }
- for (int x = 0; x < mmd->count; x++) {
- /* original strokes are at index = 0 */
- if (x == 0) {
- continue;
- }
+ /* Compute transforms for this instance */
+ float mat[4][4];
+ float mat_offset[4][4];
+ BKE_gpencil_instance_modifier_instance_tfm(ob, mmd, x, mat, mat_offset);
- /* Compute transforms for this instance */
- float mat[4][4];
- float mat_offset[4][4];
- BKE_gpencil_instance_modifier_instance_tfm(ob, mmd, x, mat, mat_offset);
+ if ((mmd->flag & GP_ARRAY_USE_OB_OFFSET) && (mmd->object)) {
+ /* recalculate cumulative offset here */
+ mul_m4_m4m4(current_offset, current_offset, mat_offset);
+ }
+ else {
+ copy_m4_m4(current_offset, mat);
+ }
- if (mmd->object) {
- /* recalculate cumulative offset here */
- mul_m4_m4m4(current_offset, current_offset, mat_offset);
- }
- else {
- copy_m4_m4(current_offset, mat);
- }
- /* apply shift */
- madd_v3_v3fl(current_offset[3], mmd->shift, x);
-
- /* Duplicate original strokes to create this instance */
- for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) {
- /* check if stroke can be duplicated */
- if (valid_strokes[idx]) {
- /* Calculate original stroke center (only first loop). */
- float r_min[3], r_max[3], center[3];
- if (x == 1) {
- INIT_MINMAX(r_min, r_max);
- BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
- add_v3_v3v3(center, r_min, r_max);
- mul_v3_fl(center, 0.5f);
- sub_v3_v3v3(center, center, ob->obmat[3]);
- }
+ /* Apply relative offset. */
+ if (mmd->flag & GP_ARRAY_USE_RELATIVE) {
+ float relative[3];
+ mul_v3_v3v3(relative, mmd->shift, size);
+ madd_v3_v3fl(current_offset[3], relative, x);
+ }
+ float rand[3][3];
+ for (int j = 0; j < 3; j++) {
+ uint primes[3] = {2, 3, 7};
+ double offset[3] = {0.0, 0.0, 0.0};
+ double r[3];
+ /* To ensure a nice distribution, we use halton sequence and offset using the seed. */
+ BLI_halton_3d(primes, offset, x, r);
+
+ for (int i = 0; i < 3; i++) {
+ rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f);
+ rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f);
+ }
+ }
+ /* Calculate Random matrix. */
+ float mat_rnd[4][4];
+ float loc[3], rot[3];
+ float scale[3] = {1.0f, 1.0f, 1.0f};
+ mul_v3_v3v3(loc, mmd->rnd_offset, rand[0]);
+ mul_v3_v3v3(rot, mmd->rnd_rot, rand[1]);
+ madd_v3_v3v3(scale, mmd->rnd_scale, rand[2]);
+
+ loc_eul_size_to_mat4(mat_rnd, loc, rot, scale);
+
+ /* Duplicate original strokes to create this instance. */
+ LISTBASE_FOREACH_BACKWARD (tmpStrokes *, iter, &stroke_cache) {
/* Duplicate stroke */
- bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps);
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(iter->gps, true);
/* Move points */
- for (int i = 0; i < gps->totpoints; i++) {
+ for (int i = 0; i < iter->gps->totpoints; i++) {
bGPDspoint *pt = &gps_dst->points[i];
+ /* Apply randomness matrix. */
+ mul_m4_v3(mat_rnd, &pt->x);
+
/* Apply object local transform (Rot/Scale). */
- if (mmd->object) {
+ if ((mmd->flag & GP_ARRAY_USE_OB_OFFSET) && (mmd->object)) {
mul_m4_v3(mat, &pt->x);
}
- /* Translate to object origin. */
- float fpt[3];
- sub_v3_v3v3(fpt, &pt->x, center);
/* Global Rotate and scale. */
- mul_mat3_m4_v3(current_offset, fpt);
+ mul_mat3_m4_v3(current_offset, &pt->x);
/* Global translate. */
- add_v3_v3(fpt, center);
- add_v3_v3v3(&pt->x, fpt, current_offset[3]);
+ add_v3_v3(&pt->x, current_offset[3]);
}
- /* if replace material, use new one */
+ /* If replace material, use new one. */
if ((mmd->mat_rpl > 0) && (mmd->mat_rpl <= ob->totcol)) {
gps_dst->mat_nr = mmd->mat_rpl - 1;
}
- /* Add new stroke to cache, to be added to the frame once
- * all duplicates have been made
- */
- BLI_addtail(&stroke_cache, gps_dst);
+ /* Add new stroke. */
+ BLI_addhead(&iter->gpf->strokes, gps_dst);
+ /* Calc bounding box. */
+ BKE_gpencil_stroke_boundingbox_calc(gps_dst);
}
}
- }
- /* merge newly created stroke instances back into the main stroke list */
- if (mmd->flag & GP_ARRAY_KEEP_ONTOP) {
- BLI_movelisttolist_reverse(&gpf->strokes, &stroke_cache);
- }
- else {
- BLI_movelisttolist(&gpf->strokes, &stroke_cache);
+ /* Free temp data. */
+ LISTBASE_FOREACH_MUTABLE (tmpStrokes *, tmp, &stroke_cache) {
+ BLI_freelinkN(&stroke_cache, tmp);
+ }
}
-
- /* free temp data */
- MEM_SAFE_FREE(valid_strokes);
}
static void bakeModifier(Main *UNUSED(bmain),
@@ -288,23 +286,17 @@ static void bakeModifier(Main *UNUSED(bmain),
GpencilModifierData *md,
Object *ob)
{
-
- bGPdata *gpd = ob->data;
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- generate_geometry(md, depsgraph, ob, gpl, gpf);
- }
- }
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ generate_geometry(md, depsgraph, scene, ob);
}
/* -------------------------------- */
/* Generic "generateStrokes" callback */
-static void generateStrokes(
- GpencilModifierData *md, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
{
- generate_geometry(md, depsgraph, ob, gpl, gpf);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ generate_geometry(md, depsgraph, scene, ob);
}
static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index e3e7168330d..7e89d8e2d6f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -174,10 +174,8 @@ static void reduce_stroke_points(bGPDstroke *gps,
gps->dvert = new_dvert;
gps->totpoints = num_points;
- /* mark stroke as needing to have its geometry caches rebuilt */
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
- MEM_SAFE_FREE(gps->triangles);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
/* --------------------------------------------- */
@@ -400,19 +398,15 @@ static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa
}
/* --------------------------------------------- */
-
-/* Entry-point for Build Modifier */
-static void generateStrokes(GpencilModifierData *md,
- Depsgraph *depsgraph,
- Object *UNUSED(ob),
- bGPDlayer *gpl,
- bGPDframe *gpf)
+static void generate_geometry(GpencilModifierData *md,
+ Depsgraph *depsgraph,
+ bGPDlayer *gpl,
+ bGPDframe *gpf)
{
BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
const float ctime = DEG_get_ctime(depsgraph);
- // printf("GP Build Modifier - %f\n", ctime);
/* Early exit if it's an empty frame */
if (gpf->strokes.first == NULL) {
@@ -459,7 +453,7 @@ static void generateStrokes(GpencilModifierData *md,
* By default, the upper bound is given by the "maximum length" setting
*/
float start_frame = gpf->framenum + mmd->start_delay;
- float end_frame = gpf->framenum + mmd->length;
+ float end_frame = start_frame + mmd->length;
if (gpf->next) {
/* Use the next frame or upper bound as end frame, whichever is lower/closer */
@@ -506,7 +500,6 @@ static void generateStrokes(GpencilModifierData *md,
/* Determine how far along we are between the keyframes */
float fac = (ctime - start_frame) / (end_frame - start_frame);
- // printf(" Progress on %d = %f (%f - %f)\n", gpf->framenum, fac, start_frame, end_frame);
/* Time management mode */
switch (mmd->mode) {
@@ -526,6 +519,21 @@ static void generateStrokes(GpencilModifierData *md,
}
}
+/* Entry-point for Build Modifier */
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+ if (gpf == NULL) {
+ continue;
+ }
+ generate_geometry(md, depsgraph, gpl, gpf);
+ }
+}
+
/* ******************************************** */
GpencilModifierTypeInfo modifierType_Gpencil_Build = {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index d9869c92e06..3a930b40c8b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -26,7 +26,6 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
@@ -35,6 +34,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_gpencil_modifier_types.h"
+#include "BKE_colortools.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_main.h"
@@ -52,13 +52,28 @@ static void initData(GpencilModifierData *md)
ARRAY_SET_ITEMS(gpmd->hsv, 0.5f, 1.0f, 1.0f);
gpmd->layername[0] = '\0';
gpmd->materialname[0] = '\0';
- gpmd->flag |= GP_COLOR_CREATE_COLORS;
gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+
+ gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_intensity) {
+ CurveMapping *curve = gpmd->curve_intensity;
+ BKE_curvemapping_initialize(curve);
+ }
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
+ ColorGpencilModifierData *gmd = (ColorGpencilModifierData *)md;
+ ColorGpencilModifierData *tgmd = (ColorGpencilModifierData *)target;
+
+ if (tgmd->curve_intensity != NULL) {
+ BKE_curvemapping_free(tgmd->curve_intensity);
+ tgmd->curve_intensity = NULL;
+ }
+
BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
/* color correction strokes */
@@ -72,6 +87,7 @@ static void deformStroke(GpencilModifierData *md,
ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
float hsv[3], factor[3];
+ const bool use_curve = (mmd->flag & GP_COLOR_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
@@ -89,60 +105,76 @@ static void deformStroke(GpencilModifierData *md,
}
copy_v3_v3(factor, mmd->hsv);
- /* keep initial values unchanged, subtracting the default values. */
- factor[0] -= 0.5f;
- factor[1] -= 1.0f;
- factor[2] -= 1.0f;
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
- rgb_to_hsv_v(gps->runtime.tmp_stroke_rgba, hsv);
- add_v3_v3(hsv, factor);
- CLAMP3(hsv, 0.0f, 1.0f);
- hsv_to_rgb_v(hsv, gps->runtime.tmp_stroke_rgba);
+ /* Apply to Vertex Color. */
+ /* Fill */
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ /* If not using Vertex Color, use the material color. */
+ if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) &&
+ (gp_style->fill_rgba[3] > 0.0f)) {
+ copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba);
+ gps->vert_color_fill[3] = 1.0f;
+ }
+
+ rgb_to_hsv_v(gps->vert_color_fill, hsv);
+ hsv[0] = fractf(hsv[0] + factor[0] + 0.5f);
+ hsv[1] = clamp_f(hsv[1] * factor[1], 0.0f, 1.0f);
+ hsv[2] = hsv[2] * factor[2];
+ hsv_to_rgb_v(hsv, gps->vert_color_fill);
}
- if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
- rgb_to_hsv_v(gps->runtime.tmp_fill_rgba, hsv);
- add_v3_v3(hsv, factor);
- CLAMP3(hsv, 0.0f, 1.0f);
- hsv_to_rgb_v(hsv, gps->runtime.tmp_fill_rgba);
+ /* Stroke */
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ /* If not using Vertex Color, use the material color. */
+ if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) {
+ copy_v4_v4(pt->vert_color, gp_style->stroke_rgba);
+ pt->vert_color[3] = 1.0f;
+ }
+
+ /* Custom curve to modulate value. */
+ float factor_value[3];
+ copy_v3_v3(factor_value, factor);
+ if (use_curve) {
+ float value = (float)i / (gps->totpoints - 1);
+ float mixfac = BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
+ mul_v3_fl(factor_value, mixfac);
+ }
+
+ rgb_to_hsv_v(pt->vert_color, hsv);
+ hsv[0] = fractf(hsv[0] + factor_value[0] + 0.5f);
+ hsv[1] = clamp_f(hsv[1] * factor_value[1], 0.0f, 1.0f);
+ hsv[2] = hsv[2] * factor_value[2];
+ hsv_to_rgb_v(hsv, pt->vert_color);
+ }
}
}
-static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
{
- ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
bGPdata *gpd = ob->data;
- GHash *gh_color = BLI_ghash_str_new("GP_Color modifier");
- 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) {
-
- Material *mat = BKE_gpencil_material(ob, gps->mat_nr + 1);
- if (mat == NULL) {
- continue;
- }
- MaterialGPencilStyle *gp_style = mat->gp_style;
- /* skip stroke if it doesn't have color info */
- if (ELEM(NULL, gp_style)) {
- continue;
- }
-
- copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
-
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
-
- gpencil_apply_modifier_material(
- bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_COLOR_CREATE_COLORS));
}
}
}
- /* free hash buffers */
- if (gh_color) {
- BLI_ghash_free(gh_color, NULL, NULL);
- gh_color = NULL;
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ BKE_curvemapping_free(gpmd->curve_intensity);
}
}
@@ -161,7 +193,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = {
/* remapTime */ NULL,
/* initData */ initData,
- /* freeData */ NULL,
+ /* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index ae51bad3ca3..41380ec4c68 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -23,6 +23,7 @@
#include <stdio.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -263,6 +264,8 @@ static void deformStroke(GpencilModifierData *md,
}
gp_hook_co_apply(&tData, weight, pt);
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
/* FIXME: Ideally we be doing this on a copy of the main depsgraph
@@ -279,8 +282,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
return;
}
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* apply hook effects on this frame
* NOTE: this assumes that we don't want hook animation on non-keyframed frames
*/
@@ -288,7 +291,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
/* compute hook effects on this frame */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
index dba554fec36..d87f3a8a199 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -23,6 +23,7 @@
#include <stdio.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_meshdata_types.h"
@@ -108,6 +109,8 @@ static void deformStroke(GpencilModifierData *md,
}
calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight);
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
/* FIXME: Ideally we be doing this on a copy of the main depsgraph
@@ -125,8 +128,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
return;
}
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* apply lattice effects on this frame
* NOTE: this assumes that we don't want lattice animation on non-keyframed frames
*/
@@ -137,7 +140,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
BKE_gpencil_lattice_init(ob);
/* compute lattice effects on this frame */
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 42d45512dc5..0f9b1034352 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -113,12 +113,7 @@ static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstro
}
}
-/* Generic "generateStrokes" callback */
-static void generateStrokes(GpencilModifierData *md,
- Depsgraph *UNUSED(depsgraph),
- Object *ob,
- bGPDlayer *gpl,
- bGPDframe *gpf)
+static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
{
MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
bGPDstroke *gps, *gps_new = NULL;
@@ -145,7 +140,7 @@ static void generateStrokes(GpencilModifierData *md,
mmd->flag & GP_MIRROR_INVERT_PASS,
mmd->flag & GP_MIRROR_INVERT_LAYERPASS,
mmd->flag & GP_MIRROR_INVERT_MATERIAL)) {
- gps_new = BKE_gpencil_stroke_duplicate(gps);
+ gps_new = BKE_gpencil_stroke_duplicate(gps, true);
update_position(ob, mmd, gps_new, xi);
BLI_addtail(&gpf->strokes, gps_new);
}
@@ -154,20 +149,35 @@ static void generateStrokes(GpencilModifierData *md,
}
}
+/* Generic "generateStrokes" callback */
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+ if (gpf == NULL) {
+ continue;
+ }
+ generate_geometry(md, ob, gpl, gpf);
+ }
+}
+
static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
bGPdata *gpd = ob->data;
int oldframe = (int)DEG_get_ctime(depsgraph);
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* apply mirror effects on this frame */
CFRA = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph, bmain);
/* compute mirror effects on this frame */
- generateStrokes(md, depsgraph, ob, gpl, gpf);
+ generate_geometry(md, ob, gpl, gpf);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
index 919dbf91862..16b0c4a5e38 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
@@ -66,7 +66,10 @@ static void initData(GpencilModifierData *md)
MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
mmd->duplications = 3;
mmd->distance = 0.1f;
- mmd->split_angle = 1.0f;
+ mmd->split_angle = DEG2RADF(1.0f);
+ mmd->fading_center = 0.5f;
+ mmd->fading_thickness = 0.5f;
+ mmd->fading_opacity = 0.5f;
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
@@ -74,60 +77,39 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
BKE_gpencil_modifier_copyData_generic(md, target);
}
-static void splitStroke(bGPDframe *gpf, bGPDstroke *gps, float split_angle)
-{
- bGPDspoint *pt = gps->points;
- bGPDstroke *new_gps = gps;
- int i;
- volatile float angle;
-
- if (split_angle <= FLT_EPSILON) {
- return;
- }
-
- for (i = 1; i < new_gps->totpoints - 1; i++) {
- angle = angle_v3v3v3(&pt[i - 1].x, &pt[i].x, &pt[i + 1].x);
- if (angle < split_angle) {
- if (BKE_gpencil_split_stroke(gpf, new_gps, i, &new_gps)) {
- pt = new_gps->points;
- i = 0;
- continue; /* then i == 1 again */
- }
- }
- }
-}
-
static void minter_v3_v3v3v3_ref(
- float *result, float *left, float *middle, float *right, float *stroke_normal)
+ float *result, float *prev, float *curr, float *next, float *stroke_normal)
{
- float left_arm[3], right_arm[3], inter1[3], inter2[3];
+ float vec[3], inter1[3], inter2[3];
+ ARRAY_SET_ITEMS(inter1, 0.0f, 0.0f, 0.0f);
+ ARRAY_SET_ITEMS(inter2, 0.0f, 0.0f, 0.0f);
+
float minter[3];
- if (left) {
- sub_v3_v3v3(left_arm, middle, left);
- cross_v3_v3v3(inter1, stroke_normal, left_arm);
+ if (prev) {
+ sub_v3_v3v3(vec, curr, prev);
+ cross_v3_v3v3(inter1, stroke_normal, vec);
}
- if (right) {
- sub_v3_v3v3(right_arm, right, middle);
- cross_v3_v3v3(inter2, stroke_normal, right_arm);
+ if (next) {
+ sub_v3_v3v3(vec, next, curr);
+ cross_v3_v3v3(inter2, stroke_normal, vec);
}
- if (!left) {
+ if (!prev) {
normalize_v3(inter2);
copy_v3_v3(result, inter2);
return;
}
-
- if (!right) {
+ if (!next) {
normalize_v3(inter1);
copy_v3_v3(result, inter1);
return;
}
-
interp_v3_v3v3(minter, inter1, inter2, 0.5);
normalize_v3(minter);
copy_v3_v3(result, minter);
}
-static void duplicateStroke(bGPDstroke *gps,
+static void duplicateStroke(Object *ob,
+ bGPDstroke *gps,
int count,
float dist,
float offset,
@@ -138,14 +120,15 @@ static void duplicateStroke(bGPDstroke *gps,
float fading_opacity)
{
int i;
- bGPDstroke *new_gps;
+ bGPDstroke *new_gps = NULL;
float stroke_normal[3];
- float minter[3];
bGPDspoint *pt;
- float offset_factor;
float thickness_factor;
float opacity_factor;
+ /* Apply object scale to offset distance. */
+ offset *= mat4_to_scale(ob->obmat);
+
BKE_gpencil_stroke_normal(gps, stroke_normal);
if (len_v3(stroke_normal) < FLT_EPSILON) {
add_v3_fl(stroke_normal, 1);
@@ -160,6 +143,7 @@ static void duplicateStroke(bGPDstroke *gps,
pt = gps->points;
for (int j = 0; j < gps->totpoints; j++) {
+ float minter[3];
if (j == 0) {
minter_v3_v3v3v3_ref(minter, NULL, &pt[j].x, &pt[j + 1].x, stroke_normal);
}
@@ -174,11 +158,11 @@ static void duplicateStroke(bGPDstroke *gps,
sub_v3_v3v3(&t2_array[j * 3], &pt[j].x, minter);
}
- /* This ensures the original stroke is the last one to be processed. */
+ /* This ensures the original stroke is the last one
+ * to be processed, since we duplicate its data. */
for (i = count - 1; i >= 0; i--) {
if (i != 0) {
- new_gps = BKE_gpencil_stroke_duplicate(gps);
- new_gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ new_gps = BKE_gpencil_stroke_duplicate(gps, true);
BLI_addtail(results, new_gps);
}
else {
@@ -187,34 +171,26 @@ static void duplicateStroke(bGPDstroke *gps,
pt = new_gps->points;
- if (count == 1) {
- offset_factor = 0;
- }
- else {
- offset_factor = (float)i / (float)(count - 1);
- }
+ float offset_fac = (count == 1) ? 0.5f : (i / (float)(count - 1));
if (fading) {
- thickness_factor = (offset_factor > fading_center) ?
- (interpf(1 - fading_thickness, 1.0f, offset_factor - fading_center)) :
- (interpf(
- 1.0f, 1 - fading_thickness, offset_factor - fading_center + 1));
- opacity_factor = (offset_factor > fading_center) ?
- (interpf(1 - fading_opacity, 1.0f, offset_factor - fading_center)) :
- (interpf(1.0f, 1 - fading_opacity, offset_factor - fading_center + 1));
+ thickness_factor = interpf(1.0f - fading_thickness, 1.0f, fabsf(offset_fac - fading_center));
+ opacity_factor = interpf(1.0f - fading_opacity, 1.0f, fabsf(offset_fac - fading_center));
}
for (int j = 0; j < new_gps->totpoints; j++) {
- interp_v3_v3v3(&pt[j].x,
- &t1_array[j * 3],
- &t2_array[j * 3],
- interpf(1 + offset, offset, offset_factor));
+ float fac = interpf(1 + offset, offset, offset_fac);
+ interp_v3_v3v3(&pt[j].x, &t1_array[j * 3], &t2_array[j * 3], fac);
if (fading) {
pt[j].pressure = gps->points[j].pressure * thickness_factor;
pt[j].strength = gps->points[j].strength * opacity_factor;
}
}
}
+ /* Calc geometry data. */
+ if (new_gps != NULL) {
+ BKE_gpencil_stroke_geometry_update(new_gps);
+ }
MEM_freeN(t1_array);
MEM_freeN(t2_array);
}
@@ -224,11 +200,10 @@ static void bakeModifier(Main *UNUSED(bmain),
GpencilModifierData *md,
Object *ob)
{
-
bGPdata *gpd = ob->data;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
ListBase duplicates = {0};
MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
bGPDstroke *gps;
@@ -247,11 +222,9 @@ static void bakeModifier(Main *UNUSED(bmain),
mmd->flag & GP_MIRROR_INVERT_MATERIAL)) {
continue;
}
- if (mmd->flags & GP_MULTIPLY_ENABLE_ANGLE_SPLITTING) {
- splitStroke(gpf, gps, mmd->split_angle);
- }
if (mmd->duplications > 0) {
- duplicateStroke(gps,
+ duplicateStroke(ob,
+ gps,
mmd->duplications,
mmd->distance,
mmd->offset,
@@ -262,23 +235,15 @@ static void bakeModifier(Main *UNUSED(bmain),
mmd->fading_opacity);
}
}
- if (duplicates.first) {
- ((bGPDstroke *)gpf->strokes.last)->next = duplicates.first;
- ((bGPDstroke *)duplicates.first)->prev = gpf->strokes.last;
- gpf->strokes.last = duplicates.first;
+ if (!BLI_listbase_is_empty(&duplicates)) {
+ BLI_movelisttolist(&gpf->strokes, &duplicates);
}
}
}
}
/* -------------------------------- */
-
-/* Generic "generateStrokes" callback */
-static void generateStrokes(GpencilModifierData *md,
- Depsgraph *UNUSED(depsgraph),
- Object *ob,
- bGPDlayer *gpl,
- bGPDframe *gpf)
+static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
{
MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
bGPDstroke *gps;
@@ -298,11 +263,9 @@ static void generateStrokes(GpencilModifierData *md,
mmd->flag & GP_MIRROR_INVERT_MATERIAL)) {
continue;
}
- if (mmd->flags & GP_MULTIPLY_ENABLE_ANGLE_SPLITTING) {
- splitStroke(gpf, gps, mmd->split_angle);
- }
if (mmd->duplications > 0) {
- duplicateStroke(gps,
+ duplicateStroke(ob,
+ gps,
mmd->duplications,
mmd->distance,
mmd->offset,
@@ -313,10 +276,23 @@ static void generateStrokes(GpencilModifierData *md,
mmd->fading_opacity);
}
}
- if (duplicates.first) {
- ((bGPDstroke *)gpf->strokes.last)->next = duplicates.first;
- ((bGPDstroke *)duplicates.first)->prev = gpf->strokes.last;
- gpf->strokes.last = duplicates.first;
+ if (!BLI_listbase_is_empty(&duplicates)) {
+ BLI_movelisttolist(&gpf->strokes, &duplicates);
+ }
+}
+
+/* Generic "generateStrokes" callback */
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
+{
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+ if (gpf == NULL) {
+ continue;
+ }
+ generate_geometry(md, ob, gpl, gpf);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index 157bd536609..9b3d37bf11f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -23,18 +23,23 @@
#include <stdio.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_rand.h"
+#include "MEM_guardedalloc.h"
+
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_gpencil_modifier_types.h"
+#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
@@ -57,13 +62,38 @@ static void initData(GpencilModifierData *md)
gpmd->layername[0] = '\0';
gpmd->materialname[0] = '\0';
gpmd->vgname[0] = '\0';
- gpmd->step = 1;
- gpmd->seed = 0;
+ gpmd->step = 4;
+ gpmd->seed = 1;
+ gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_intensity) {
+ CurveMapping *curve = gpmd->curve_intensity;
+ BKE_curvemap_reset(curve->cm, &curve->clipr, CURVE_PRESET_BELL, CURVEMAP_SLOPE_POSITIVE);
+ BKE_curvemapping_initialize(curve);
+ }
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ BKE_curvemapping_free(gpmd->curve_intensity);
+ }
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
+ NoiseGpencilModifierData *gmd = (NoiseGpencilModifierData *)md;
+ NoiseGpencilModifierData *tgmd = (NoiseGpencilModifierData *)target;
+
+ if (tgmd->curve_intensity != NULL) {
+ BKE_curvemapping_free(tgmd->curve_intensity);
+ tgmd->curve_intensity = NULL;
+ }
+
BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
static bool dependsOnTime(GpencilModifierData *md)
@@ -72,24 +102,36 @@ static bool dependsOnTime(GpencilModifierData *md)
return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
}
+static float *noise_table(int len, int seed)
+{
+ float *table = MEM_callocN(sizeof(float) * len, __func__);
+ for (int i = 0; i < len; i++) {
+ table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + 1));
+ }
+ return table;
+}
+
+BLI_INLINE float table_sample(float *table, float x)
+{
+ return interpf(table[(int)ceilf(x)], table[(int)floor(x)], fractf(x));
+}
+
/* aply noise effect based on stroke direction */
static void deformStroke(GpencilModifierData *md,
Depsgraph *depsgraph,
Object *ob,
bGPDlayer *gpl,
- bGPDframe *UNUSED(gpf),
+ bGPDframe *gpf,
bGPDstroke *gps)
{
NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
- bGPDspoint *pt0, *pt1;
MDeformVert *dvert = NULL;
- float shift, vran, vdir;
+ /* Noise value in range [-1..1] */
float normal[3];
float vec1[3], vec2[3];
- int sc_frame = 0;
- int stroke_seed = 0;
const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
- const float unit_v3[3] = {1.0f, 1.0f, 1.0f};
+ const bool invert_group = (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0;
+ const bool use_curve = (mmd->flag & GP_NOISE_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
@@ -106,134 +148,99 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- sc_frame = (int)DEG_get_ctime(depsgraph);
+ int seed = mmd->seed;
+ /* FIXME(fclem): This is really slow. We should get the stroke index in another way. */
+ int stroke_seed = BLI_findindex(&gpf->strokes, gps);
+ seed += stroke_seed;
- zero_v3(vec2);
+ /* Make sure different modifiers get different seeds. */
+ seed += BLI_hash_string(ob->id.name + 2);
+ seed += BLI_hash_string(md->name);
+
+ if (mmd->flag & GP_NOISE_USE_RANDOM) {
+ seed += ((int)DEG_get_ctime(depsgraph)) / mmd->step;
+ }
+
+ /* Sanitize as it can create out of bound reads. */
+ float noise_scale = clamp_f(mmd->noise_scale, 0.0f, 1.0f);
+
+ int len = ceilf(gps->totpoints * noise_scale) + 1;
+ float *noise_table_position = (mmd->factor > 0.0f) ? noise_table(len, seed + 2) : NULL;
+ float *noise_table_strength = (mmd->factor_strength > 0.0f) ? noise_table(len, seed + 3) : NULL;
+ float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ? noise_table(len, seed) : NULL;
+ float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ? noise_table(len, seed + 4) : NULL;
/* calculate stroke normal*/
if (gps->totpoints > 2) {
BKE_gpencil_stroke_normal(gps, normal);
}
else {
- copy_v3_v3(normal, unit_v3);
+ copy_v3_fl(normal, 1.0f);
}
/* move points */
for (int i = 0; i < gps->totpoints; i++) {
- if (((i == 0) || (i == gps->totpoints - 1)) && ((mmd->flag & GP_NOISE_MOVE_EXTREME) == 0)) {
- continue;
- }
-
- /* first point is special */
- if (i == 0) {
- if (gps->dvert) {
- dvert = &gps->dvert[0];
- }
- pt0 = (gps->totpoints > 1) ? &gps->points[1] : &gps->points[0];
- pt1 = &gps->points[0];
- }
- else {
- int prev_idx = i - 1;
- CLAMP_MIN(prev_idx, 0);
- if (gps->dvert) {
- dvert = &gps->dvert[prev_idx];
- }
- pt0 = &gps->points[prev_idx];
- pt1 = &gps->points[i];
- }
-
+ bGPDspoint *pt = &gps->points[i];
/* verify vertex group */
- const float weight = get_modifier_point_weight(
- dvert, (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0, def_nr);
+ dvert = &gps->dvert[i];
+ float weight = get_modifier_point_weight(dvert, invert_group, def_nr);
if (weight < 0.0f) {
continue;
}
- /* initial vector (p0 -> p1) */
- if (i == 0) {
- sub_v3_v3v3(vec1, &pt0->x, &pt1->x);
- }
- else {
- sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+ if (use_curve) {
+ float value = (float)i / (gps->totpoints - 1);
+ weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
}
- vran = len_v3(vec1);
- /* Vector orthogonal to normal. */
- cross_v3_v3v3(vec2, vec1, normal);
- normalize_v3(vec2);
- /* Use random noise */
- if (mmd->flag & GP_NOISE_USE_RANDOM) {
- stroke_seed = BLI_hash_int_2d((sc_frame / mmd->step) + gps->totpoints, mmd->seed + 1);
- vran = BLI_hash_frand(stroke_seed);
- if (mmd->flag & GP_NOISE_FULL_STROKE) {
- vdir = BLI_hash_frand(stroke_seed + 3);
- }
- else {
- int f = (BLI_hash_frand(stroke_seed + 3) * 10.0f) + i;
- vdir = f % 2;
+
+ if (mmd->factor > 0.0f) {
+ /* Offset point randomly around the bi-normal vector. */
+ if (gps->totpoints == 1) {
+ copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f);
}
- }
- else {
- vran = 1.0f;
- if (mmd->flag & GP_NOISE_FULL_STROKE) {
- vdir = gps->totpoints % 2;
+ else if (i != gps->totpoints - 1) {
+ /* Initial vector (p1 -> p0). */
+ sub_v3_v3v3(vec1, &gps->points[i].x, &gps->points[i + 1].x);
+ /* if vec2 is zero, set to something */
+ if (len_squared_v3(vec1) < 1e-8f) {
+ copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f);
+ }
}
else {
- vdir = i % 2;
+ /* Last point reuse the penultimate normal (still stored in vec1)
+ * because the previous point is already modified. */
}
- }
+ /* Vector orthogonal to normal. */
+ cross_v3_v3v3(vec2, vec1, normal);
+ normalize_v3(vec2);
- /* if vec2 is zero, set to something */
- if (gps->totpoints < 3) {
- if ((vec2[0] == 0.0f) && (vec2[1] == 0.0f) && (vec2[2] == 0.0f)) {
- copy_v3_v3(vec2, unit_v3);
- }
+ float noise = table_sample(noise_table_position, i * noise_scale);
+ madd_v3_v3fl(&pt->x, vec2, (noise * 2.0f - 1.0f) * weight * mmd->factor * 0.1f);
}
- /* apply randomness to location of the point */
- if (mmd->flag & GP_NOISE_MOD_LOCATION) {
- /* factor is too sensitive, so need divide */
- shift = ((vran * mmd->factor) / 1000.0f) * weight;
- if (vdir > 0.5f) {
- mul_v3_fl(vec2, shift);
- }
- else {
- mul_v3_fl(vec2, shift * -1.0f);
- }
- add_v3_v3(&pt1->x, vec2);
+ if (mmd->factor_thickness > 0.0f) {
+ float noise = table_sample(noise_table_thickness, i * noise_scale);
+ pt->pressure *= max_ff(1.0f + (noise * 2.0f - 1.0f) * weight * mmd->factor_thickness, 0.0f);
+ CLAMP_MIN(pt->pressure, GPENCIL_STRENGTH_MIN);
}
- /* apply randomness to thickness */
- if (mmd->flag & GP_NOISE_MOD_THICKNESS) {
- if (vdir > 0.5f) {
- pt1->pressure -= pt1->pressure * vran * mmd->factor * weight;
- }
- else {
- pt1->pressure += pt1->pressure * vran * mmd->factor * weight;
- }
- CLAMP_MIN(pt1->pressure, GPENCIL_STRENGTH_MIN);
+ if (mmd->factor_strength > 0.0f) {
+ float noise = table_sample(noise_table_strength, i * noise_scale);
+ pt->strength *= max_ff(1.0f - noise * weight * mmd->factor_strength, 0.0f);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
- /* apply randomness to color strength */
- if (mmd->flag & GP_NOISE_MOD_STRENGTH) {
- if (vdir > 0.5f) {
- pt1->strength -= pt1->strength * vran * mmd->factor * weight;
- }
- else {
- pt1->strength += pt1->strength * vran * mmd->factor * weight;
- }
- CLAMP_MIN(pt1->strength, GPENCIL_STRENGTH_MIN);
- }
- /* apply randomness to uv rotation */
- if (mmd->flag & GP_NOISE_MOD_UV) {
- if (vdir > 0.5f) {
- pt1->uv_rot -= pt1->uv_rot * vran * mmd->factor * weight;
- }
- else {
- pt1->uv_rot += pt1->uv_rot * vran * mmd->factor * weight;
- }
- CLAMP(pt1->uv_rot, -M_PI_2, M_PI_2);
+ if (mmd->factor_uvs > 0.0f) {
+ float noise = table_sample(noise_table_uvs, i * noise_scale);
+ pt->uv_rot += (noise * 2.0f - 1.0f) * weight * mmd->factor_uvs * M_PI_2;
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
}
}
+
+ MEM_SAFE_FREE(noise_table_position);
+ MEM_SAFE_FREE(noise_table_strength);
+ MEM_SAFE_FREE(noise_table_thickness);
+ MEM_SAFE_FREE(noise_table_uvs);
}
static void bakeModifier(struct Main *UNUSED(bmain),
@@ -243,9 +250,9 @@ static void bakeModifier(struct Main *UNUSED(bmain),
{
bGPdata *gpd = ob->data;
- 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) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
@@ -267,7 +274,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
/* remapTime */ NULL,
/* initData */ initData,
- /* freeData */ NULL,
+ /* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
index 0979a2d90c9..5a9a1b68361 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -23,6 +23,7 @@
#include <stdio.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -108,6 +109,8 @@ static void deformStroke(GpencilModifierData *md,
mul_m4_v3(mat, &pt->x);
}
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
static void bakeModifier(struct Main *UNUSED(bmain),
@@ -117,9 +120,9 @@ static void bakeModifier(struct Main *UNUSED(bmain),
{
bGPdata *gpd = ob->data;
- 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) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index 9647489358e..4b04e349067 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -26,7 +26,6 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
#include "BLI_math_vector.h"
#include "DNA_meshdata_types.h"
@@ -35,6 +34,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_gpencil_modifier_types.h"
+#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_material.h"
#include "BKE_gpencil.h"
@@ -54,13 +54,27 @@ static void initData(GpencilModifierData *md)
gpmd->layername[0] = '\0';
gpmd->materialname[0] = '\0';
gpmd->vgname[0] = '\0';
- gpmd->flag |= GP_OPACITY_CREATE_COLORS;
gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+ gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_intensity) {
+ CurveMapping *curve = gpmd->curve_intensity;
+ BKE_curvemapping_initialize(curve);
+ }
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
+ OpacityGpencilModifierData *gmd = (OpacityGpencilModifierData *)md;
+ OpacityGpencilModifierData *tgmd = (OpacityGpencilModifierData *)target;
+
+ if (tgmd->curve_intensity != NULL) {
+ BKE_curvemapping_free(tgmd->curve_intensity);
+ tgmd->curve_intensity = NULL;
+ }
+
BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
/* opacity strokes */
@@ -73,6 +87,7 @@ static void deformStroke(GpencilModifierData *md,
{
OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+ const bool use_curve = (mmd->flag & GP_OPACITY_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
@@ -89,98 +104,79 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) {
- if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
- gps->runtime.tmp_stroke_rgba[3] *= mmd->factor;
- /* if factor is > 1, then force opacity */
- if (mmd->factor > 1.0f) {
- gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
- }
- CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f);
- }
-
- if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
- gps->runtime.tmp_fill_rgba[3] *= mmd->factor;
- /* if factor is > 1, then force opacity */
- if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
- gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
- }
- CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f);
- }
-
- /* if opacity > 1.0, affect the strength of the stroke */
- if (mmd->factor > 1.0f) {
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- pt->strength += mmd->factor - 1.0f;
- CLAMP(pt->strength, 0.0f, 1.0f);
- }
- }
- }
- /* Apply opacity by strength */
- else {
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+ /* Stroke using strength. */
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
/* verify vertex group */
float weight = get_modifier_point_weight(
dvert, (mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0, def_nr);
if (weight < 0.0f) {
continue;
}
+ /* Custom curve to modulate value. */
+ float factor_curve = mmd->factor;
+ if (use_curve) {
+ float value = (float)i / (gps->totpoints - 1);
+ factor_curve *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
+ }
+
if (def_nr < 0) {
- pt->strength += mmd->factor - 1.0f;
+ if (mmd->flag & GP_OPACITY_NORMALIZE) {
+ pt->strength = factor_curve;
+ }
+ else {
+ pt->strength += factor_curve - 1.0f;
+ }
}
else {
/* High factor values, change weight too. */
- if ((mmd->factor > 1.0f) && (weight < 1.0f)) {
- weight += mmd->factor - 1.0f;
+ if ((factor_curve > 1.0f) && (weight < 1.0f)) {
+ weight += factor_curve - 1.0f;
CLAMP(weight, 0.0f, 1.0f);
}
- pt->strength += (mmd->factor - 1) * weight;
+ if (mmd->flag & GP_OPACITY_NORMALIZE) {
+ pt->strength = factor_curve;
+ }
+ else {
+ pt->strength += (factor_curve - 1) * weight;
+ }
}
+
CLAMP(pt->strength, 0.0f, 1.0f);
}
}
+
+ /* Fill using opacity factor. */
+ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
+ gps->fill_opacity_fac = mmd->factor;
+ CLAMP(gps->fill_opacity_fac, 0.0f, 1.0f);
+ }
}
-static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
{
- OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
bGPdata *gpd = ob->data;
- GHash *gh_color = BLI_ghash_str_new("GP_Opacity modifier");
- 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) {
-
- Material *mat = BKE_gpencil_material(ob, gps->mat_nr + 1);
- if (mat == NULL) {
- continue;
- }
- MaterialGPencilStyle *gp_style = mat->gp_style;
- /* skip stroke if it doesn't have color info */
- if (ELEM(NULL, gp_style)) {
- continue;
- }
-
- copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
-
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
-
- if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) {
- gpencil_apply_modifier_material(
- bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS));
- }
}
}
}
- /* free hash buffers */
- if (gh_color) {
- BLI_ghash_free(gh_color, NULL, NULL);
- gh_color = NULL;
+}
+static void freeData(GpencilModifierData *md)
+{
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ BKE_curvemapping_free(gpmd->curve_intensity);
}
}
@@ -199,7 +195,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
/* remapTime */ NULL,
/* initData */ initData,
- /* freeData */ NULL,
+ /* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index 9594fc8581e..60e26407b63 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -23,6 +23,7 @@
#include <stdio.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_scene_types.h"
@@ -84,21 +85,21 @@ static void deformStroke(GpencilModifierData *md,
switch (mmd->mode) {
case GP_SIMPLIFY_FIXED: {
for (int i = 0; i < mmd->step; i++) {
- BKE_gpencil_simplify_fixed(gps);
+ BKE_gpencil_stroke_simplify_fixed(gps);
}
break;
}
case GP_SIMPLIFY_ADAPTIVE: {
/* simplify stroke using Ramer-Douglas-Peucker algorithm */
- BKE_gpencil_simplify_stroke(gps, mmd->factor);
+ BKE_gpencil_stroke_simplify_adaptive(gps, mmd->factor);
break;
}
case GP_SIMPLIFY_SAMPLE: {
- BKE_gpencil_sample_stroke(gps, mmd->length, false);
+ BKE_gpencil_stroke_sample(gps, mmd->length, false);
break;
}
case GP_SIMPLIFY_MERGE: {
- BKE_gpencil_merge_distance_stroke(gpf, gps, mmd->distance, true);
+ BKE_gpencil_stroke_merge_distance(gpf, gps, mmd->distance, true);
break;
}
default:
@@ -113,9 +114,9 @@ static void bakeModifier(struct Main *UNUSED(bmain),
{
bGPdata *gpd = ob->data;
- 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) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
index b6b5bf05a9d..896333318aa 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -23,6 +23,7 @@
#include <stdio.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_meshdata_types.h"
@@ -30,6 +31,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_gpencil_modifier_types.h"
+#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
@@ -49,11 +51,27 @@ static void initData(GpencilModifierData *md)
gpmd->materialname[0] = '\0';
gpmd->vgname[0] = '\0';
gpmd->step = 1;
+
+ gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_intensity) {
+ CurveMapping *curve = gpmd->curve_intensity;
+ BKE_curvemapping_initialize(curve);
+ }
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
+ SmoothGpencilModifierData *gmd = (SmoothGpencilModifierData *)md;
+ SmoothGpencilModifierData *tgmd = (SmoothGpencilModifierData *)target;
+
+ if (tgmd->curve_intensity != NULL) {
+ BKE_curvemapping_free(tgmd->curve_intensity);
+ tgmd->curve_intensity = NULL;
+ }
+
BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
/* aply smooth effect based on stroke direction */
@@ -66,6 +84,7 @@ static void deformStroke(GpencilModifierData *md,
{
SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md;
const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+ const bool use_curve = (mmd->flag & GP_SMOOTH_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
@@ -89,28 +108,34 @@ static void deformStroke(GpencilModifierData *md,
MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
/* verify vertex group */
- const float weight = get_modifier_point_weight(
+ float weight = get_modifier_point_weight(
dvert, (mmd->flag & GP_SMOOTH_INVERT_VGROUP) != 0, def_nr);
if (weight < 0.0f) {
continue;
}
+ /* Custom curve to modulate value. */
+ if (use_curve) {
+ float value = (float)i / (gps->totpoints - 1);
+ weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
+ }
+
const float val = mmd->factor * weight;
/* perform smoothing */
if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
- BKE_gpencil_smooth_stroke(gps, i, val);
+ BKE_gpencil_stroke_smooth(gps, i, val);
}
if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
- BKE_gpencil_smooth_stroke_strength(gps, i, val);
+ BKE_gpencil_stroke_smooth_strength(gps, i, val);
}
if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0.0f)) {
/* thickness need to repeat process several times */
for (int r2 = 0; r2 < r * 10; r2++) {
- BKE_gpencil_smooth_stroke_thickness(gps, i, val);
+ BKE_gpencil_stroke_smooth_thickness(gps, i, val);
}
}
if (mmd->flag & GP_SMOOTH_MOD_UV) {
- BKE_gpencil_smooth_stroke_uv(gps, i, val);
+ BKE_gpencil_stroke_smooth_uv(gps, i, val);
}
}
}
@@ -124,15 +149,24 @@ static void bakeModifier(struct Main *UNUSED(bmain),
{
bGPdata *gpd = ob->data;
- 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) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
}
}
+static void freeData(GpencilModifierData *md)
+{
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ BKE_curvemapping_free(gpmd->curve_intensity);
+ }
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
/* name */ "Smooth",
/* structName */ "SmoothGpencilModifierData",
@@ -148,7 +182,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
/* remapTime */ NULL,
/* initData */ initData,
- /* freeData */ NULL,
+ /* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
index 89d6565d0dd..25abf0b81eb 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_meshdata_types.h"
@@ -84,7 +85,7 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- BKE_gpencil_subdivide(gps, mmd->level, mmd->flag);
+ BKE_gpencil_stroke_subdivide(gps, mmd->level, mmd->type);
}
static void bakeModifier(struct Main *UNUSED(bmain),
@@ -94,9 +95,9 @@ static void bakeModifier(struct Main *UNUSED(bmain),
{
bGPdata *gpd = ob->data;
- 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) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
@@ -104,7 +105,7 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
- /* name */ "Subdivision",
+ /* name */ "Subdivide",
/* structName */ "SubdivGpencilModifierData",
/* structSize */ sizeof(SubdivGpencilModifierData),
/* type */ eGpencilModifierTypeType_Gpencil,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index 694b932a6bf..894dff46ac2 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -23,6 +23,8 @@
#include <stdio.h>
+#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_meshdata_types.h"
@@ -45,7 +47,8 @@ static void initData(GpencilModifierData *md)
{
ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
gpmd->pass_index = 0;
- gpmd->thickness = 2;
+ gpmd->thickness_fac = 1.0f;
+ gpmd->thickness = 30;
gpmd->layername[0] = '\0';
gpmd->materialname[0] = '\0';
gpmd->vgname[0] = '\0';
@@ -105,70 +108,38 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- /* Check to see if we normalize the whole stroke or only certain points along it. */
- bool gps_has_affected_points = false;
- bool gps_has_unaffected_points = false;
-
- if (mmd->flag & GP_THICK_NORMALIZE) {
- for (int i = 0; i < gps->totpoints; i++) {
- MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
- const float weight = get_modifier_point_weight(
- dvert, (mmd->flag & GP_THICK_INVERT_VGROUP) != 0, def_nr);
- if (weight < 0.0f) {
- gps_has_unaffected_points = true;
- }
- else {
- gps_has_affected_points = true;
- }
-
- /* If both checks are true, we have what we need so we can stop looking. */
- if (gps_has_affected_points && gps_has_unaffected_points) {
- break;
- }
- }
- }
-
- /* If we are normalizing and all points of the stroke are affected, it's safe to reset thickness
- */
- if (mmd->flag & GP_THICK_NORMALIZE && gps_has_affected_points && !gps_has_unaffected_points) {
- gps->thickness = mmd->thickness;
- }
- /* Without this check, modifier alters the thickness of strokes which have no points in scope */
+ float stroke_thickness_inv = 1.0f / max_ii(gps->thickness, 1);
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
- float curvef = 1.0f;
/* Verify point is part of vertex group. */
- const float weight = get_modifier_point_weight(
+ float weight = get_modifier_point_weight(
dvert, (mmd->flag & GP_THICK_INVERT_VGROUP) != 0, def_nr);
if (weight < 0.0f) {
continue;
}
+ float curvef = 1.0f;
+ if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) {
+ /* Normalize value to evaluate curve. */
+ float value = (float)i / (gps->totpoints - 1);
+ curvef = BKE_curvemapping_evaluateF(mmd->curve_thickness, 0, value);
+ }
+
+ float target;
if (mmd->flag & GP_THICK_NORMALIZE) {
- if (gps_has_unaffected_points) {
- /* Clamp value for very weird situations when stroke thickness can be zero. */
- CLAMP_MIN(gps->thickness, 1);
- /* Calculate pressure value to match the width of strokes with reset thickness and 1.0
- * pressure. */
- pt->pressure = (float)mmd->thickness / (float)gps->thickness;
- }
- else {
- /* Reset point pressure values so only stroke thickness counts. */
- pt->pressure = 1.0f;
- }
+ target = mmd->thickness * stroke_thickness_inv;
+ target *= curvef;
}
else {
- if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) {
- /* Normalize value to evaluate curve. */
- float value = (float)i / (gps->totpoints - 1);
- curvef = BKE_curvemapping_evaluateF(mmd->curve_thickness, 0, value);
- }
-
- pt->pressure += mmd->thickness * weight * curvef;
- CLAMP_MIN(pt->pressure, 0.1f);
+ target = pt->pressure * mmd->thickness_fac;
+ weight *= curvef;
}
+
+ pt->pressure = interpf(target, pt->pressure, weight);
+
+ CLAMP_MIN(pt->pressure, 0.1f);
}
}
@@ -179,9 +150,9 @@ static void bakeModifier(struct Main *UNUSED(bmain),
{
bGPdata *gpd = ob->data;
- 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) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index 8f3956276dd..96f1f004812 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -26,7 +26,6 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
#include "BLI_math_vector.h"
#include "DNA_scene_types.h"
@@ -34,6 +33,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_gpencil_modifier_types.h"
+#include "BKE_colortools.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_material.h"
@@ -52,13 +52,28 @@ static void initData(GpencilModifierData *md)
gpmd->layername[0] = '\0';
gpmd->materialname[0] = '\0';
ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f);
- gpmd->flag |= GP_TINT_CREATE_COLORS;
gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
+
+ gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_intensity) {
+ CurveMapping *curve = gpmd->curve_intensity;
+ BKE_curvemapping_initialize(curve);
+ }
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
+ TintGpencilModifierData *gmd = (TintGpencilModifierData *)md;
+ TintGpencilModifierData *tgmd = (TintGpencilModifierData *)target;
+
+ if (tgmd->curve_intensity != NULL) {
+ BKE_curvemapping_free(tgmd->curve_intensity);
+ tgmd->curve_intensity = NULL;
+ }
+
BKE_gpencil_modifier_copyData_generic(md, target);
+
+ tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
/* tint strokes */
@@ -70,6 +85,7 @@ static void deformStroke(GpencilModifierData *md,
bGPDstroke *gps)
{
TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+ const bool use_curve = (mmd->flag & GP_TINT_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
@@ -86,69 +102,77 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
- interp_v3_v3v3(
- gps->runtime.tmp_stroke_rgba, gps->runtime.tmp_stroke_rgba, mmd->rgb, mmd->factor);
- /* if factor is > 1, the alpha must be changed to get full tint */
- if (mmd->factor > 1.0f) {
- gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f;
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+
+ /* if factor > 1.0, affect the strength of the stroke */
+ if (mmd->factor > 1.0f) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->strength += mmd->factor - 1.0f;
+ CLAMP(pt->strength, 0.0f, 1.0f);
}
- CLAMP4(gps->runtime.tmp_stroke_rgba, 0.0f, 1.0f);
}
+ /* Apply to Vertex Color. */
+ float mixfac = mmd->factor;
+
+ CLAMP(mixfac, 0.0, 1.0f);
+ /* Fill */
if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) {
- interp_v3_v3v3(gps->runtime.tmp_fill_rgba, gps->runtime.tmp_fill_rgba, mmd->rgb, mmd->factor);
- /* if factor is > 1, the alpha must be changed to get full tint */
- if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) {
- gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f;
+ /* If not using Vertex Color, use the material color. */
+ if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) &&
+ (gp_style->fill_rgba[3] > 0.0f)) {
+ copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba);
+ gps->vert_color_fill[3] = 1.0f;
}
- CLAMP4(gps->runtime.tmp_fill_rgba, 0.0f, 1.0f);
+
+ interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, mmd->rgb, mixfac);
}
- /* if factor > 1.0, affect the strength of the stroke */
- if (mmd->factor > 1.0f) {
+ /* Stroke */
+ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) {
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
- pt->strength += mmd->factor - 1.0f;
- CLAMP(pt->strength, 0.0f, 1.0f);
+ /* If not using Vertex Color, use the material color. */
+ if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) {
+ copy_v4_v4(pt->vert_color, gp_style->stroke_rgba);
+ pt->vert_color[3] = 1.0f;
+ }
+
+ /* Custom curve to modulate value. */
+ float mixvalue = mixfac;
+ if (use_curve) {
+ float value = (float)i / (gps->totpoints - 1);
+ mixvalue *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
+ }
+
+ interp_v3_v3v3(pt->vert_color, pt->vert_color, mmd->rgb, mixvalue);
}
}
}
-static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
+static void bakeModifier(Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
{
- TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
bGPdata *gpd = ob->data;
- GHash *gh_color = BLI_ghash_str_new("GP_Tint modifier");
- 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) {
-
- Material *mat = BKE_gpencil_material(ob, gps->mat_nr + 1);
- if (mat == NULL) {
- continue;
- }
- MaterialGPencilStyle *gp_style = mat->gp_style;
- /* skip stroke if it doesn't have color info */
- if (ELEM(NULL, gp_style)) {
- continue;
- }
-
- copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
-
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
deformStroke(md, depsgraph, ob, gpl, gpf, gps);
-
- gpencil_apply_modifier_material(
- bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_TINT_CREATE_COLORS));
}
}
}
- /* free hash buffers */
- if (gh_color) {
- BLI_ghash_free(gh_color, NULL, NULL);
- gh_color = NULL;
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
+
+ if (gpmd->curve_intensity) {
+ BKE_curvemapping_free(gpmd->curve_intensity);
}
}
@@ -167,7 +191,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
/* remapTime */ NULL,
/* initData */ initData,
- /* freeData */ NULL,
+ /* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c
new file mode 100644
index 00000000000..b279d90dd4f
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c
@@ -0,0 +1,314 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_action.h"
+#include "BKE_colorband.h"
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_layer.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "MOD_gpencil_util.h"
+#include "MOD_gpencil_modifiertypes.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+static void initData(GpencilModifierData *md)
+{
+ VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md;
+ gpmd->pass_index = 0;
+ gpmd->layername[0] = '\0';
+ gpmd->materialname[0] = '\0';
+ gpmd->vgname[0] = '\0';
+ gpmd->object = NULL;
+ gpmd->radius = 1.0f;
+ gpmd->factor = 1.0f;
+
+ /* Add default color ramp. */
+ gpmd->colorband = BKE_colorband_add(false);
+ if (gpmd->colorband) {
+ BKE_colorband_init(gpmd->colorband, true);
+ CBData *ramp = gpmd->colorband->data;
+ ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f;
+ ramp[0].pos = 0.0f;
+ ramp[1].r = ramp[1].g = ramp[1].b = 0.0f;
+ ramp[1].a = 1.0f;
+ ramp[1].pos = 1.0f;
+
+ gpmd->colorband->tot = 2;
+ }
+
+ gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ if (gpmd->curve_intensity) {
+ CurveMapping *curve = gpmd->curve_intensity;
+ BKE_curvemapping_initialize(curve);
+ }
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ VertexcolorGpencilModifierData *gmd = (VertexcolorGpencilModifierData *)md;
+ VertexcolorGpencilModifierData *tgmd = (VertexcolorGpencilModifierData *)target;
+
+ MEM_SAFE_FREE(tgmd->colorband);
+
+ if (tgmd->curve_intensity != NULL) {
+ BKE_curvemapping_free(tgmd->curve_intensity);
+ tgmd->curve_intensity = NULL;
+ }
+
+ BKE_gpencil_modifier_copyData_generic(md, target);
+
+ if (gmd->colorband) {
+ tgmd->colorband = MEM_dupallocN(gmd->colorband);
+ }
+
+ tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
+}
+
+/* deform stroke */
+static void deformStroke(GpencilModifierData *md,
+ Depsgraph *UNUSED(depsgraph),
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps)
+{
+ VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md;
+ if (!mmd->object) {
+ return;
+ }
+
+ const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+ const bool use_curve = (mmd->flag & GP_VERTEXCOL_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->materialname,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_VERTEXCOL_INVERT_LAYER,
+ mmd->flag & GP_VERTEXCOL_INVERT_PASS,
+ mmd->flag & GP_VERTEXCOL_INVERT_LAYERPASS,
+ mmd->flag & GP_VERTEXCOL_INVERT_MATERIAL)) {
+ return;
+ }
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+
+ float coba_res[4];
+ float matrix[4][4];
+ mul_m4_m4m4(matrix, mmd->object->imat, ob->obmat);
+
+ /* loop points and apply deform */
+ bool fill_done = false;
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ if (!fill_done) {
+ /* Apply to fill. */
+ if (mmd->mode != GPPAINT_MODE_STROKE) {
+
+ /* If not using Vertex Color, use the material color. */
+ if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) &&
+ (gp_style->fill_rgba[3] > 0.0f)) {
+ copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba);
+ gps->vert_color_fill[3] = 1.0f;
+ }
+
+ float center[3];
+ add_v3_v3v3(center, gps->boundbox_min, gps->boundbox_max);
+ mul_v3_fl(center, 0.5f);
+ float pt_loc[3];
+ mul_v3_m4v3(pt_loc, matrix, &pt->x);
+ float dist = len_v3(pt_loc);
+ float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f);
+
+ BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res);
+ interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, coba_res, mmd->factor);
+ gps->vert_color_fill[3] = mmd->factor;
+ /* If no stroke, cancel loop. */
+ if (mmd->mode != GPPAINT_MODE_BOTH) {
+ break;
+ }
+ }
+
+ fill_done = true;
+ }
+
+ /* Verify vertex group. */
+ if (mmd->mode != GPPAINT_MODE_FILL) {
+ float weight = get_modifier_point_weight(
+ dvert, (mmd->flag & GP_VERTEXCOL_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+ /* Custom curve to modulate value. */
+ if (use_curve) {
+ float value = (float)i / (gps->totpoints - 1);
+ weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
+ }
+
+ /* Calc world position of point. */
+ float pt_loc[3];
+ mul_v3_m4v3(pt_loc, matrix, &pt->x);
+ float dist = len_v3(pt_loc);
+
+ /* If not using Vertex Color, use the material color. */
+ if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) {
+ copy_v4_v4(pt->vert_color, gp_style->stroke_rgba);
+ pt->vert_color[3] = 1.0f;
+ }
+
+ /* Calc the factor using the distance and get mix color. */
+ float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f);
+ BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res);
+
+ interp_v3_v3v3(pt->vert_color, pt->vert_color, coba_res, mmd->factor * weight * coba_res[3]);
+ }
+ }
+}
+
+/* FIXME: Ideally we be doing this on a copy of the main depsgraph
+ * (i.e. one where we don't have to worry about restoring state)
+ */
+static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
+{
+ VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = ob->data;
+ int oldframe = (int)DEG_get_ctime(depsgraph);
+
+ if (mmd->object == NULL) {
+ return;
+ }
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ /* apply effects on this frame
+ * NOTE: this assumes that we don't want animation on non-keyframed frames
+ */
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+
+ /* compute effects on this frame */
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ deformStroke(md, depsgraph, ob, gpl, gpf, gps);
+ }
+ }
+ }
+
+ /* return frame state and DB to original state */
+ CFRA = oldframe;
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+static void freeData(GpencilModifierData *md)
+{
+ VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md;
+ if (mmd->colorband) {
+ MEM_freeN(mmd->colorband);
+ mmd->colorband = NULL;
+ }
+ if (mmd->curve_intensity) {
+ BKE_curvemapping_free(mmd->curve_intensity);
+ }
+}
+
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md;
+
+ return !mmd->object;
+}
+
+static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ VertexcolorGpencilModifierData *lmd = (VertexcolorGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Vertexcolor Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier");
+}
+
+static void foreachObjectLink(GpencilModifierData *md,
+ Object *ob,
+ ObjectWalkFunc walk,
+ void *userData)
+{
+ VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md;
+
+ walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Vertexcolor = {
+ /* name */ "Vertex Color",
+ /* structName */ "VertexcolorGpencilModifierData",
+ /* structSize */ sizeof(VertexcolorGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index 7d0f8b0bcbf..213cbe30794 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -173,6 +173,8 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb,
#define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \
GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil)
+void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4]);
+
void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data);
void GPU_framebuffer_read_color(
GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data);
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
index c636135d75b..8b0d25e51a3 100644
--- a/source/blender/gpu/GPU_shader_interface.h
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -55,6 +55,7 @@ typedef enum {
GPU_UNIFORM_COLOR, /* vec4 color */
GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
+ GPU_UNIFORM_RESOURCE_ID, /* int resourceId */
GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 338f4d906f6..50b7c23059d 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -95,6 +95,7 @@ typedef enum eGPUTextureFormat {
#if 0
GPU_RGB10_A2,
GPU_RGB10_A2UI,
+ GPU_SRGB8_A8,
#endif
GPU_R11F_G11F_B10F,
GPU_DEPTH32F_STENCIL8,
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index cbc20f37f27..f5717645bc1 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -112,6 +112,8 @@ uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias);
+void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count);
+
void GPU_vertformat_deinterleave(GPUVertFormat *format);
int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name);
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index b0fbb0eae49..6197d5f99b8 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -614,6 +614,21 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb,
glClear(mask);
}
+/* Clear all textures bound to this framebuffer with a different color. */
+void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4])
+{
+ CHECK_FRAMEBUFFER_IS_BOUND(fb);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0;
+ for (int i = 0; type < GPU_FB_MAX_ATTACHEMENT; i++, type++) {
+ if (fb->attachments[type].tex != NULL) {
+ glClearBufferfv(GL_COLOR, i, clear_cols[i]);
+ }
+ }
+}
+
void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data)
{
CHECK_FRAMEBUFFER_IS_BOUND(fb);
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index 983c5dfc27a..f895993a27d 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -67,6 +67,7 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u)
[GPU_UNIFORM_COLOR] = "color",
[GPU_UNIFORM_BASE_INSTANCE] = "baseInstance",
[GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk",
+ [GPU_UNIFORM_RESOURCE_ID] = "resourceId",
[GPU_UNIFORM_CUSTOM] = NULL,
[GPU_NUM_UNIFORMS] = NULL,
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c
index 65573b71c76..16d8f8f875b 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.c
+++ b/source/blender/gpu/intern/gpu_vertex_format.c
@@ -206,6 +206,47 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
attr->names[attr->name_len++] = copy_attr_name(format, alias);
}
+/**
+ * Makes vertex attrib from the next vertices to be accessible in the vertex shader.
+ * For an attrib named "attr" you can access the next nth vertex using "attrn".
+ * Use this function after specifying all the attribs in the format.
+ *
+ * NOTE: This does NOT work when using indexed rendering.
+ * NOTE: Only works for first attrib name. (this limitation can be changed if needed)
+ *
+ * WARNING: this function creates a lot of aliases/attribs, make sure to keep the attrib name
+ * short to avoid overflowing the namebuffer.
+ * */
+void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
+{
+ /* Sanity check. Maximum can be upgraded if needed. */
+ BLI_assert(load_count > 1 && load_count < 5);
+ /* We need a packed format because of format->stride. */
+ if (!format->packed) {
+ VertexFormat_pack(format);
+ }
+
+ BLI_assert((format->name_len + 1) * load_count < GPU_VERT_FORMAT_MAX_NAMES);
+ BLI_assert(format->attr_len * load_count <= GPU_VERT_ATTR_MAX_LEN);
+ BLI_assert(format->name_offset * load_count < GPU_VERT_ATTR_NAMES_BUF_LEN);
+
+ const GPUVertAttr *attr = format->attrs;
+ int attr_len = format->attr_len;
+ for (int i = 0; i < attr_len; i++, attr++) {
+ const char *attr_name = GPU_vertformat_attr_name_get(format, attr, 0);
+ for (int j = 1; j < load_count; j++) {
+ char load_name[64];
+ BLI_snprintf(load_name, sizeof(load_name), "%s%d", attr_name, j);
+ GPUVertAttr *dst_attr = &format->attrs[format->attr_len++];
+ *dst_attr = *attr;
+
+ dst_attr->names[0] = copy_attr_name(format, load_name);
+ dst_attr->name_len = 1;
+ dst_attr->offset += format->stride * j;
+ }
+ }
+}
+
int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name)
{
for (int i = 0; i < format->attr_len; i++) {
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 8ac9b2e2e16..83ef910d0bb 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -601,6 +601,9 @@ void bilinear_interpolation_color_wrap(
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3]);
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol[3]);
+void IMB_sampleImageAtLocation(
+ struct ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4]);
+
/**
*
* \attention defined in readimage.c
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 6a234232a35..4cd47d19e62 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -37,6 +37,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
#include <math.h>
/* Only this one is used liberally here, and in imbuf */
@@ -490,3 +491,19 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol
cp += 4;
}
}
+
+/* Sample pixel of image using NEAREST method. */
+void IMB_sampleImageAtLocation(ImBuf *ibuf, float x, float y, bool make_linear_rgb, float color[4])
+{
+ if (ibuf->rect_float) {
+ nearest_interpolation_color(ibuf, NULL, color, x, y);
+ }
+ else {
+ unsigned char byte_color[4];
+ nearest_interpolation_color(ibuf, byte_color, NULL, x, y);
+ rgba_uchar_to_float(color, byte_color);
+ if (make_linear_rgb) {
+ IMB_colormanagement_colorspace_to_scene_linear_v4(color, false, ibuf->rect_colorspace);
+ }
+ }
+}
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 0109fba909b..3f703558e54 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -50,8 +50,7 @@ typedef struct BrushClone {
typedef struct BrushGpencilSettings {
/** Amount of smoothing to apply to newly created strokes. */
float draw_smoothfac;
- /** Amount of sensitivity to apply to newly created strokes. */
- float draw_sensitivity;
+ char _pad2[4];
/** Amount of alpha strength to apply to newly created strokes. */
float draw_strength;
/** Amount of jitter to apply to newly created strokes. */
@@ -64,18 +63,11 @@ typedef struct BrushGpencilSettings {
float draw_random_press;
/** Factor of strength for strength. */
float draw_random_strength;
- /** Factor of randomness for subdivision. */
- float draw_random_sub;
/** Number of times to apply smooth factor to new strokes. */
short draw_smoothlvl;
/** Number of times to subdivide new strokes. */
short draw_subdivide;
- short _pad;
-
- /** Number of times to apply thickness smooth factor to new strokes. */
- short thick_smoothlvl;
- /** Amount of thickness smoothing to apply to newly created strokes. */
- float thick_smoothfac;
+ char _pad[4];
/** Factor for transparency. */
float fill_threshold;
@@ -83,7 +75,7 @@ typedef struct BrushGpencilSettings {
short fill_leak;
/** Fill zoom factor */
short fill_factor;
- char _pad_1[4];
+ char _pad1[4];
/** Number of simplify steps. */
int fill_simplylvl;
@@ -110,12 +102,24 @@ typedef struct BrushGpencilSettings {
int flag;
/** gradient control along y for color */
- float gradient_f;
+ float hardeness;
/** factor xy of shape for dots gradients */
- float gradient_s[2];
+ float aspect_ratio[2];
/** Simplify adaptive factor */
float simplify_f;
+ /** Mix colorfactor */
+ float vertex_factor;
+ int vertex_mode;
+
+ /** eGP_Sculpt_Flag. */
+ int sculpt_flag;
+ /** eGP_Sculpt_Mode_Flag. */
+ int sculpt_mode_flag;
+ /** Preset type (used to reset brushes - internal). */
+ short preset_type;
+ char _pad3[6];
+
struct CurveMapping *curve_sensitivity;
struct CurveMapping *curve_strength;
struct CurveMapping *curve_jitter;
@@ -125,6 +129,49 @@ typedef struct BrushGpencilSettings {
struct Material *material;
} BrushGpencilSettings;
+/* BrushGpencilSettings->preset_type.
+ * Use a range for each group and not continuous values.*/
+typedef enum eGPBrush_Presets {
+ GP_BRUSH_PRESET_UNKNOWN = 0,
+
+ /* Draw 1-99. */
+ GP_BRUSH_PRESET_AIRBRUSH = 1,
+ GP_BRUSH_PRESET_INK_PEN = 2,
+ GP_BRUSH_PRESET_INK_PEN_ROUGH = 3,
+ GP_BRUSH_PRESET_MARKER_BOLD = 4,
+ GP_BRUSH_PRESET_MARKER_CHISEL = 5,
+ GP_BRUSH_PRESET_PEN = 6,
+ GP_BRUSH_PRESET_PENCIL_SOFT = 7,
+ GP_BRUSH_PRESET_PENCIL = 8,
+ GP_BRUSH_PRESET_FILL_AREA = 9,
+ GP_BRUSH_PRESET_ERASER_SOFT = 10,
+ GP_BRUSH_PRESET_ERASER_HARD = 11,
+ GP_BRUSH_PRESET_ERASER_POINT = 12,
+ GP_BRUSH_PRESET_ERASER_STROKE = 13,
+ GP_BRUSH_PRESET_TINT = 14,
+
+ /* Vertex Paint 100-199. */
+ GP_BRUSH_PRESET_VERTEX_DRAW = 100,
+ GP_BRUSH_PRESET_VERTEX_BLUR = 101,
+ GP_BRUSH_PRESET_VERTEX_AVERAGE = 102,
+ GP_BRUSH_PRESET_VERTEX_SMEAR = 103,
+ GP_BRUSH_PRESET_VERTEX_REPLACE = 104,
+
+ /* Sculpt 200-299. */
+ GP_BRUSH_PRESET_SMOOTH_STROKE = 200,
+ GP_BRUSH_PRESET_STRENGTH_STROKE = 201,
+ GP_BRUSH_PRESET_THICKNESS_STROKE = 202,
+ GP_BRUSH_PRESET_GRAB_STROKE = 203,
+ GP_BRUSH_PRESET_PUSH_STROKE = 204,
+ GP_BRUSH_PRESET_TWIST_STROKE = 205,
+ GP_BRUSH_PRESET_PINCH_STROKE = 206,
+ GP_BRUSH_PRESET_RANDOMIZE_STROKE = 207,
+ GP_BRUSH_PRESET_CLONE_STROKE = 208,
+
+ /* Weight Paint 300-399. */
+ GP_BRUSH_PRESET_DRAW_WEIGHT = 300,
+} eGPBrush_Presets;
+
/* BrushGpencilSettings->gp_flag */
typedef enum eGPDbrush_Flag {
/* brush use pressure */
@@ -133,8 +180,6 @@ typedef enum eGPDbrush_Flag {
GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 1),
/* brush use pressure for alpha factor */
GP_BRUSH_USE_JITTER_PRESSURE = (1 << 2),
- /* enable screen cursor */
- GP_BRUSH_ENABLE_CURSOR = (1 << 5),
/* fill hide transparent */
GP_BRUSH_FILL_HIDE = (1 << 6),
/* show fill help lines */
@@ -187,6 +232,22 @@ typedef enum eGP_BrushIcons {
GP_BRUSH_ICON_ERASE_STROKE = 10,
GP_BRUSH_ICON_AIRBRUSH = 11,
GP_BRUSH_ICON_CHISEL = 12,
+ GP_BRUSH_ICON_TINT = 13,
+ GP_BRUSH_ICON_VERTEX_DRAW = 14,
+ GP_BRUSH_ICON_VERTEX_BLUR = 15,
+ GP_BRUSH_ICON_VERTEX_AVERAGE = 16,
+ GP_BRUSH_ICON_VERTEX_SMEAR = 17,
+ GP_BRUSH_ICON_VERTEX_REPLACE = 18,
+ GP_BRUSH_ICON_GPBRUSH_SMOOTH = 19,
+ GP_BRUSH_ICON_GPBRUSH_THICKNESS = 20,
+ GP_BRUSH_ICON_GPBRUSH_STRENGTH = 21,
+ GP_BRUSH_ICON_GPBRUSH_RANDOMIZE = 22,
+ GP_BRUSH_ICON_GPBRUSH_GRAB = 23,
+ GP_BRUSH_ICON_GPBRUSH_PUSH = 24,
+ GP_BRUSH_ICON_GPBRUSH_TWIST = 25,
+ GP_BRUSH_ICON_GPBRUSH_PINCH = 26,
+ GP_BRUSH_ICON_GPBRUSH_CLONE = 27,
+ GP_BRUSH_ICON_GPBRUSH_WEIGHT = 28,
} eGP_BrushIcons;
typedef enum eBrushCurvePreset {
@@ -225,6 +286,38 @@ typedef enum eBrushClothForceFalloffType {
BRUSH_CLOTH_FORCE_FALLOFF_PLANE = 1,
} eBrushClothForceFalloffType;
+/* Gpencilsettings.Vertex_mode */
+typedef enum eGp_Vertex_Mode {
+ /* Affect to Stroke only. */
+ GPPAINT_MODE_STROKE = 0,
+ /* Affect to Fill only. */
+ GPPAINT_MODE_FILL = 1,
+ /* Affect to both. */
+ GPPAINT_MODE_BOTH = 2,
+} eGp_Vertex_Mode;
+
+/* sculpt_flag */
+typedef enum eGP_Sculpt_Flag {
+ /* invert the effect of the brush */
+ GP_SCULPT_FLAG_INVERT = (1 << 0),
+ /* smooth brush affects pressure values as well */
+ GP_SCULPT_FLAG_SMOOTH_PRESSURE = (1 << 2),
+ /* temporary invert action */
+ GP_SCULPT_FLAG_TMP_INVERT = (1 << 3),
+} eGP_Sculpt_Flag;
+
+/* sculpt_mode_flag */
+typedef enum eGP_Sculpt_Mode_Flag {
+ /* apply brush to position */
+ GP_SCULPT_FLAGMODE_APPLY_POSITION = (1 << 0),
+ /* apply brush to strength */
+ GP_SCULPT_FLAGMODE_APPLY_STRENGTH = (1 << 1),
+ /* apply brush to thickness */
+ GP_SCULPT_FLAGMODE_APPLY_THICKNESS = (1 << 2),
+ /* apply brush to uv data */
+ GP_SCULPT_FLAGMODE_APPLY_UV = (1 << 3),
+} eGP_Sculpt_Mode_Flag;
+
typedef enum eAutomasking_flag {
BRUSH_AUTOMASKING_TOPOLOGY = (1 << 0),
BRUSH_AUTOMASKING_FACE_SETS = (1 << 1),
@@ -327,7 +420,13 @@ typedef struct Brush {
char mask_tool;
/** Active grease pencil tool. */
char gpencil_tool;
- char _pad1[5];
+ /** Active grease pencil vertex tool. */
+ char gpencil_vertex_tool;
+ /** Active grease pencil sculpt tool. */
+ char gpencil_sculpt_tool;
+ /** Active grease pencil weight tool. */
+ char gpencil_weight_tool;
+ char _pad1_[6];
float autosmooth_factor;
@@ -398,9 +497,20 @@ typedef struct Brush {
float mask_stencil_pos[2];
float mask_stencil_dimension[2];
+ char _pad6[4];
struct BrushGpencilSettings *gpencil_settings;
} Brush;
+
+/* Struct to hold palette colors for sorting. */
+typedef struct tPaletteColorHSV {
+ float rgb[3];
+ float value;
+ float h;
+ float s;
+ float v;
+} tPaletteColorHSV;
+
typedef struct PaletteColor {
struct PaletteColor *next, *prev;
/* two values, one to store rgb, other to store values for sculpt/weight */
@@ -629,8 +739,37 @@ typedef enum eBrushGPaintTool {
GPAINT_TOOL_DRAW = 0,
GPAINT_TOOL_FILL = 1,
GPAINT_TOOL_ERASE = 2,
+ GPAINT_TOOL_TINT = 3,
} eBrushGPaintTool;
+/* BrushGpencilSettings->brush type */
+typedef enum eBrushGPVertexTool {
+ GPVERTEX_TOOL_DRAW = 0,
+ GPVERTEX_TOOL_BLUR = 1,
+ GPVERTEX_TOOL_AVERAGE = 2,
+ GPVERTEX_TOOL_TINT = 3,
+ GPVERTEX_TOOL_SMEAR = 4,
+ GPVERTEX_TOOL_REPLACE = 5,
+} eBrushGPVertexTool;
+
+/* BrushGpencilSettings->brush type */
+typedef enum eBrushGPSculptTool {
+ GPSCULPT_TOOL_SMOOTH = 0,
+ GPSCULPT_TOOL_THICKNESS = 1,
+ GPSCULPT_TOOL_STRENGTH = 2,
+ GPSCULPT_TOOL_GRAB = 3,
+ GPSCULPT_TOOL_PUSH = 4,
+ GPSCULPT_TOOL_TWIST = 5,
+ GPSCULPT_TOOL_PINCH = 6,
+ GPSCULPT_TOOL_RANDOMIZE = 7,
+ GPSCULPT_TOOL_CLONE = 8,
+} eBrushGPSculptTool;
+
+/* BrushGpencilSettings->brush type */
+typedef enum eBrushGPWeightTool {
+ GPWEIGHT_TOOL_DRAW = 0,
+} eBrushGPWeightTool;
+
/* direction that the brush displaces along */
enum {
SCULPT_DISP_DIR_AREA = 0,
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 5fe12998998..1121bdf4df0 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -47,6 +47,7 @@ typedef enum GpencilModifierType {
eGpencilModifierType_Armature = 15,
eGpencilModifierType_Time = 16,
eGpencilModifierType_Multiply = 17,
+ eGpencilModifierType_Vertexcolor = 18,
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -89,12 +90,18 @@ typedef struct NoiseGpencilModifierData {
int flag;
/** Factor of noise. */
float factor;
+ float factor_strength;
+ float factor_thickness;
+ float factor_uvs;
+ /** Noise Frequency scaling */
+ float noise_scale;
/** How many frames before recalculate randoms. */
int step;
/** Custom index for passes. */
int layer_pass;
/** Random seed */
int seed;
+ struct CurveMapping *curve_intensity;
} NoiseGpencilModifierData;
typedef enum eNoiseGpencil_Flag {
@@ -103,7 +110,7 @@ typedef enum eNoiseGpencil_Flag {
GP_NOISE_MOD_STRENGTH = (1 << 2),
GP_NOISE_MOD_THICKNESS = (1 << 3),
GP_NOISE_FULL_STROKE = (1 << 4),
- GP_NOISE_MOVE_EXTREME = (1 << 5),
+ GP_NOISE_CUSTOM_CURVE = (1 << 5),
GP_NOISE_INVERT_LAYER = (1 << 6),
GP_NOISE_INVERT_PASS = (1 << 7),
GP_NOISE_INVERT_VGROUP = (1 << 8),
@@ -126,16 +133,23 @@ typedef struct SubdivGpencilModifierData {
int level;
/** Custom index for passes. */
int layer_pass;
+ /** Type of subdivision */
+ short type;
+ char _pad[6];
} SubdivGpencilModifierData;
typedef enum eSubdivGpencil_Flag {
- GP_SUBDIV_SIMPLE = (1 << 0),
GP_SUBDIV_INVERT_LAYER = (1 << 1),
GP_SUBDIV_INVERT_PASS = (1 << 2),
GP_SUBDIV_INVERT_LAYERPASS = (1 << 3),
GP_SUBDIV_INVERT_MATERIAL = (1 << 4),
} eSubdivGpencil_Flag;
+typedef enum eSubdivGpencil_Type {
+ GP_SUBDIV_CATMULL = 0,
+ GP_SUBDIV_SIMPLE = 1,
+} eSubdivGpencil_Type;
+
typedef struct ThickGpencilModifierData {
GpencilModifierData modifier;
/** Layer name. */
@@ -148,10 +162,13 @@ typedef struct ThickGpencilModifierData {
int pass_index;
/** Flags. */
int flag;
- /** Thickness change. */
+ /** Relative thickness factor. */
+ float thickness_fac;
+ /** Absolute thickness overide. */
int thickness;
/** Custom index for passes. */
int layer_pass;
+ char _pad[4];
struct CurveMapping *curve_thickness;
} ThickGpencilModifierData;
@@ -225,15 +242,17 @@ typedef struct TintGpencilModifierData {
char _pad[7];
/** Custom index for passes. */
int layer_pass;
+
char _pad1[4];
+ struct CurveMapping *curve_intensity;
} TintGpencilModifierData;
typedef enum eTintGpencil_Flag {
- GP_TINT_CREATE_COLORS = (1 << 0),
GP_TINT_INVERT_LAYER = (1 << 1),
GP_TINT_INVERT_PASS = (1 << 2),
GP_TINT_INVERT_LAYERPASS = (1 << 3),
GP_TINT_INVERT_MATERIAL = (1 << 4),
+ GP_TINT_CUSTOM_CURVE = (1 << 5),
} eTintGpencil_Flag;
typedef struct ColorGpencilModifierData {
@@ -253,15 +272,17 @@ typedef struct ColorGpencilModifierData {
char _pad[3];
/** Custom index for passes. */
int layer_pass;
+
char _pad1[4];
+ struct CurveMapping *curve_intensity;
} ColorGpencilModifierData;
typedef enum eColorGpencil_Flag {
- GP_COLOR_CREATE_COLORS = (1 << 0),
GP_COLOR_INVERT_LAYER = (1 << 1),
GP_COLOR_INVERT_PASS = (1 << 2),
GP_COLOR_INVERT_LAYERPASS = (1 << 3),
GP_COLOR_INVERT_MATERIAL = (1 << 4),
+ GP_COLOR_CUSTOM_CURVE = (1 << 5),
} eColorGpencil_Flag;
typedef struct OpacityGpencilModifierData {
@@ -280,21 +301,22 @@ typedef struct OpacityGpencilModifierData {
float factor;
/** Modify stroke, fill or both. */
char modify_color;
- /** Mode of opacity, colors or strength */
- char opacity_mode;
- char _pad[2];
+ char _pad[3];
/** Custom index for passes. */
int layer_pass;
+
char _pad1[4];
+ struct CurveMapping *curve_intensity;
} OpacityGpencilModifierData;
typedef enum eOpacityGpencil_Flag {
GP_OPACITY_INVERT_LAYER = (1 << 0),
GP_OPACITY_INVERT_PASS = (1 << 1),
GP_OPACITY_INVERT_VGROUP = (1 << 2),
- GP_OPACITY_CREATE_COLORS = (1 << 3),
GP_OPACITY_INVERT_LAYERPASS = (1 << 4),
GP_OPACITY_INVERT_MATERIAL = (1 << 5),
+ GP_OPACITY_CUSTOM_CURVE = (1 << 6),
+ GP_OPACITY_NORMALIZE = (1 << 7),
} eOpacityGpencil_Flag;
typedef struct ArrayGpencilModifierData {
@@ -308,17 +330,15 @@ typedef struct ArrayGpencilModifierData {
float offset[3];
/** Shift increment. */
float shift[3];
- /** Random size factor. */
- float rnd_size;
- /** Random size factor. */
- float rnd_rot;
- /** Rotation changes. */
- float rot[3];
- /** Scale changes. */
- float scale[3];
- /** (first element is the index) random values. */
- float rnd[20];
+ /** Random Offset. */
+ float rnd_offset[3];
+ /** Random Rotation. */
+ float rnd_rot[3];
+ /** Random Scales. */
+ float rnd_scale[3];
char _pad[4];
+ /** (first element is the index) random values. */
+ int seed;
/** Custom index for passes. */
int pass_index;
@@ -333,13 +353,13 @@ typedef struct ArrayGpencilModifierData {
} ArrayGpencilModifierData;
typedef enum eArrayGpencil_Flag {
- GP_ARRAY_RANDOM_SIZE = (1 << 0),
- GP_ARRAY_RANDOM_ROT = (1 << 1),
GP_ARRAY_INVERT_LAYER = (1 << 2),
GP_ARRAY_INVERT_PASS = (1 << 3),
- GP_ARRAY_KEEP_ONTOP = (1 << 4),
GP_ARRAY_INVERT_LAYERPASS = (1 << 5),
GP_ARRAY_INVERT_MATERIAL = (1 << 6),
+ GP_ARRAY_USE_OFFSET = (1 << 7),
+ GP_ARRAY_USE_RELATIVE = (1 << 8),
+ GP_ARRAY_USE_OB_OFFSET = (1 << 9),
} eArrayGpencil_Flag;
typedef struct BuildGpencilModifierData {
@@ -613,7 +633,9 @@ typedef struct SmoothGpencilModifierData {
int step;
/** Custom index for passes. */
int layer_pass;
- char _pad[4];
+
+ char _pad1[4];
+ struct CurveMapping *curve_intensity;
} SmoothGpencilModifierData;
typedef enum eSmoothGpencil_Flag {
@@ -626,6 +648,7 @@ typedef enum eSmoothGpencil_Flag {
GP_SMOOTH_MOD_UV = (1 << 6),
GP_SMOOTH_INVERT_LAYERPASS = (1 << 7),
GP_SMOOTH_INVERT_MATERIAL = (1 << 4),
+ GP_SMOOTH_CUSTOM_CURVE = (1 << 8),
} eSmoothGpencil_Flag;
typedef struct ArmatureGpencilModifierData {
@@ -677,4 +700,41 @@ typedef enum eMultiplyGpencil_Flag {
GP_MULTIPLY_ENABLE_FADING = (1 << 2),
} eMultiplyGpencil_Flag;
+typedef struct VertexcolorGpencilModifierData {
+ GpencilModifierData modifier;
+
+ struct Object *object;
+ /** Layer name. */
+ char layername[64];
+ /** Material name. */
+ char materialname[64];
+ /** Optional vertexgroup name, MAX_VGROUP_NAME. */
+ char vgname[64];
+ /** Custom index for passes. */
+ int pass_index;
+ /** Custom index for passes. */
+ int layer_pass;
+ /** Flags. */
+ int flag;
+ /** Mode. */
+ int mode;
+
+ float factor;
+ float radius;
+
+ struct CurveMapping *curve_intensity;
+
+ struct ColorBand *colorband;
+} VertexcolorGpencilModifierData;
+
+typedef enum eVertexcolorGpencil_Flag {
+ GP_VERTEXCOL_INVERT_LAYER = (1 << 0),
+ GP_VERTEXCOL_INVERT_PASS = (1 << 1),
+ GP_VERTEXCOL_INVERT_VGROUP = (1 << 2),
+ GP_VERTEXCOL_UNIFORM_SPACE = (1 << 3),
+ GP_VERTEXCOL_INVERT_LAYERPASS = (1 << 4),
+ GP_VERTEXCOL_INVERT_MATERIAL = (1 << 5),
+ GP_VERTEXCOL_CUSTOM_CURVE = (1 << 6),
+} eVertexcolorGpencil_Flag;
+
#endif /* __DNA_GPENCIL_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 8908b3c42d9..6059df6f886 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -36,6 +36,8 @@ struct MDeformVert;
#define GP_DEFAULT_GRID_LINES 4
#define GP_MAX_INPUT_SAMPLES 10
+#define GP_MATERIAL_BUFFER_LEN 256
+
/* ***************************************** */
/* GP Stroke Points */
@@ -78,9 +80,15 @@ typedef struct bGPDspoint {
float uv_fac;
/** Uv rotation for dot mode. */
float uv_rot;
+ /** Uv for fill mode */
+ float uv_fill[2];
+
+ /** Vertex Color RGBA (A=mix factor). */
+ float vert_color[4];
/** Runtime data */
char _pad2[4];
+
bGPDspoint_Runtime runtime;
} bGPDspoint;
@@ -105,8 +113,6 @@ typedef enum eGPDspoint_Flag {
typedef struct bGPDtriangle {
/* indices for tessellated triangle used for GP Fill */
unsigned int verts[3];
- /* texture coordinates for verts */
- float uv[3][2];
} bGPDtriangle;
/* ***************************************** */
@@ -166,18 +172,17 @@ typedef enum eGPDpalette_Flag {
/* Runtime temp data for bGPDstroke */
typedef struct bGPDstroke_Runtime {
- /** runtime final colors (result of original colors and modifiers) */
- float tmp_stroke_rgba[4];
-
- /** runtime final fill colors (result of original colors and modifiers) */
- float tmp_fill_rgba[4];
-
/** temporary layer name only used during copy/paste to put the stroke in the original layer */
char tmp_layerinfo[128];
/** Runtime falloff factor (only for transform). */
float multi_frame_falloff;
- char _pad[4];
+
+ /** Vertex offset in the vbo where this stroke starts. */
+ int stroke_start;
+ /** Triangle offset in the ibo where this fill starts. */
+ int fill_start;
+ int _pad[1];
/** Original stroke (used to dereference evaluated data) */
struct bGPDstroke *gps_orig;
@@ -217,15 +222,31 @@ typedef struct bGPDstroke {
short caps[2];
/** gradient control along y for color */
- float gradient_f;
+ float hardeness;
/** factor xy of shape for dots gradients */
- float gradient_s[2];
- char _pad_3[4];
+ float aspect_ratio[2];
+
+ /** Factor of opacity for Fill color (used by opacity modifier). */
+ float fill_opacity_fac;
+
+ /** Min of the bound box used to speedup painting operators. */
+ float boundbox_min[3];
+ /** Max of the bound box used to speedup painting operators. */
+ float boundbox_max[3];
+
+ /** UV rotation */
+ float uv_rotation;
+ /** UV translation (X and Y axis) */
+ float uv_translation[2];
+ float uv_scale;
/** Vertex weight data. */
struct MDeformVert *dvert;
void *_pad3;
+ /** Vertex Color for Fill (one for all stroke, A=mix factor). */
+ float vert_color_fill[4];
+
bGPDstroke_Runtime runtime;
} bGPDstroke;
@@ -239,14 +260,13 @@ typedef enum eGPDstroke_Flag {
GP_STROKE_2DIMAGE = (1 << 2),
/* stroke is selected */
GP_STROKE_SELECT = (1 << 3),
- /* Recalculate geometry data (triangulation, UVs, Bound Box,...
- * (when true, force a new recalc) */
- GP_STROKE_RECALC_GEOMETRY = (1 << 4),
/* Flag used to indicate that stroke is closed and draw edge between last and first point */
GP_STROKE_CYCLIC = (1 << 7),
/* Flag used to indicate that stroke is used for fill close and must use
* fill color for stroke and no fill area */
GP_STROKE_NOFILL = (1 << 8),
+ /* Tag for update geometry */
+ GP_STROKE_TAG = (1 << 14),
/* only for use with stroke-buffer (while drawing eraser) */
GP_STROKE_ERASER = (1 << 15),
} eGPDstroke_Flag;
@@ -265,8 +285,13 @@ typedef enum eGPDstroke_Caps {
/* Runtime temp data for bGPDframe */
typedef struct bGPDframe_Runtime {
- /** Parent matrix for drawing. */
- float parent_obmat[4][4];
+ /** Index of this frame in the listbase of frames. */
+ int frameid;
+ /** Onion offset from active frame. 0 if not onion. INT_MAX to bypass frame. */
+ int onion_id;
+
+ /** Original frame (used to dereference evaluated data) */
+ struct bGPDframe *gpf_orig;
} bGPDframe_Runtime;
/* Grease-Pencil Annotations - 'Frame'
@@ -300,11 +325,31 @@ typedef enum eGPDframe_Flag {
/* ***************************************** */
/* GP Layer */
+/* List of masking layers. */
+typedef struct bGPDlayer_Mask {
+ struct bGPDlayer_Mask *next, *prev;
+ char name[128];
+ short flag;
+ /** Index for sorting. Only valid while sorting algorithm is running. */
+ short sort_index;
+ char _pad[4];
+} bGPDlayer_Mask;
+
+/* bGPDlayer_Mask->flag */
+typedef enum ebGPDlayer_Mask_Flag {
+ /* Mask is hidden. */
+ GP_MASK_HIDE = (1 << 0),
+ /* Mask is inverted. */
+ GP_MASK_INVERT = (1 << 1),
+} ebGPDlayer_Mask_Flag;
+
/* Runtime temp data for bGPDlayer */
typedef struct bGPDlayer_Runtime {
/** Id for dynamic icon used to show annotation color preview for layer. */
int icon_id;
char _pad[4];
+ /** Original layer (used to dereference evaluated data) */
+ struct bGPDlayer *gpl_orig;
} bGPDlayer_Runtime;
/* Grease-Pencil Annotations - 'Layer' */
@@ -355,7 +400,8 @@ typedef struct bGPDlayer {
/** Blend modes. */
int blend_mode;
- char _pad[4];
+ /** Vertex Paint opacity by Layer. */
+ float vertex_paint_opacity;
/* annotation onion skin */
/**
@@ -375,6 +421,12 @@ typedef struct bGPDlayer {
float gcolor_next[3];
char _pad1[4];
+ /** Mask list (bGPDlayer_Mask). */
+ ListBase mask_layers;
+ /** Current Mask index (noted base 1). */
+ int act_mask;
+ char _pad2[4];
+
bGPDlayer_Runtime runtime;
} bGPDlayer;
@@ -388,6 +440,8 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_ACTIVE = (1 << 2),
/* draw points of stroke for debugging purposes */
GP_LAYER_DRAWDEBUG = (1 << 3),
+ /* Flag used to display in Paint mode only layers with keyframe */
+ GP_LAYER_SOLO_MODE = (1 << 4),
/* for editing in Action Editor */
GP_LAYER_SELECT = (1 << 5),
/* current frame for layer can't be changed */
@@ -396,12 +450,12 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_NO_XRAY = (1 << 7),
/* "volumetric" strokes */
GP_LAYER_VOLUMETRIC = (1 << 10),
+ /* Use Scene lights */
+ GP_LAYER_USE_LIGHTS = (1 << 11),
/* Unlock color */
GP_LAYER_UNLOCK_COLOR = (1 << 12),
/* Mask Layer */
- GP_LAYER_USE_MASK = (1 << 13),
- /* Flag used to display in Paint mode only layers with keyframe */
- GP_LAYER_SOLO_MODE = (1 << 4),
+ GP_LAYER_USE_MASK = (1 << 13), /*TODO: DEPRECATED */
/* Ruler Layer */
GP_LAYER_IS_RULER = (1 << 14),
} eGPDlayer_Flag;
@@ -431,18 +485,15 @@ typedef struct bGPdata_Runtime {
struct ARegion *ar;
/** Stroke buffer. */
void *sbuffer;
+ /** Temp batches cleared after drawing. */
+ struct GPUBatch *sbuffer_stroke_batch;
+ struct GPUBatch *sbuffer_fill_batch;
+ /** Temp stroke used for drawing. */
+ struct bGPDstroke *sbuffer_gps;
- /* GP Object drawing */
- /** Buffer stroke color. */
- float scolor[4];
- /** Buffer fill color. */
- float sfill[4];
- /** Settings for color. */
- short mode;
- /** Buffer style for drawing strokes (used to select shader type). */
- short bstroke_style;
- /** Buffer style for filling areas (used to select shader type). */
- short bfill_style;
+ char _pad[2];
+ /** Material index of the stroke. */
+ short matid;
/* Stroke Buffer data (only used during paint-session)
* - buffer must be initialized before use, but freed after
@@ -450,16 +501,26 @@ typedef struct bGPdata_Runtime {
*/
/** Flags for stroke that cache represents. */
short sbuffer_sflag;
+ char _pad1[2];
/** Number of elements currently used in cache. */
int sbuffer_used;
/** Number of total elements available in cache. */
int sbuffer_size;
+ /** Vertex Color applied to point (while drawing). */
+ float vert_color[4];
+
+ /** Vertex Color applied to Fill (while drawing). */
+ float vert_color_fill[4];
+
/** Number of control-points for stroke. */
int tot_cp_points;
- char _pad_[4];
+ char _pad2[4];
/** Array of control-points for stroke. */
bGPDcontrolpoint *cp_points;
+ /** Brush pointer */
+ Brush *sbuffer_brush;
+ struct GpencilBatchCache *gpencil_cache;
} bGPdata_Runtime;
/* grid configuration */
@@ -481,7 +542,7 @@ typedef struct bGPdata {
struct AnimData *adt;
/* Grease-Pencil data */
- /** BGPDlayers. */
+ /** bGPDlayer. */
ListBase layers;
/** Settings for this data-block. */
int flag;
@@ -581,8 +642,6 @@ typedef enum eGPdata_Flag {
/* Main flag to switch onion skinning on/off */
GP_DATA_SHOW_ONIONSKINS = (1 << 9),
- /* Draw a green and red point to indicate start and end of the stroke */
- GP_DATA_SHOW_DIRECTION = (1 << 10),
/* Batch drawing cache need to be recalculated */
GP_DATA_CACHE_IS_DIRTY = (1 << 11),
@@ -600,15 +659,9 @@ typedef enum eGPdata_Flag {
/* Allow edit several frames at the same time */
GP_DATA_STROKE_MULTIEDIT = (1 << 16),
- /* Force fill recalc if use deformation modifiers.
- * this is required if the stroke is deformed and the triangulation data is
- * not valid.
- */
- GP_DATA_STROKE_FORCE_RECALC = (1 << 17),
- /* Special mode drawing polygons */
- GP_DATA_STROKE_POLYGON = (1 << 18),
- /* Use adaptive UV scales */
- GP_DATA_UV_ADAPTIVE = (1 << 19),
+ /* Vertex Paint Mode - Toggle paint mode */
+ GP_DATA_STROKE_VERTEXMODE = (1 << 18),
+
/* Autolock not active layers */
GP_DATA_AUTOLOCK_LAYERS = (1 << 20),
/* Internal flag for python update */
@@ -654,28 +707,38 @@ typedef enum eGP_DrawMode {
/* Check if 'multiedit sessions' is enabled */
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd) \
((gpd) && \
- (gpd->flag & \
- (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)) && \
+ (gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
+ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)) && \
(gpd->flag & GP_DATA_STROKE_MULTIEDIT))
/* Macros to check grease pencil modes */
#define GPENCIL_ANY_MODE(gpd) \
- ((gpd) && (gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | \
- GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
-#define GPENCIL_EDIT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE))
+ ((gpd) && \
+ (gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
+ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)))
+#define GPENCIL_EDIT_MODE(gpd) ((gpd) && ((gpd)->flag & GP_DATA_STROKE_EDITMODE))
#define GPENCIL_ANY_EDIT_MODE(gpd) \
((gpd) && (gpd->flag & \
(GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
#define GPENCIL_PAINT_MODE(gpd) ((gpd) && (gpd->flag & (GP_DATA_STROKE_PAINTMODE)))
#define GPENCIL_SCULPT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_SCULPTMODE))
#define GPENCIL_WEIGHT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE))
+#define GPENCIL_VERTEX_MODE(gpd) ((gpd) && (gpd->flag & (GP_DATA_STROKE_VERTEXMODE)))
#define GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd) \
((gpd) && (gpd->flag & (GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
#define GPENCIL_NONE_EDIT_MODE(gpd) \
((gpd) && ((gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
- GP_DATA_STROKE_WEIGHTMODE)) == 0))
+ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)) == 0))
#define GPENCIL_LAZY_MODE(brush, shift) \
(((brush) && ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) && (shift == 0))) || \
(((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && (shift == 1)))
+#define GPENCIL_ANY_SCULPT_MASK(flag) \
+ ((flag & (GP_SCULPT_MASK_SELECTMODE_POINT | GP_SCULPT_MASK_SELECTMODE_STROKE | \
+ GP_SCULPT_MASK_SELECTMODE_SEGMENT)))
+
+#define GPENCIL_ANY_VERTEX_MASK(flag) \
+ ((flag & (GP_VERTEX_MASK_SELECTMODE_POINT | GP_VERTEX_MASK_SELECTMODE_STROKE | \
+ GP_VERTEX_MASK_SELECTMODE_SEGMENT)))
+
#endif /* __DNA_GPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 1d1ccef8846..0db7feffa99 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -72,15 +72,14 @@ typedef struct MaterialGPencilStyle {
/** Factor used to define shader behavior (several uses). */
float mix_factor;
/** Angle used for gradients orientation. */
- float gradient_angle;
+ float gradient_angle DNA_DEPRECATED;
/** Radius for radial gradients. */
- float gradient_radius;
- /** Cheesboard size. */
- float pattern_gridsize;
+ float gradient_radius DNA_DEPRECATED;
+ char _pad2[4];
/** Uv coordinates scale. */
- float gradient_scale[2];
+ float gradient_scale[2] DNA_DEPRECATED;
/** Factor to shift filling in 2d space. */
- float gradient_shift[2];
+ float gradient_shift[2] DNA_DEPRECATED;
/** Angle used for texture orientation. */
float texture_angle;
/** Texture scale (separated of uv scale). */
@@ -107,35 +106,35 @@ typedef struct MaterialGPencilStyle {
/* MaterialGPencilStyle->flag */
typedef enum eMaterialGPencilStyle_Flag {
/* Fill Texture is a pattern */
- GP_STYLE_FILL_PATTERN = (1 << 0),
+ GP_MATERIAL_FILL_PATTERN = (1 << 0),
/* don't display color */
- GP_STYLE_COLOR_HIDE = (1 << 1),
+ GP_MATERIAL_HIDE = (1 << 1),
/* protected from further editing */
- GP_STYLE_COLOR_LOCKED = (1 << 2),
+ GP_MATERIAL_LOCKED = (1 << 2),
/* do onion skinning */
- GP_STYLE_COLOR_ONIONSKIN = (1 << 3),
+ GP_MATERIAL_ONIONSKIN = (1 << 3),
/* clamp texture */
- GP_STYLE_COLOR_TEX_CLAMP = (1 << 4),
+ GP_MATERIAL_TEX_CLAMP = (1 << 4),
/* mix fill texture */
- GP_STYLE_FILL_TEX_MIX = (1 << 5),
+ GP_MATERIAL_FILL_TEX_MIX = (1 << 5),
/* Flip fill colors */
- GP_STYLE_COLOR_FLIP_FILL = (1 << 6),
+ GP_MATERIAL_FLIP_FILL = (1 << 6),
/* Stroke Texture is a pattern */
- GP_STYLE_STROKE_PATTERN = (1 << 7),
+ GP_MATERIAL_STROKE_PATTERN = (1 << 7),
/* Stroke show main switch */
- GP_STYLE_STROKE_SHOW = (1 << 8),
- /* Fill show main switch */
- GP_STYLE_FILL_SHOW = (1 << 9),
+ GP_MATERIAL_STROKE_SHOW = (1 << 8),
+ /* Fill show main switch */
+ GP_MATERIAL_FILL_SHOW = (1 << 9),
/* mix stroke texture */
- GP_STYLE_STROKE_TEX_MIX = (1 << 11),
+ GP_MATERIAL_STROKE_TEX_MIX = (1 << 11),
/* disable stencil clipping (overlap) */
- GP_STYLE_DISABLE_STENCIL = (1 << 12),
+ GP_MATERIAL_DISABLE_STENCIL = (1 << 12),
} eMaterialGPencilStyle_Flag;
typedef enum eMaterialGPencilStyle_Mode {
- GP_STYLE_MODE_LINE = 0, /* line */
- GP_STYLE_MODE_DOTS = 1, /* dots */
- GP_STYLE_MODE_BOX = 2, /* rectangles */
+ GP_MATERIAL_MODE_LINE = 0,
+ GP_MATERIAL_MODE_DOT = 1,
+ GP_MATERIAL_MODE_SQUARE = 2,
} eMaterialGPencilStyle_Mode;
typedef struct Material {
@@ -332,28 +331,28 @@ enum {
/* Grease Pencil Stroke styles */
enum {
- GP_STYLE_STROKE_STYLE_SOLID = 0,
- GP_STYLE_STROKE_STYLE_TEXTURE,
+ GP_MATERIAL_STROKE_STYLE_SOLID = 0,
+ GP_MATERIAL_STROKE_STYLE_TEXTURE,
};
/* Grease Pencil Fill styles */
enum {
- GP_STYLE_FILL_STYLE_SOLID = 0,
- GP_STYLE_FILL_STYLE_GRADIENT,
- GP_STYLE_FILL_STYLE_CHECKER,
- GP_STYLE_FILL_STYLE_TEXTURE,
+ GP_MATERIAL_FILL_STYLE_SOLID = 0,
+ GP_MATERIAL_FILL_STYLE_GRADIENT,
+ GP_MATERIAL_FILL_STYLE_CHECKER, /* DEPRECATED (only for convert old files) */
+ GP_MATERIAL_FILL_STYLE_TEXTURE,
};
/* Grease Pencil Gradient Types */
enum {
- GP_STYLE_GRADIENT_LINEAR = 0,
- GP_STYLE_GRADIENT_RADIAL,
+ GP_MATERIAL_GRADIENT_LINEAR = 0,
+ GP_MATERIAL_GRADIENT_RADIAL,
};
/* Grease Pencil Follow Drawing Modes */
enum {
- GP_STYLE_FOLLOW_PATH = 0,
- GP_STYLE_FOLLOW_OBJ,
- GP_STYLE_FOLLOW_FIXED,
+ GP_MATERIAL_FOLLOW_PATH = 0,
+ GP_MATERIAL_FOLLOW_OBJ,
+ GP_MATERIAL_FOLLOW_FIXED,
};
#endif
diff --git a/source/blender/makesdna/DNA_object_enums.h b/source/blender/makesdna/DNA_object_enums.h
index c15f32564c4..f3e69161c85 100644
--- a/source/blender/makesdna/DNA_object_enums.h
+++ b/source/blender/makesdna/DNA_object_enums.h
@@ -37,6 +37,7 @@ typedef enum eObjectMode {
OB_MODE_PAINT_GPENCIL = 1 << 8,
OB_MODE_SCULPT_GPENCIL = 1 << 9,
OB_MODE_WEIGHT_GPENCIL = 1 << 10,
+ OB_MODE_VERTEX_GPENCIL = 1 << 11,
} eObjectMode;
/** #Object.dt, #View3DShading.type */
@@ -54,7 +55,8 @@ typedef enum eDrawType {
(OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)
#define OB_MODE_ALL_PAINT_GPENCIL \
- (OB_MODE_PAINT_GPENCIL | OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL)
+ (OB_MODE_PAINT_GPENCIL | OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL | \
+ OB_MODE_VERTEX_GPENCIL)
/** Any mode that uses Object.sculpt. */
#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)
@@ -66,6 +68,6 @@ typedef enum eDrawType {
#define OB_MODE_ALL_MODE_DATA \
(OB_MODE_EDIT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_SCULPT | OB_MODE_POSE | \
OB_MODE_PAINT_GPENCIL | OB_MODE_EDIT_GPENCIL | OB_MODE_SCULPT_GPENCIL | \
- OB_MODE_WEIGHT_GPENCIL)
+ OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL)
#endif /* __DNA_OBJECT_ENUMS_H__ */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 4d15abc3c77..fca74c29909 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -167,6 +167,18 @@ typedef struct Object_Runtime {
struct Mesh *mesh_deform_eval;
/**
+ * Original grease pencil bGPdata pointer, before object->data was changed to point
+ * to gpd_eval.
+ * Is assigned by dependency graph's copy-on-write evaluation.
+ */
+ struct bGPdata *gpd_orig;
+ /**
+ * bGPdata structure created during object evaluation.
+ * It has all modifiers applied.
+ */
+ struct bGPdata *gpd_eval;
+
+ /**
* This is a mesh representation of corresponding object.
* It created when Python calls `object.to_mesh()`.
*/
@@ -175,14 +187,6 @@ typedef struct Object_Runtime {
/** Runtime evaluated curve-specific data, not stored in the file. */
struct CurveCache *curve_cache;
- /** Runtime grease pencil drawing data */
- struct GpencilBatchCache *gpencil_cache;
- /** Runtime grease pencil total layers used for evaluated data created by modifiers */
- int gpencil_tot_layers;
- char _pad4[4];
- /** Runtime grease pencil evaluated data created by modifiers */
- struct bGPDframe *gpencil_evaluated_frames;
-
unsigned short local_collections_bits;
short _pad2[3];
} Object_Runtime;
@@ -542,6 +546,8 @@ enum {
OB_DRAWTRANSP = 1 << 7,
OB_DRAW_ALL_EDGES = 1 << 8, /* only for meshes currently */
OB_DRAW_NO_SHADOW_CAST = 1 << 9,
+ /* Enable lights for grease pencil. */
+ OB_USE_GPENCIL_LIGHTS = 1 << 10,
};
/* empty_drawtype: no flags */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 8617f122d55..3a88cd0a33b 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -999,8 +999,38 @@ typedef struct UvSculpt {
/* grease pencil drawing brushes */
typedef struct GpPaint {
Paint paint;
+ int flag;
+ /* Mode of paint (Materials or Vertex Color). */
+ int mode;
} GpPaint;
+/* GpPaint.flag */
+enum {
+ GPPAINT_FLAG_USE_MATERIAL = 0,
+ GPPAINT_FLAG_USE_VERTEXCOLOR = 1,
+};
+
+/* Grease pencil vertex paint. */
+typedef struct GpVertexPaint {
+ Paint paint;
+ int flag;
+ char _pad[4];
+} GpVertexPaint;
+
+/* Grease pencil sculpt paint. */
+typedef struct GpSculptPaint {
+ Paint paint;
+ int flag;
+ char _pad[4];
+} GpSculptPaint;
+
+/* Grease pencil weight paint. */
+typedef struct GpWeightPaint {
+ Paint paint;
+ int flag;
+ char _pad[4];
+} GpWeightPaint;
+
/* ------------------------------------------- */
/* Vertex Paint */
@@ -1022,27 +1052,6 @@ enum {
/* ------------------------------------------- */
/* GPencil Stroke Sculpting */
-/* GP_Sculpt_Settings.brushtype */
-typedef enum eGP_Sculpt_Types {
- GP_SCULPT_TYPE_SMOOTH = 0,
- GP_SCULPT_TYPE_THICKNESS = 1,
- GP_SCULPT_TYPE_STRENGTH = 2,
- GP_SCULPT_TYPE_GRAB = 3,
- GP_SCULPT_TYPE_PUSH = 4,
- GP_SCULPT_TYPE_TWIST = 5,
- GP_SCULPT_TYPE_PINCH = 6,
- GP_SCULPT_TYPE_RANDOMIZE = 7,
- GP_SCULPT_TYPE_CLONE = 8,
- GP_SCULPT_TYPE_SUBDIVIDE = 9,
- GP_SCULPT_TYPE_SIMPLIFY = 10,
- /* add any sculpt brush above this value */
- GP_SCULPT_TYPE_WEIGHT = 11,
- /* add any weight paint brush below this value. Do no mix brushes */
-
- /* !!! Update GP_Sculpt_Data brush[###]; below !!! */
- GP_SCULPT_TYPE_MAX,
-} eGP_Sculpt_Types;
-
/* GP_Sculpt_Settings.lock_axis */
typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_VIEW = 0,
@@ -1052,23 +1061,6 @@ typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_CURSOR = 4,
} eGP_Lockaxis_Types;
-/* Settings for a GPencil Stroke Sculpting Brush */
-typedef struct GP_Sculpt_Data {
- /** Radius of brush. */
- short size;
- /** EGP_Sculpt_Flag. */
- short flag;
- /** Strength of effect. */
- float strength;
- /** Cursor color for add. */
- float curcolor_add[3];
- /** Cursor color for sub. */
- float curcolor_sub[3];
- /** Target weight. */
- float weight;
- char _pad[4];
-} GP_Sculpt_Data;
-
/* Settings for a GPencil Speed Guide */
typedef struct GP_Sculpt_Guide {
char use_guide;
@@ -1083,48 +1075,17 @@ typedef struct GP_Sculpt_Guide {
struct Object *reference_object;
} GP_Sculpt_Guide;
-/* GP_Sculpt_Data.flag */
-typedef enum eGP_Sculpt_Flag {
- /* invert the effect of the brush */
- GP_SCULPT_FLAG_INVERT = (1 << 0),
- /* adjust strength using pen pressure */
- GP_SCULPT_FLAG_USE_PRESSURE = (1 << 1),
-
- /* strength of brush falls off with distance from cursor */
- GP_SCULPT_FLAG_USE_FALLOFF = (1 << 2),
-
- /* smooth brush affects pressure values as well */
- GP_SCULPT_FLAG_SMOOTH_PRESSURE = (1 << 3),
- /* enable screen cursor */
- GP_SCULPT_FLAG_ENABLE_CURSOR = (1 << 4),
- /* temporary invert action */
- GP_SCULPT_FLAG_TMP_INVERT = (1 << 5),
- /* adjust radius using pen pressure */
- GP_SCULPT_FLAG_PRESSURE_RADIUS = (1 << 6),
-} eGP_Sculpt_Flag;
-
/* GPencil Stroke Sculpting Settings */
typedef struct GP_Sculpt_Settings {
- /** GP_SCULPT_TYPE_MAX. */
- GP_Sculpt_Data brush[12];
/** Runtime. */
void *paintcursor;
-
- /** #eGP_Sculpt_Types (sculpt). */
- int brushtype;
/** #eGP_Sculpt_SettingsFlag. */
int flag;
/** #eGP_Lockaxis_Types lock drawing to one axis. */
int lock_axis;
/** Threshold for intersections */
float isect_threshold;
-
- /* weight paint is a submode of sculpt but use its own index. All weight paint
- * brushes must be defined at the end of the brush array.
- */
- /** #eGP_Sculpt_Types (weight paint). */
- int weighttype;
- char _pad[4];
+ char _pad_[4];
/** Multiframe edit falloff effect by frame. */
struct CurveMapping *cur_falloff;
/** Curve used for primitive tools. */
@@ -1135,22 +1096,12 @@ typedef struct GP_Sculpt_Settings {
/* GP_Sculpt_Settings.flag */
typedef enum eGP_Sculpt_SettingsFlag {
- /* only affect selected points */
- GP_SCULPT_SETT_FLAG_DEPRECATED = (1 << 0),
- /* apply brush to position */
- GP_SCULPT_SETT_FLAG_APPLY_POSITION = (1 << 1),
- /* apply brush to strength */
- GP_SCULPT_SETT_FLAG_APPLY_STRENGTH = (1 << 2),
- /* apply brush to thickness */
- GP_SCULPT_SETT_FLAG_APPLY_THICKNESS = (1 << 3),
- /* apply brush to thickness */
- GP_SCULPT_SETT_FLAG_WEIGHT_MODE = (1 << 4),
/* enable falloff for multiframe editing */
- GP_SCULPT_SETT_FLAG_FRAME_FALLOFF = (1 << 5),
- /* apply brush to uv data */
- GP_SCULPT_SETT_FLAG_APPLY_UV = (1 << 6),
+ GP_SCULPT_SETT_FLAG_FRAME_FALLOFF = (1 << 0),
/* apply primitive curve */
- GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE = (1 << 7),
+ GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE = (1 << 1),
+ /* Scale thickness. */
+ GP_SCULPT_SETT_FLAG_SCALE_THICKNESS = (1 << 3),
} eGP_Sculpt_SettingsFlag;
/* GP_Sculpt_Settings.gpencil_selectmode_sculpt */
@@ -1163,6 +1114,16 @@ typedef enum eGP_Sculpt_SelectMaskFlag {
GP_SCULPT_MASK_SELECTMODE_SEGMENT = (1 << 2),
} eGP_Sculpt_SelectMaskFlag;
+/* GP_Sculpt_Settings.gpencil_selectmode_vertex */
+typedef enum eGP_vertex_SelectMaskFlag {
+ /* only affect selected points */
+ GP_VERTEX_MASK_SELECTMODE_POINT = (1 << 0),
+ /* only affect selected strokes */
+ GP_VERTEX_MASK_SELECTMODE_STROKE = (1 << 1),
+ /* only affect selected segmenst */
+ GP_VERTEX_MASK_SELECTMODE_SEGMENT = (1 << 2),
+} eGP_Vertex_SelectMaskFlag;
+
/* Settings for GP Interpolation Operators */
typedef struct GP_Interpolate_Settings {
/** #eGP_Interpolate_SettingsFlag. */
@@ -1395,6 +1356,12 @@ typedef struct ToolSettings {
UvSculpt *uvsculpt;
/** Gpencil paint. */
GpPaint *gp_paint;
+ /** Gpencil vertex paint. */
+ GpVertexPaint *gp_vertexpaint;
+ /** Gpencil sculpt paint. */
+ GpSculptPaint *gp_sculptpaint;
+ /** Gpencil weight paint. */
+ GpWeightPaint *gp_weightpaint;
/* Vertex group weight - used only for editmode, not weight
* paint */
@@ -1508,8 +1475,11 @@ typedef struct ToolSettings {
/** Subset selection filter in wpaint. */
char vgroupsubset;
+ /** Stroke selection mode for Vertex Paint. */
+ char gpencil_selectmode_vertex;
+
/* UV painting */
- char _pad2[3];
+ char _pad2[2];
char uv_sculpt_settings;
char uv_relax_method;
/* XXX: these sculpt_paint_* fields are deprecated, use the
@@ -2289,14 +2259,12 @@ typedef enum eGPencil_SimplifyFlags {
SIMPLIFY_GPENCIL_FILL = (1 << 2),
/* Simplify modifier on viewport */
SIMPLIFY_GPENCIL_MODIFIER = (1 << 3),
- /* Remove fill external line */
- SIMPLIFY_GPENCIL_REMOVE_FILL_LINE = (1 << 4),
/* Simplify Shader FX */
SIMPLIFY_GPENCIL_FX = (1 << 5),
- /* Simplify layer blending */
- SIMPLIFY_GPENCIL_BLEND = (1 << 6),
/* Simplify layer tint */
SIMPLIFY_GPENCIL_TINT = (1 << 7),
+ /* Simplify Antialiasing */
+ SIMPLIFY_GPENCIL_AA = (1 << 8),
} eGPencil_SimplifyFlags;
/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index 6cda58a3279..e0931d8cac3 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -34,7 +34,7 @@ typedef enum ShaderFxType {
eShaderFxType_None = 0,
eShaderFxType_Blur = 1,
eShaderFxType_Flip = 2,
- eShaderFxType_Light = 3,
+ eShaderFxType_Light_deprecated = 3, /* DEPRECATED (replaced by scene lights) */
eShaderFxType_Pixel = 4,
eShaderFxType_Swirl = 5,
eShaderFxType_Wave = 6,
@@ -81,15 +81,13 @@ typedef struct ShaderFxData_Runtime {
typedef struct BlurShaderFxData {
ShaderFxData shaderfx;
- int radius[2];
+ float radius[2];
/** Flags. */
int flag;
/** Number of samples. */
int samples;
- /** Circle of confusion. */
- float coc;
- /** Not visible in rna. */
- int blur[2];
+ /** Rotation of blur effect. */
+ float rotation;
char _pad[4];
ShaderFxData_Runtime runtime;
@@ -136,14 +134,20 @@ typedef enum eFlipShaderFx_Flag {
typedef struct GlowShaderFxData {
ShaderFxData shaderfx;
- float glow_color[3];
+ float glow_color[4];
float select_color[3];
float threshold;
/** Flags. */
int flag;
int mode;
- int blur[2];
+ float blur[2];
int samples;
+ /** Rotation of effect. */
+ float rotation;
+ /** Blend modes. */
+ int blend_mode;
+ char _pad[4];
+
ShaderFxData_Runtime runtime;
} GlowShaderFxData;
@@ -156,19 +160,6 @@ typedef enum eGlowShaderFx_Flag {
FX_GLOW_USE_ALPHA = (1 << 0),
} eGlowShaderFx_Flag;
-typedef struct LightShaderFxData {
- ShaderFxData shaderfx;
- struct Object *object;
- /** Flags. */
- int flag;
- float energy;
- float ambient;
- /** Internal, not visible in rna. */
- float loc[4];
- char _pad[4];
- ShaderFxData_Runtime runtime;
-} LightShaderFxData;
-
typedef struct PixelShaderFxData {
ShaderFxData shaderfx;
/** Last element used for shader only. */
@@ -179,10 +170,6 @@ typedef struct PixelShaderFxData {
ShaderFxData_Runtime runtime;
} PixelShaderFxData;
-typedef enum ePixelShaderFx_Flag {
- FX_PIXEL_USE_LINES = (1 << 0),
-} ePixelShaderFx_Flag;
-
typedef struct RimShaderFxData {
ShaderFxData shaderfx;
int offset[2];
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index b3f82bc1269..6961a9e9c3e 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -853,8 +853,7 @@ typedef struct UserDef {
short pie_menu_threshold;
short opensubdiv_compute_type;
- /** #eMultiSample_Type, amount of samples for Grease Pencil. */
- short gpencil_multisamples;
+ short _pad6;
char factor_display_type;
@@ -1228,7 +1227,7 @@ typedef enum eNdof_Flag {
#define NDOF_PIXELS_PER_SECOND 600.0f
-/** UserDef.ogl_multisamples and gpencil_multisamples */
+/** UserDef.ogl_multisamples */
typedef enum eMultiSample_Type {
USER_MULTISAMPLE_NONE = 0,
USER_MULTISAMPLE_2 = 2,
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 67ef1b35f9d..edc86a4b0ea 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -224,6 +224,9 @@ typedef struct View3DOverlay {
float gpencil_grid_opacity;
float gpencil_fade_layer;
+ /** Factor for mixing vertex paint with original color */
+ float gpencil_vertex_paint_opacity;
+ char _pad4[4];
} View3DOverlay;
typedef struct View3D_Runtime {
@@ -415,13 +418,15 @@ enum {
#define V3D_FLAG2_UNUSED_15 (1 << 15) /* cleared */
/** #View3D.gp_flag (short) */
-#define V3D_GP_SHOW_PAPER (1 << 0) /* Activate paper to cover all viewport */
-#define V3D_GP_SHOW_GRID (1 << 1) /* Activate paper grid */
+#define V3D_GP_FADE_OBJECTS (1 << 0) /* Fade all non GP objects */
+#define V3D_GP_SHOW_GRID (1 << 1) /* Activate paper grid */
#define V3D_GP_SHOW_EDIT_LINES (1 << 2)
#define V3D_GP_SHOW_MULTIEDIT_LINES (1 << 3)
#define V3D_GP_SHOW_ONION_SKIN (1 << 4) /* main switch at view level */
#define V3D_GP_FADE_NOACTIVE_LAYERS (1 << 5) /* fade layers not active */
#define V3D_GP_FADE_NOACTIVE_GPENCIL (1 << 6) /* Fade other GPencil objects */
+#define V3D_GP_SHOW_STROKE_DIRECTION (1 << 7) /* Show Strokes Directions */
+#define V3D_GP_SHOW_MATERIAL_NAME (1 << 8) /* Show Material names */
/** #View3DShading.flag */
enum {
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 1ae7ad6bc70..678baef3cef 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -110,3 +110,7 @@ DNA_STRUCT_RENAME_ELEM(bTheme, ttopbar, space_topbar)
DNA_STRUCT_RENAME_ELEM(bTheme, tuserpref, space_preferences)
DNA_STRUCT_RENAME_ELEM(bTheme, tv3d, space_view3d)
DNA_STRUCT_RENAME_ELEM(ThemeSpace, show_back_grad, background_type)
+DNA_STRUCT_RENAME_ELEM(bGPDstroke, gradient_f, hardeness)
+DNA_STRUCT_RENAME_ELEM(bGPDstroke, gradient_s, aspect_ratio)
+DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_f, hardeness)
+DNA_STRUCT_RENAME_ELEM(BrushGpencilSettings, gradient_s, aspect_ratio)
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 41858fffcf5..fa8cf6903ad 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -666,6 +666,7 @@ extern StructRNA RNA_UVWarpModifier;
extern StructRNA RNA_UnitSettings;
extern StructRNA RNA_UnknownType;
extern StructRNA RNA_UserSolidLight;
+extern StructRNA RNA_VertexcolorGpencilModifier;
extern StructRNA RNA_VectorFont;
extern StructRNA RNA_VertexGroup;
extern StructRNA RNA_VertexGroupElement;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index c10436ae08e..fef98f9da4b 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -122,12 +122,13 @@ extern const EnumPropertyItem rna_enum_brush_uv_sculpt_tool_items[];
extern const EnumPropertyItem rna_enum_brush_vertex_tool_items[];
extern const EnumPropertyItem rna_enum_brush_weight_tool_items[];
extern const EnumPropertyItem rna_enum_brush_gpencil_types_items[];
+extern const EnumPropertyItem rna_enum_brush_gpencil_vertex_types_items[];
+extern const EnumPropertyItem rna_enum_brush_gpencil_sculpt_types_items[];
+extern const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[];
extern const EnumPropertyItem rna_enum_brush_image_tool_items[];
extern const EnumPropertyItem rna_enum_particle_edit_hair_brush_items[];
extern const EnumPropertyItem rna_enum_particle_edit_disconnected_hair_brush_items[];
-extern const EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[];
-extern const EnumPropertyItem rna_enum_gpencil_weight_brush_items[];
extern const EnumPropertyItem rna_enum_uv_sculpt_tool_items[];
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index c2dbb2973a3..39216009e34 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -149,6 +149,73 @@ const EnumPropertyItem rna_enum_brush_gpencil_types_items[] = {
ICON_PANEL_CLOSE,
"Erase",
"The brush is used for erasing strokes"},
+ {GPAINT_TOOL_TINT,
+ "TINT",
+ ICON_BRUSH_TEXDRAW,
+ "Tint",
+ "The brush is of type used for tinting strokes"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_brush_gpencil_vertex_types_items[] = {
+ {GPVERTEX_TOOL_DRAW, "DRAW", ICON_BRUSH_MIX, "Draw", ""},
+ {GPVERTEX_TOOL_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""},
+ {GPVERTEX_TOOL_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""},
+ {GPVERTEX_TOOL_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""},
+ {GPVERTEX_TOOL_REPLACE, "REPLACE", ICON_BRUSH_BLUR, "Replace", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_brush_gpencil_sculpt_types_items[] = {
+ {GPSCULPT_TOOL_SMOOTH, "SMOOTH", ICON_GPBRUSH_SMOOTH, "Smooth", "Smooth stroke points"},
+ {GPSCULPT_TOOL_THICKNESS,
+ "THICKNESS",
+ ICON_GPBRUSH_THICKNESS,
+ "Thickness",
+ "Adjust thickness of strokes"},
+ {GPSCULPT_TOOL_STRENGTH,
+ "STRENGTH",
+ ICON_GPBRUSH_STRENGTH,
+ "Strength",
+ "Adjust color strength of strokes"},
+ {GPSCULPT_TOOL_RANDOMIZE,
+ "RANDOMIZE",
+ ICON_GPBRUSH_RANDOMIZE,
+ "Randomize",
+ "Introduce jitter/randomness into strokes"},
+ {GPSCULPT_TOOL_GRAB,
+ "GRAB",
+ ICON_GPBRUSH_GRAB,
+ "Grab",
+ "Translate the set of points initially within the brush circle"},
+ {GPSCULPT_TOOL_PUSH,
+ "PUSH",
+ ICON_GPBRUSH_PUSH,
+ "Push",
+ "Move points out of the way, as if combing them"},
+ {GPSCULPT_TOOL_TWIST,
+ "TWIST",
+ ICON_GPBRUSH_TWIST,
+ "Twist",
+ "Rotate points around the midpoint of the brush"},
+ {GPSCULPT_TOOL_PINCH,
+ "PINCH",
+ ICON_GPBRUSH_PINCH,
+ "Pinch",
+ "Pull points towards the midpoint of the brush"},
+ {GPSCULPT_TOOL_CLONE,
+ "CLONE",
+ ICON_GPBRUSH_CLONE,
+ "Clone",
+ "Paste copies of the strokes stored on the clipboard"},
+ {0, NULL, 0, NULL, NULL}};
+
+const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[] = {
+ {GPWEIGHT_TOOL_DRAW,
+ "WEIGHT",
+ ICON_GPBRUSH_WEIGHT,
+ "Weight",
+ "Weight Paint for Vertex Groups"},
{0, NULL, 0, NULL, NULL},
};
@@ -174,7 +241,7 @@ static EnumPropertyItem rna_enum_gpencil_fill_draw_modes_items[] = {
{GP_FILL_DMODE_CONTROL, "CONTROL", 0, "Edit Lines", "Use edit lines as fill boundary limits"},
{0, NULL, 0, NULL, NULL}};
-static EnumPropertyItem rna_enum_gpencil_brush_icons_items[] = {
+static EnumPropertyItem rna_enum_gpencil_brush_paint_icons_items[] = {
{GP_BRUSH_ICON_PENCIL, "PENCIL", ICON_GPBRUSH_PENCIL, "Pencil", ""},
{GP_BRUSH_ICON_PEN, "PEN", ICON_GPBRUSH_PEN, "Pen", ""},
{GP_BRUSH_ICON_INK, "INK", ICON_GPBRUSH_INK, "Ink", ""},
@@ -189,6 +256,32 @@ static EnumPropertyItem rna_enum_gpencil_brush_icons_items[] = {
{GP_BRUSH_ICON_ERASE_STROKE, "STROKE", ICON_GPBRUSH_ERASE_STROKE, "Eraser Stroke", ""},
{0, NULL, 0, NULL, NULL},
};
+
+static EnumPropertyItem rna_enum_gpencil_brush_sculpt_icons_items[] = {
+ {GP_BRUSH_ICON_GPBRUSH_SMOOTH, "SMOOTH", ICON_GPBRUSH_SMOOTH, "Smooth", ""},
+ {GP_BRUSH_ICON_GPBRUSH_THICKNESS, "THICKNESS", ICON_GPBRUSH_THICKNESS, "Thickness", ""},
+ {GP_BRUSH_ICON_GPBRUSH_STRENGTH, "STRENGTH", ICON_GPBRUSH_STRENGTH, "Strength", ""},
+ {GP_BRUSH_ICON_GPBRUSH_RANDOMIZE, "RANDOMIZE", ICON_GPBRUSH_RANDOMIZE, "Randomize", ""},
+ {GP_BRUSH_ICON_GPBRUSH_GRAB, "GRAB", ICON_GPBRUSH_GRAB, "Grab", ""},
+ {GP_BRUSH_ICON_GPBRUSH_PUSH, "PUSH", ICON_GPBRUSH_PUSH, "Push", ""},
+ {GP_BRUSH_ICON_GPBRUSH_TWIST, "TWIST", ICON_GPBRUSH_TWIST, "Twist", ""},
+ {GP_BRUSH_ICON_GPBRUSH_PINCH, "PINCH", ICON_GPBRUSH_PINCH, "Pinch", ""},
+ {GP_BRUSH_ICON_GPBRUSH_CLONE, "CLONE", ICON_GPBRUSH_CLONE, "Clone", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static EnumPropertyItem rna_enum_gpencil_brush_weight_icons_items[] = {
+ {GP_BRUSH_ICON_GPBRUSH_WEIGHT, "DRAW", ICON_GPBRUSH_WEIGHT, "Draw", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+static EnumPropertyItem rna_enum_gpencil_brush_vertex_icons_items[] = {
+ {GP_BRUSH_ICON_VERTEX_DRAW, "DRAW", ICON_BRUSH_MIX, "Draw", ""},
+ {GP_BRUSH_ICON_VERTEX_BLUR, "BLUR", ICON_BRUSH_BLUR, "Blur", ""},
+ {GP_BRUSH_ICON_VERTEX_AVERAGE, "AVERAGE", ICON_BRUSH_BLUR, "Average", ""},
+ {GP_BRUSH_ICON_VERTEX_SMEAR, "SMEAR", ICON_BRUSH_BLUR, "Smear", ""},
+ {GP_BRUSH_ICON_VERTEX_REPLACE, "REPLACE", ICON_BRUSH_MIX, "Replace", ""},
+ {0, NULL, 0, NULL, NULL},
+};
#endif
#ifdef RNA_RUNTIME
@@ -1072,19 +1165,19 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ /* modes */
+ static EnumPropertyItem gppaint_mode_types_items[] = {
+ {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"},
+ {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"},
+ {GPPAINT_MODE_BOTH, "BOTH", 0, "Both", "Vertex Color affects to Stroke and Fill"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "BrushGpencilSettings", NULL);
RNA_def_struct_sdna(srna, "BrushGpencilSettings");
RNA_def_struct_path_func(srna, "rna_BrushGpencilSettings_path");
RNA_def_struct_ui_text(srna, "Grease Pencil Brush Settings", "Settings for grease pencil brush");
- /* Sensitivity factor for new strokes */
- prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity");
- RNA_def_property_range(prop, 0.1f, 3.0f);
- RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
/* Strength factor for new strokes */
prop = RNA_def_property(srna, "pen_strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "draw_strength");
@@ -1121,15 +1214,6 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Randomnes factor for subdivision */
- prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "draw_random_sub");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(
- prop, "Random Subdivision", "Randomness factor for new strokes after subdivision");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
/* Angle when brush is full size */
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "draw_angle");
@@ -1171,27 +1255,6 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- /* Thickness smoothing factor for new strokes */
- prop = RNA_def_property(srna, "pen_thick_smooth_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "thick_smoothfac");
- RNA_def_property_range(prop, 0.0, 2.0f);
- RNA_def_property_ui_text(prop,
- "Smooth Thickness",
- "Amount of thickness smoothing to apply after finish newly created "
- "strokes, to reduce jitter/noise");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- /* Thickness iterations of the Smoothing factor */
- prop = RNA_def_property(srna, "pen_thick_smooth_steps", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "thick_smoothlvl");
- RNA_def_property_range(prop, 1, 3);
- RNA_def_property_ui_text(prop,
- "Iterations Thickness",
- "Number of times to smooth thickness for newly created strokes");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
/* Subdivision level for new strokes */
prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "draw_subdivide");
@@ -1278,22 +1341,21 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* gradient control */
- prop = RNA_def_property(srna, "gradient_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "gradient_f");
+ prop = RNA_def_property(srna, "hardeness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "hardeness");
RNA_def_property_range(prop, 0.001f, 1.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop,
- "Border Opacity Factor",
- "Amount of gradient for Dot and Box strokes (set to 1 for full solid)");
+ RNA_def_property_ui_text(
+ prop, "Hardeness", "Amount of gradient for Dot and Box strokes (set to 1 for full solid)");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
/* gradient shape ratio */
- prop = RNA_def_property(srna, "gradient_shape", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "gradient_s");
+ prop = RNA_def_property(srna, "aspect", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "aspect_ratio");
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.01f, 1.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Aspect Ratio", "");
+ RNA_def_property_ui_text(prop, "Aspect", "");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_NONE);
@@ -1331,12 +1393,45 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* brush standard icon */
- prop = RNA_def_property(srna, "gp_icon", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "gpencil_paint_icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "icon_id");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_paint_icons_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Grease Pencil Icon", "");
+
+ prop = RNA_def_property(srna, "gpencil_sculpt_icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "icon_id");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_sculpt_icons_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Grease Pencil Icon", "");
+
+ prop = RNA_def_property(srna, "gpencil_weight_icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "icon_id");
- RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_icons_items);
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_weight_icons_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Grease Pencil Icon", "");
+ prop = RNA_def_property(srna, "gpencil_vertex_icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "icon_id");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_vertex_icons_items);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Grease Pencil Icon", "");
+
+ /* Mode type. */
+ prop = RNA_def_property(srna, "vertex_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "vertex_mode");
+ RNA_def_property_enum_items(prop, gppaint_mode_types_items);
+ RNA_def_property_ui_text(prop, "Mode Type", "Defines how vertex color affect to the strokes");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ /* Vertex Color mix factor. */
+ prop = RNA_def_property(srna, "vertex_color_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "vertex_factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(
+ prop, "Vertex Color Factor", "Factor used to mix vertex color to get final color");
+
/* Flags */
prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
@@ -1369,12 +1464,6 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
"override while drawing");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_ENABLE_CURSOR);
- RNA_def_property_boolean_default(prop, true);
- RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
prop = RNA_def_property(srna, "eraser_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "eraser_mode");
RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_eraser_modes_items);
@@ -1395,6 +1484,47 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Trim Stroke Ends", "Trim intersecting stroke ends");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ prop = RNA_def_property(srna, "use_edit_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_flag", GP_SCULPT_FLAG_SMOOTH_PRESSURE);
+ RNA_def_property_ui_text(
+ prop, "Affect Pressure", "Affect pressure values as well when smoothing strokes");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "sculpt_flag");
+ RNA_def_property_enum_items(prop, prop_direction_items);
+ RNA_def_property_ui_text(prop, "Direction", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_edit_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_APPLY_POSITION);
+ RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_edit_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_APPLY_STRENGTH);
+ RNA_def_property_ui_text(
+ prop, "Affect Strength", "The brush affects the color strength of the point");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_edit_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_APPLY_THICKNESS);
+ RNA_def_property_ui_text(
+ prop, "Affect Thickness", "The brush affects the thickness of the point");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_edit_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_mode_flag", GP_SCULPT_FLAGMODE_APPLY_UV);
+ RNA_def_property_ui_text(prop, "Affect UV", "The brush affects the UV rotation of the point");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* Material */
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
@@ -1713,6 +1843,25 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_enum_items(prop, rna_enum_brush_gpencil_types_items);
RNA_def_property_ui_text(prop, "Grease Pencil Draw Tool", "");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "gpencil_vertex_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gpencil_vertex_tool");
+ RNA_def_property_enum_items(prop, rna_enum_brush_gpencil_vertex_types_items);
+ RNA_def_property_ui_text(prop, "Grease Pencil Vertex Paint Tool", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "gpencil_sculpt_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gpencil_sculpt_tool");
+ RNA_def_property_enum_items(prop, rna_enum_brush_gpencil_sculpt_types_items);
+ RNA_def_property_ui_text(prop, "Grease Pencil Sculpt Paint Tool", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "gpencil_weight_tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gpencil_weight_tool");
+ RNA_def_property_enum_items(prop, rna_enum_brush_gpencil_weight_types_items);
+ RNA_def_property_ui_text(prop, "Grease Pencil Weight Paint Tool", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
/** End per mode tool properties. */
prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
@@ -2443,7 +2592,12 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_paint_grease_pencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_PAINT_GPENCIL);
- RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in grease pencil drawing mode");
+ RNA_def_property_ui_text(prop, "Use Paint", "Use this brush in grease pencil drawing mode");
+
+ prop = RNA_def_property(srna, "use_vertex_grease_pencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_VERTEX_GPENCIL);
+ RNA_def_property_ui_text(
+ prop, "Use Vertex", "Use this brush in grease pencil vertex color mode");
/* texture */
prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index 579dd92b703..c4c54aac2c6 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -52,6 +52,7 @@ const EnumPropertyItem rna_enum_context_mode_items[] = {
{CTX_MODE_EDIT_GPENCIL, "EDIT_GPENCIL", 0, "Grease Pencil Edit", ""},
{CTX_MODE_SCULPT_GPENCIL, "SCULPT_GPENCIL", 0, "Grease Pencil Sculpt", ""},
{CTX_MODE_WEIGHT_GPENCIL, "WEIGHT_GPENCIL", 0, "Grease Pencil Weight Paint", ""},
+ {CTX_MODE_VERTEX_GPENCIL, "VERTEX_GPENCIL", 0, "Grease Pencil Vertex Paint", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 17163095d4b..e828d9d3d95 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -141,6 +141,7 @@ static EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = {
# include "BKE_icons.h"
# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_build.h"
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
@@ -148,6 +149,28 @@ static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
+static void rna_GPencil_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_TRANSFORM);
+ DEG_relations_tag_update(bmain);
+ WM_main_add_notifier(NC_OBJECT | ND_PARENT, ptr->owner_id);
+
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
+static void rna_GPencil_uv_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ /* Force to recalc the UVs. */
+ bGPDstroke *gps = (bGPDstroke *)ptr->data;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+}
+
static void rna_GPencil_autolock(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->owner_id;
@@ -167,25 +190,6 @@ static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene
WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL);
}
-/* Recalc UVs and Fill for all strokes. */
-static void rna_GPencil_strokes_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- bGPdata *gpd = (bGPdata *)ptr->owner_id;
- 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) {
- BKE_gpencil_triangulate_stroke_fill(gpd, gps);
- }
- }
- }
- }
-
- /* Now do standard updates... */
- DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
-}
-
/* Poll Callback to filter GP Datablocks to only show those for Annotations */
bool rna_GPencil_datablocks_annotations_poll(PointerRNA *UNUSED(ptr), const PointerRNA value)
{
@@ -294,6 +298,42 @@ static void rna_GPencilLayer_parent_bone_set(PointerRNA *ptr, const char *value)
}
}
+static char *rna_GPencilLayerMask_path(PointerRNA *ptr)
+{
+ bGPdata *gpd = (bGPdata *)ptr->owner_id;
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ bGPDlayer_Mask *mask = (bGPDlayer_Mask *)ptr->data;
+
+ char name_layer[sizeof(gpl->info) * 2];
+ char name_mask[sizeof(mask->name) * 2];
+
+ BLI_strescape(name_layer, gpl->info, sizeof(name_layer));
+ BLI_strescape(name_mask, mask->name, sizeof(name_mask));
+
+ return BLI_sprintfN("layers[\"%s\"].mask_layers[\"%s\"]", name_layer, name_mask);
+}
+
+static int rna_GPencil_active_mask_index_get(PointerRNA *ptr)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+ return gpl->act_mask - 1;
+}
+
+static void rna_GPencil_active_mask_index_set(PointerRNA *ptr, int value)
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+ gpl->act_mask = value + 1;
+}
+
+static void rna_GPencil_active_mask_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ bGPDlayer *gpl = (bGPDlayer *)ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&gpl->mask_layers) - 1);
+}
+
/* parent types enum */
static const EnumPropertyItem *rna_Object_parent_type_itemf(bContext *UNUSED(C),
PointerRNA *ptr,
@@ -383,7 +423,7 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr,
static int rna_GPencil_active_layer_index_get(PointerRNA *ptr)
{
bGPdata *gpd = (bGPdata *)ptr->owner_id;
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
return BLI_findindex(&gpd->layers, gpl);
}
@@ -393,7 +433,7 @@ static void rna_GPencil_active_layer_index_set(PointerRNA *ptr, int value)
bGPdata *gpd = (bGPdata *)ptr->owner_id;
bGPDlayer *gpl = BLI_findlink(&gpd->layers, value);
- BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_active_set(gpd, gpl);
/* Now do standard updates... */
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
@@ -433,7 +473,8 @@ static const EnumPropertyItem *rna_GPencil_active_layer_itemf(bContext *C,
item_tmp.name = gpl->info;
item_tmp.value = i;
- item_tmp.icon = BKE_icon_gplayer_color_ensure(gpl);
+ item_tmp.icon = (gpd->flag & GP_DATA_ANNOTATIONS) ? BKE_icon_gplayer_color_ensure(gpl) :
+ ICON_GREASEPENCIL;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
@@ -460,6 +501,45 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
/* now fix animation paths */
BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info);
+
+ /* Fix mask layers. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl_, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_->mask_layers) {
+ if (STREQ(mask->name, oldname)) {
+ BLI_strncpy(mask->name, gpl->info, sizeof(mask->name));
+ }
+ }
+ }
+}
+
+static void rna_GPencilLayer_mask_info_set(PointerRNA *ptr, const char *value)
+{
+ bGPdata *gpd = (bGPdata *)ptr->owner_id;
+ bGPDlayer_Mask *mask = ptr->data;
+ char oldname[128] = "";
+ BLI_strncpy(oldname, mask->name, sizeof(oldname));
+
+ /* Really is changing the layer name. */
+ bGPDlayer *gpl = BKE_gpencil_layer_named_get(gpd, oldname);
+ if (gpl) {
+ /* copy the new name into the name slot */
+ BLI_strncpy_utf8(gpl->info, value, sizeof(gpl->info));
+
+ BLI_uniquename(
+ &gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+
+ /* now fix animation paths */
+ BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info);
+
+ /* Fix mask layers. */
+ LISTBASE_FOREACH (bGPDlayer *, gpl_, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDlayer_Mask *, mask_, &gpl_->mask_layers) {
+ if (STREQ(mask_->name, oldname)) {
+ BLI_strncpy(mask_->name, gpl->info, sizeof(mask_->name));
+ }
+ }
+ }
+ }
}
static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd,
@@ -558,7 +638,8 @@ static void rna_GPencil_stroke_point_add(
stroke->totpoints += count;
- stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(stroke);
gpd->flag |= GP_DATA_PYTHON_UPDATED;
DEG_id_tag_update(&gpd->id,
@@ -619,7 +700,8 @@ static void rna_GPencil_stroke_point_pop(ID *id,
MEM_freeN(pt_dvert);
}
- stroke->flag |= GP_STROKE_RECALC_GEOMETRY;
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(stroke);
gpd->flag |= GP_DATA_PYTHON_UPDATED;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
@@ -630,8 +712,9 @@ static void rna_GPencil_stroke_point_pop(ID *id,
static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame)
{
bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- stroke->gradient_f = 1.0f;
- ARRAY_SET_ITEMS(stroke->gradient_s, 1.0f, 1.0f);
+ stroke->hardeness = 1.0f;
+ ARRAY_SET_ITEMS(stroke->aspect_ratio, 1.0f, 1.0f);
+ stroke->uv_scale = 1.0f;
BLI_addtail(&frame->strokes, stroke);
return stroke;
@@ -665,7 +748,7 @@ static void rna_GPencil_stroke_close(ID *id,
return;
}
- BKE_gpencil_close_stroke(stroke);
+ BKE_gpencil_stroke_close(stroke);
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -703,14 +786,14 @@ static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer,
{
bGPDframe *frame;
- if (BKE_gpencil_layer_find_frame(layer, frame_number)) {
+ if (BKE_gpencil_layer_frame_find(layer, frame_number)) {
BKE_reportf(reports, RPT_ERROR, "Frame already exists on this frame number %d", frame_number);
return NULL;
}
frame = BKE_gpencil_frame_addnew(layer, frame_number);
if (active) {
- layer->actframe = BKE_gpencil_layer_getframe(layer, frame_number, GP_GETFRAME_USE_PREV);
+ layer->actframe = BKE_gpencil_layer_frame_get(layer, frame_number, GP_GETFRAME_USE_PREV);
}
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
@@ -725,7 +808,7 @@ static void rna_GPencil_frame_remove(bGPDlayer *layer, ReportList *reports, Poin
return;
}
- BKE_gpencil_layer_delframe(layer, frame);
+ BKE_gpencil_layer_frame_delete(layer, frame);
RNA_POINTER_INVALIDATE(frame_ptr);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
@@ -735,7 +818,7 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
{
bGPDframe *frame = BKE_gpencil_frame_duplicate(src);
- while (BKE_gpencil_layer_find_frame(layer, frame->framenum)) {
+ while (BKE_gpencil_layer_frame_find(layer, frame->framenum)) {
frame->framenum++;
}
@@ -791,6 +874,31 @@ static void rna_GPencil_layer_move(bGPdata *gpd,
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
+static void rna_GPencil_layer_mask_add(bGPDlayer *gpl, PointerRNA *layer_ptr)
+{
+ bGPDlayer *gpl_mask = layer_ptr->data;
+
+ BKE_gpencil_layer_mask_add(gpl, gpl_mask->info);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
+static void rna_GPencil_layer_mask_remove(bGPDlayer *gpl,
+ ReportList *reports,
+ PointerRNA *mask_ptr)
+{
+ bGPDlayer_Mask *mask = mask_ptr->data;
+ if (BLI_findindex(&gpl->mask_layers, mask) == -1) {
+ BKE_report(reports, RPT_ERROR, "Mask not found in mask list");
+ return;
+ }
+
+ BKE_gpencil_layer_mask_remove(gpl, mask);
+ RNA_POINTER_INVALIDATE(mask_ptr);
+
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
static void rna_GPencil_frame_clear(bGPDframe *frame)
{
BKE_gpencil_free_strokes(frame);
@@ -879,6 +987,16 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set");
RNA_def_property_ui_text(prop, "Select", "Point is selected for viewport editing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Vertex color. */
+ prop = RNA_def_property(srna, "vertex_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "vert_color");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(
+ prop, "Vertex Color", "Color used to mix with point color to get final color");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
}
static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop)
@@ -951,27 +1069,6 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "verts[2]");
RNA_def_property_ui_text(prop, "v3", "Third triangle vertex index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- /* texture coord for point v1 */
- prop = RNA_def_property(srna, "uv1", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_float_sdna(prop, NULL, "uv[0]");
- RNA_def_property_array(prop, 2);
- RNA_def_property_ui_text(prop, "uv1", "First triangle vertex texture coordinates");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- /* texture coord for point v2 */
- prop = RNA_def_property(srna, "uv2", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_float_sdna(prop, NULL, "uv[1]");
- RNA_def_property_array(prop, 2);
- RNA_def_property_ui_text(prop, "uv2", "Second triangle vertex texture coordinates");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- /* texture coord for point v3 */
- prop = RNA_def_property(srna, "uv3", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_float_sdna(prop, NULL, "uv[2]");
- RNA_def_property_array(prop, 2);
- RNA_def_property_ui_text(prop, "uv3", "Third triangle vertex texture coordinates");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_gpencil_mvert_group(BlenderRNA *brna)
@@ -1103,22 +1200,70 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* gradient control along y */
- prop = RNA_def_property(srna, "gradient_factor", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_float_sdna(prop, NULL, "gradient_f");
+ prop = RNA_def_property(srna, "hardeness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "hardeness");
RNA_def_property_range(prop, 0.001f, 1.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(
- prop, "Border Opacity Factor", "Amount of gradient along section of stroke");
+ RNA_def_property_ui_text(prop, "Hardeness", "Amount of gradient along section of stroke");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Stroke bound box */
+ prop = RNA_def_property(srna, "bound_box_min", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "boundbox_min");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Boundbox Min", "");
+
+ prop = RNA_def_property(srna, "bound_box_max", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "boundbox_max");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Boundbox Max", "");
+
/* gradient shape ratio */
- prop = RNA_def_property(srna, "gradient_shape", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "gradient_s");
+ prop = RNA_def_property(srna, "aspect", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "aspect_ratio");
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.01f, 1.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Aspect Ratio", "");
+ RNA_def_property_ui_text(prop, "Aspect", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* UV translation. */
+ prop = RNA_def_property(srna, "uv_translation", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "uv_translation");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "UV Translation", "Translation of default UV postion");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_uv_update");
+
+ /* UV rotation. */
+ prop = RNA_def_property(srna, "uv_rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_rotation");
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "UV Rotation", "Rotation of the UV");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_uv_update");
+
+ /* UV scale. */
+ prop = RNA_def_property(srna, "uv_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_scale");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.01f, 100.0f);
+ RNA_def_property_ui_text(prop, "UV Scale", "Scale of the UV");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_uv_update");
+
+ /* Vertex Color for Fill. */
+ prop = RNA_def_property(srna, "vertex_color_fill", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "vert_color_fill");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(
+ prop, "Vertex Fill Color", "Color used to mix with fill color to get final color");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
}
@@ -1239,6 +1384,74 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
}
+static void rna_def_gpencil_layers_mask_api(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "GreasePencilMaskLayers");
+ srna = RNA_def_struct(brna, "GreasePencilMaskLayers", NULL);
+ RNA_def_struct_sdna(srna, "bGPDlayer");
+ RNA_def_struct_ui_text(
+ srna, "Grease Pencil Mask Layers", "Collection of grease pencil masking layers");
+
+ prop = RNA_def_property(srna, "active_mask_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_funcs(prop,
+ "rna_GPencil_active_mask_index_get",
+ "rna_GPencil_active_mask_index_set",
+ "rna_GPencil_active_mask_index_range");
+ RNA_def_property_ui_text(prop, "Active Layer Mask Index", "Active index in layer mask array");
+
+ func = RNA_def_function(srna, "add", "rna_GPencil_layer_mask_add");
+ RNA_def_function_ui_description(func, "Add a layer to mask list");
+ parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "Layer to add as mask");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ func = RNA_def_function(srna, "remove", "rna_GPencil_layer_mask_remove");
+ RNA_def_function_ui_description(func, "Remove a layer from mask list");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "mask", "GPencilLayerMask", "", "Mask to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+}
+
+static void rna_def_gpencil_layer_mask(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "GPencilLayerMask", NULL);
+ RNA_def_struct_sdna(srna, "bGPDlayer_Mask");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Masking Layers", "List of Mask Layers");
+ RNA_def_struct_path_func(srna, "rna_GPencilLayerMask_path");
+
+ /* Name */
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Layer", "Mask layer name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_mask_info_set");
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, NULL);
+
+ /* Flags */
+ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MASK_HIDE);
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
+ RNA_def_property_ui_text(prop, "Hide", "Set mask Visibility");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MASK_INVERT);
+ RNA_def_property_ui_icon(prop, ICON_CLIPUV_HLT, -1);
+ RNA_def_property_ui_text(prop, "Invert", "Invert mask");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+}
+
static void rna_def_gpencil_layer(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1267,6 +1480,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Frames", "Sketches for this layer on different frames");
rna_def_gpencil_frames_api(brna, prop);
+ /* Mask Layers */
+ prop = RNA_def_property(srna, "mask_layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "mask_layers", NULL);
+ RNA_def_property_struct_type(prop, "GPencilLayerMask");
+ RNA_def_property_ui_text(prop, "Masks", "List of Masking Layers");
+ rna_def_gpencil_layers_mask_api(brna, prop);
+
/* Active Frame */
prop = RNA_def_property(srna, "active_frame", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "actframe");
@@ -1308,7 +1528,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Tint Color */
- prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "tintcolor");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1316,12 +1536,20 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Tint factor */
- prop = RNA_def_property(srna, "tint_factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "tint_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "tintcolor[3]");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Tint Factor", "Factor of tinting color");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Vertex Paint opacity factor */
+ prop = RNA_def_property(srna, "vertex_paint_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "vertex_paint_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Vertex Paint Opacity", "Vertex Paint mix factor");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Line Thickness Change */
prop = RNA_def_property(srna, "line_change", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "line_change");
@@ -1434,11 +1662,17 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop, "Disallow Locked Materials Editing", "Avoids editing locked materials in the layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- prop = RNA_def_property(srna, "mask_layer", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_mask_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Mask Layer", "Mask pixels from underlying layers drawing");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_lights", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_LIGHTS);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
- prop, "Mask Layer", "Remove any pixel outside underlying layers drawing");
+ prop, "Use Lights", "Enable the use of lights on stroke and fill materials");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* solo mode: Only display frames with keyframe */
@@ -1454,15 +1688,6 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Ruler", "This is a special ruler layer");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- /* exposed as layers.active */
-# if 0
- prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencilLayer_active_set");
- RNA_def_property_ui_text(prop, "Active", "Set active layer for editing");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
-# endif
-
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SELECT);
RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet");
@@ -1486,7 +1711,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Parent", "Parent Object");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_dependency_update");
/* parent type */
prop = RNA_def_property(srna, "parent_type", PROP_ENUM, PROP_NONE);
@@ -1686,7 +1911,9 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "draw_mode");
RNA_def_property_enum_items(prop, rna_enum_gpencil_stroke_depth_order_items);
RNA_def_property_ui_text(
- prop, "Stroke Depth Order", "Defines how the strokes are ordered in 3D space");
+ prop,
+ "Stroke Depth Order",
+ "Defines how the strokes are ordered in 3D space (for objects not displayed 'In Front')");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Flags */
@@ -1719,6 +1946,13 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_update(
prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+ prop = RNA_def_property(srna, "is_stroke_vertex_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_VERTEXMODE);
+ RNA_def_property_ui_text(prop, "Stroke Vertex Paint Mode", "Grease Pencil vertex paint");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(
+ prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_ONIONSKINS);
RNA_def_property_boolean_default(prop, true);
@@ -1727,14 +1961,6 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_update(
prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
- prop = RNA_def_property(srna, "show_stroke_direction", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_DIRECTION);
- RNA_def_property_ui_text(prop,
- "Show Direction",
- "Show stroke drawing direction with a bigger green dot (start) "
- "and smaller red dot (end) points");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
prop = RNA_def_property(srna, "stroke_thickness_space", PROP_ENUM, PROP_NONE); /* as an enum */
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, stroke_thickness_items);
@@ -1760,20 +1986,6 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
"(keyframes must be selected to be included)");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "use_force_fill_recalc", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_FORCE_RECALC);
- RNA_def_property_ui_text(
- prop,
- "Force Fill Update",
- "Force recalc of fill data after use deformation modifiers (reduce FPS)");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "use_adaptive_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_UV_ADAPTIVE);
- RNA_def_property_ui_text(
- prop, "Adaptive UV", "Automatic UVs are calculated depending of the stroke size");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_strokes_update");
-
prop = RNA_def_property(srna, "use_autolock_layers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_AUTOLOCK_LAYERS);
RNA_def_property_ui_text(
@@ -1820,7 +2032,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "gcolor_prev");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1829,7 +2041,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_update(
prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
- prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "gcolor_next");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -1871,10 +2083,8 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_onion_loop", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_LOOP);
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
- RNA_def_property_ui_text(prop,
- "Loop",
- "Display first onion keyframes using next frame color to show "
- "indication of loop start frame");
+ RNA_def_property_ui_text(
+ prop, "Show Start Frame", "Display onion keyframes for looping animations");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "onion_factor", PROP_FLOAT, PROP_NONE);
@@ -1889,6 +2099,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "zdepth_offset");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 3);
+ RNA_def_property_float_default(prop, 0.150f);
RNA_def_property_ui_text(prop, "Surface Offset", "Offset amount when drawing in surface mode");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
@@ -1918,6 +2129,7 @@ void RNA_def_gpencil(BlenderRNA *brna)
rna_def_gpencil_data(brna);
rna_def_gpencil_layer(brna);
+ rna_def_gpencil_layer_mask(brna);
rna_def_gpencil_frame(brna);
rna_def_gpencil_stroke(brna);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 53fa3f7459d..0caa93940c8 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_mesh_types.h"
#include "DNA_gpencil_modifier_types.h"
@@ -33,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLT_translation.h"
@@ -127,6 +129,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
"Opacity",
"Opacity of the strokes"},
{eGpencilModifierType_Tint, "GP_TINT", ICON_MOD_TINT, "Tint", "Tint strokes with new color"},
+ {eGpencilModifierType_Vertexcolor,
+ "GP_VERTEXCOLOR",
+ ICON_MOD_NORMALEDIT,
+ "Vertex Color",
+ "Apply color changes to Vertex Color"},
{0, NULL, 0, NULL, NULL},
};
@@ -138,16 +145,6 @@ static const EnumPropertyItem modifier_modify_color_items[] = {
{0, NULL, 0, NULL, NULL},
};
-static const EnumPropertyItem modifier_opacity_mode_items[] = {
- {GP_OPACITY_MODE_MATERIAL,
- "MATERIAL",
- 0,
- "Material",
- "Modify opacity using alpha channel of material"},
- {GP_OPACITY_MODE_STRENGTH, "STRENGTH", 0, "Strength", "Modify opacity using point strength"},
- {0, NULL, 0, NULL, NULL},
-};
-
static const EnumPropertyItem modifier_gphook_falloff_items[] = {
{eGPHook_Falloff_None, "NONE", 0, "No Falloff", ""},
{eGPHook_Falloff_Curve, "CURVE", 0, "Curve", ""},
@@ -168,6 +165,11 @@ static const EnumPropertyItem rna_enum_time_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem gpencil_subdivision_type_items[] = {
+ {GP_SUBDIV_CATMULL, "CATMULL_CLARK", 0, "Catmull-Clark", ""},
+ {GP_SUBDIV_SIMPLE, "SIMPLE", 0, "Simple", ""},
+ {0, NULL, 0, NULL, NULL},
+};
#endif
#ifdef RNA_RUNTIME
@@ -224,6 +226,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_ArmatureGpencilModifier;
case eGpencilModifierType_Multiply:
return &RNA_MultiplyGpencilModifier;
+ case eGpencilModifierType_Vertexcolor:
+ return &RNA_VertexcolorGpencilModifier;
/* Default */
case eGpencilModifierType_None:
case NUM_GREASEPENCIL_MODIFIER_TYPES:
@@ -338,6 +342,17 @@ static void rna_HookGpencilModifier_object_set(PointerRNA *ptr,
BKE_object_modifier_gpencil_hook_reset(ob, hmd);
}
+static void rna_VertexcolorGpencilModifier_object_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ VertexcolorGpencilModifierData *hmd = ptr->data;
+ Object *ob = (Object *)value.data;
+
+ hmd->object = ob;
+ id_lib_extern((ID *)ob);
+}
+
static void rna_TimeModifier_start_frame_set(PointerRNA *ptr, int value)
{
TimeGpencilModifierData *tmd = ptr->data;
@@ -360,6 +375,42 @@ static void rna_TimeModifier_end_frame_set(PointerRNA *ptr, int value)
}
}
+static void rna_GpencilOpacity_range(
+ PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax)
+{
+ OpacityGpencilModifierData *md = (OpacityGpencilModifierData *)ptr->data;
+
+ *min = 0.0f;
+ *softmin = 0.0f;
+
+ *softmax = (md->flag & GP_OPACITY_NORMALIZE) ? 1.0f : 2.0f;
+ *max = *softmax;
+}
+
+static void rna_GpencilOpacity_max_set(PointerRNA *ptr, float value)
+{
+ OpacityGpencilModifierData *md = (OpacityGpencilModifierData *)ptr->data;
+
+ md->factor = value;
+ if (md->flag & GP_OPACITY_NORMALIZE) {
+ if (md->factor > 1.0f) {
+ md->factor = 1.0f;
+ }
+ }
+}
+
+static void rna_GpencilModifier_opacity_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ OpacityGpencilModifierData *md = (OpacityGpencilModifierData *)ptr->data;
+ if (md->flag & GP_OPACITY_NORMALIZE) {
+ if (md->factor > 1.0f) {
+ md->factor = 1.0f;
+ }
+ }
+
+ rna_GpencilModifier_update(bmain, scene, ptr);
+}
+
#else
static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
@@ -388,15 +439,41 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NoiseGpencilModifier_vgname_set");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "factor");
- RNA_def_property_range(prop, 0, 30.0);
- RNA_def_property_ui_text(prop, "Factor", "Amount of noise to apply");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Offset Factor", "Amount of noise to apply");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor_strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "factor_strength");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Strength Factor", "Amount of noise to apply to opacity");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor_thickness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "factor_thickness");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "Thickness Factor", "Amount of noise to apply to thickness");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor_uvs", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "factor_uvs");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_ui_text(prop, "UV Factor", "Amount of noise to apply uv rotation");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "random", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_USE_RANDOM);
- RNA_def_property_ui_text(prop, "Random", "Use random values");
+ RNA_def_property_ui_text(prop, "Random", "Use random values over time");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
@@ -409,33 +486,21 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
prop, "Affect Position", "The modifier affects the position of the point");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "use_edit_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_STRENGTH);
- RNA_def_property_ui_text(
- prop, "Affect Strength", "The modifier affects the color strength of the point");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
- prop = RNA_def_property(srna, "use_edit_thickness", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_THICKNESS);
- RNA_def_property_ui_text(
- prop, "Affect Thickness", "The modifier affects the thickness of the point");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
- prop = RNA_def_property(srna, "use_edit_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_UV);
- RNA_def_property_ui_text(
- prop, "Affect UV", "The modifier affects the UV rotation factor of the point");
+ prop = RNA_def_property(srna, "noise_scale", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "noise_scale");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(prop, "Noise Scale", "Scale the noise frequency");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "full_stroke", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_FULL_STROKE);
+ prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_CUSTOM_CURVE);
RNA_def_property_ui_text(
- prop, "Full Stroke", "The noise moves the stroke as a whole, not point by point");
+ prop, "Custom Curve", "Use a custom curve to define noise effect along the strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "move_extreme", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOVE_EXTREME);
- RNA_def_property_ui_text(prop, "Move Extremes", "The noise moves the stroke extreme points");
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_intensity");
+ RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -509,9 +574,9 @@ static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmoothGpencilModifier_vgname_set");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "factor");
- RNA_def_property_range(prop, 0, 2);
+ RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Factor", "Amount of smooth to apply");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@@ -582,6 +647,17 @@ static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_LAYERPASS);
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_CUSTOM_CURVE);
+ RNA_def_property_ui_text(
+ prop, "Custom Curve", "Use a custom curve to define smooth effect along the strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_intensity");
+ RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
static void rna_def_modifier_gpencilsubdiv(BlenderRNA *brna)
@@ -610,9 +686,10 @@ static void rna_def_modifier_gpencilsubdiv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Level", "Number of subdivisions");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "simple", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_SIMPLE);
- RNA_def_property_ui_text(prop, "Simple", "The modifier only add control points");
+ prop = RNA_def_property(srna, "subdivision_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, gpencil_subdivision_type_items);
+ RNA_def_property_ui_text(prop, "Subdivision Type", "Select type of subdivision algorithm");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -663,7 +740,7 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
"ADAPTIVE",
ICON_IPO_EASE_IN_OUT,
"Adaptive",
- "Use a RDP algorithm to simplify the stroke"},
+ "Use a Ramer-Douglas-Peucker algorithm to simplify the stroke preserving main shape"},
{GP_SIMPLIFY_SAMPLE,
"SAMPLE",
ICON_IPO_EASE_IN_OUT,
@@ -692,7 +769,7 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Material", "Material name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "factor");
RNA_def_property_range(prop, 0, 100.0);
RNA_def_property_ui_range(prop, 0, 100.0, 1.0f, 3);
@@ -744,16 +821,18 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
/* Sample */
- prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "length");
- RNA_def_property_range(prop, 0, 10.0f);
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1.0, 0.01, 3);
RNA_def_property_ui_text(prop, "Length", "Length of each segment");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- /* Distance */
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
+ /* Merge */
+ prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "distance");
- RNA_def_property_range(prop, 0, 100.0f);
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1.0, 0.01, 3);
RNA_def_property_ui_text(prop, "Distance", "Distance between points");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
@@ -787,7 +866,15 @@ static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "thickness");
RNA_def_property_range(prop, -100, 500);
- RNA_def_property_ui_text(prop, "Thickness", "Factor of thickness change");
+ RNA_def_property_ui_text(prop, "Thickness", "Absolute thickness to apply everywhere");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "thickness_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "thickness_fac");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 10.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Thickness Factor", "Factor to multiply the thickness with");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -829,17 +916,18 @@ static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_CUSTOM_CURVE);
- RNA_def_property_ui_text(prop, "Custom Curve", "Use a custom curve to define thickness changes");
+ RNA_def_property_ui_text(
+ prop, "Custom Curve", "Use a custom curve to define thickness change along the strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "normalize_thickness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_NORMALIZE);
- RNA_def_property_ui_text(prop, "Normalize", "Normalize the full stroke to modifier thickness");
+ RNA_def_property_ui_text(prop, "Uniform Thickness", "Replace the stroke thickness");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curve_thickness");
- RNA_def_property_ui_text(prop, "Curve", "Custom Thickness Curve");
+ RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
@@ -950,7 +1038,7 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Material", "Material name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rgb");
RNA_def_property_array(prop, 3);
@@ -959,15 +1047,10 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna)
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "factor");
- RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 3);
+ RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 2);
RNA_def_property_ui_text(prop, "Factor", "Factor for mixing color");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_CREATE_COLORS);
- RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "pass_index");
RNA_def_property_range(prop, 0, 100);
@@ -999,6 +1082,17 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_LAYERPASS);
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_CUSTOM_CURVE);
+ RNA_def_property_ui_text(
+ prop, "Custom Curve", "Use a custom curve to define tint effect along the strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_intensity");
+ RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
static void rna_def_modifier_gpenciltime(BlenderRNA *brna)
@@ -1110,29 +1204,27 @@ static void rna_def_modifier_gpencilcolor(BlenderRNA *brna)
prop = RNA_def_property(srna, "hue", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 0.5);
RNA_def_property_float_sdna(prop, NULL, "hsv[0]");
RNA_def_property_ui_text(prop, "Hue", "Color Hue");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0);
RNA_def_property_float_sdna(prop, NULL, "hsv[1]");
RNA_def_property_ui_text(prop, "Saturation", "Color Saturation");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0);
RNA_def_property_float_sdna(prop, NULL, "hsv[2]");
RNA_def_property_ui_text(prop, "Value", "Color Value");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_CREATE_COLORS);
- RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "pass_index");
RNA_def_property_range(prop, 0, 100);
@@ -1164,6 +1256,17 @@ static void rna_def_modifier_gpencilcolor(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_INVERT_LAYERPASS);
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_CUSTOM_CURVE);
+ RNA_def_property_ui_text(
+ prop, "Custom Curve", "Use a custom curve to define color effect along the strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_intensity");
+ RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
@@ -1181,11 +1284,6 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "opacity_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, modifier_opacity_mode_items);
- RNA_def_property_ui_text(prop, "Opacity Mode", "Set what mode used to define opacity");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "layername");
RNA_def_property_ui_text(prop, "Layer", "Layer name");
@@ -1204,13 +1302,10 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "factor");
- RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 3);
- RNA_def_property_ui_text(prop, "Factor", "Factor of Opacity");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
- prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_CREATE_COLORS);
- RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material");
+ RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 2);
+ RNA_def_property_float_funcs(
+ prop, NULL, "rna_GpencilOpacity_max_set", "rna_GpencilOpacity_range");
+ RNA_def_property_ui_text(prop, "Opacity Factor", "Factor of Opacity");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -1249,9 +1344,25 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_LAYERPASS);
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "normalize_opacity", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_NORMALIZE);
+ RNA_def_property_ui_text(prop, "Uniform Opacity", "Replace the stroke opacity");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_opacity_update");
+
+ prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_CUSTOM_CURVE);
+ RNA_def_property_ui_text(
+ prop, "Custom Curve", "Use a custom curve to define opacity effect along the strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_intensity");
+ RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
-static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
+static void rna_def_modifier_gpencilarray(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -1295,50 +1406,41 @@ static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
- prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION);
+ prop = RNA_def_property(srna, "constant_offset", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "offset");
- RNA_def_property_ui_text(prop, "Offset", "Value for the distance between items");
+ RNA_def_property_ui_text(prop, "Constant Offset", "Value for the distance between items");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "shift", PROP_FLOAT, PROP_TRANSLATION);
+ prop = RNA_def_property(srna, "relative_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "shift");
- RNA_def_property_ui_text(prop, "Shift", "Shiftiness value");
- RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
- prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float_sdna(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Rotation", "Value for changes in rotation");
+ RNA_def_property_ui_text(
+ prop,
+ "Relative Offset",
+ "The size of the geometry will determine the distance between arrayed items");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "scale");
- RNA_def_property_ui_text(prop, "Scale", "Value for changes in scale");
+ prop = RNA_def_property(srna, "random_offset", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "rnd_offset");
+ RNA_def_property_ui_text(prop, "Random Offset", "Value for changes in location");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "random_rot", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_RANDOM_ROT);
- RNA_def_property_ui_text(prop, "Random Rotation", "Use random factors for rotation");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
-
- prop = RNA_def_property(srna, "rot_factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "random_rotation", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "rnd_rot");
- RNA_def_property_ui_text(prop, "Rotation Factor", "Random factor for rotation");
- RNA_def_property_range(prop, -10.0, 10.0);
+ RNA_def_property_ui_text(prop, "Random Rotation", "Value for changes in rotation");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "random_scale", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_RANDOM_SIZE);
- RNA_def_property_ui_text(prop, "Random Scale", "Use random factors for scale");
+ prop = RNA_def_property(srna, "random_scale", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "rnd_scale");
+ RNA_def_property_ui_text(prop, "Scale", "Value for changes in scale");
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "scale_factor", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "rnd_size");
- RNA_def_property_ui_text(prop, "Scale Factor", "Random factor for scale");
- RNA_def_property_range(prop, -10.0, 10.0);
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_ui_text(prop, "Seed", "Random seed");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "replace_material", PROP_INT, PROP_NONE);
@@ -1376,12 +1478,19 @@ static void rna_def_modifier_gpencilinstance(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "keep_on_top", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_KEEP_ONTOP);
- RNA_def_property_ui_text(
- prop,
- "Keep on Top",
- "Keep the original stroke in front of new instances (only affect by layer)");
+ prop = RNA_def_property(srna, "use_constant_offset", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_USE_OFFSET);
+ RNA_def_property_ui_text(prop, "Offset", "Enable offset");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_object_offset", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_USE_OB_OFFSET);
+ RNA_def_property_ui_text(prop, "Object Offset", "Enable obejct offset");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_relative_offset", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_USE_RELATIVE);
+ RNA_def_property_ui_text(prop, "Shift", "Enable shift");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
@@ -1848,16 +1957,6 @@ static void rna_def_modifier_gpencilarmature(BlenderRNA *brna)
prop, "Preserve Volume", "Deform rotation interpolation with quaternions");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
-# if 0 /* GPXX keep disabled now */
- prop = RNA_def_property(srna, "use_multi_modifier", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "multi", 0);
- RNA_def_property_ui_text(
- prop,
- "Multi Modifier",
- "Use same input as previous modifier, and mix results using overall vgroup");
- RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
-# endif
-
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "vgname");
RNA_def_property_ui_text(
@@ -1930,28 +2029,33 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Angle Splitting", "Enable angle splitting");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "enable_fading", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_fade", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", GP_MULTIPLY_ENABLE_FADING);
- RNA_def_property_ui_text(prop, "Enable Fading", "Enable fading");
+ RNA_def_property_ui_text(
+ prop, "Enable Fade", "Fade the stroke thickness for each generated stroke");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, M_PI);
+ RNA_def_property_ui_range(prop, 0, M_PI, 10, 2);
RNA_def_property_ui_text(prop, "Angle", "Split angle for segments");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "duplications", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 10);
- RNA_def_property_ui_text(prop, "Duplications", "How many copies of strokes be displayed");
+ prop = RNA_def_property(srna, "duplicates", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "duplications");
+ RNA_def_property_range(prop, 0, 999);
+ RNA_def_property_ui_range(prop, 1, 10, 1, 1);
+ RNA_def_property_ui_text(prop, "Duplicates", "How many copies of strokes be displayed");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0, M_PI);
+ prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 3);
RNA_def_property_ui_text(prop, "Distance", "Distance of duplications");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, -1, 1, 0.1, 3);
+ RNA_def_property_ui_range(prop, -1, 1, 0.01, 3);
RNA_def_property_ui_text(prop, "Offset", "Offset of duplicates. -1 to 1: inner to outer");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@@ -1967,12 +2071,132 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Opacity", "Fade influence of stroke's opacity");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "fading_center", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "fading_center", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_float_default(prop, 0.5);
RNA_def_property_ui_text(prop, "Center", "Fade center");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
+static void rna_def_modifier_gpencilvertexcolor(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* modes */
+ static EnumPropertyItem vertexcol_mode_types_items[] = {
+ {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"},
+ {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"},
+ {GPPAINT_MODE_BOTH, "BOTH", 0, "Both", "Vertex Color affects to Stroke and Fill"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "VertexcolorGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Vertexcolor Modifier", "Vertex color modifier");
+ RNA_def_struct_sdna(srna, "VertexcolorGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT);
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Object", "Parent object to define the center of the effect");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_pointer_funcs(
+ prop, NULL, "rna_VertexcolorGpencilModifier_object_set", NULL, NULL);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "materialname");
+ RNA_def_property_ui_text(prop, "Material", "Material name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_HookGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_MATERIAL);
+ RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse Vertex Group", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Factor", "Factor of tinting");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "radius");
+ RNA_def_property_range(prop, 1e-6f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 1, 3);
+ RNA_def_property_ui_text(prop, "Radius", "Defines the maximum distance of the effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Mode type. */
+ prop = RNA_def_property(srna, "vertex_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, vertexcol_mode_types_items);
+ RNA_def_property_ui_text(prop, "Mode", "Defines how vertex color affect to the strokes");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Color band */
+ prop = RNA_def_property(srna, "colors", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "colorband");
+ RNA_def_property_struct_type(prop, "ColorRamp");
+ RNA_def_property_ui_text(prop, "Colors", "Color ramp used to define tinting colors");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_VERTEXCOL_CUSTOM_CURVE);
+ RNA_def_property_ui_text(
+ prop, "Custom Curve", "Use a custom curve to define vertex color effect along the strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_intensity");
+ RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2038,7 +2262,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpenciltint(brna);
rna_def_modifier_gpenciltime(brna);
rna_def_modifier_gpencilcolor(brna);
- rna_def_modifier_gpencilinstance(brna);
+ rna_def_modifier_gpencilarray(brna);
rna_def_modifier_gpencilbuild(brna);
rna_def_modifier_gpencilopacity(brna);
rna_def_modifier_gpencillattice(brna);
@@ -2046,6 +2270,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencilhook(brna);
rna_def_modifier_gpencilarmature(brna);
rna_def_modifier_gpencilmultiply(brna);
+ rna_def_modifier_gpencilvertexcolor(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index a29031900ac..f206e0061fc 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -63,6 +63,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = {
# include "MEM_guardedalloc.h"
+# include "DNA_gpencil_types.h"
# include "DNA_node_types.h"
# include "DNA_object_types.h"
# include "DNA_screen_types.h"
@@ -111,16 +112,16 @@ static void rna_Material_update_previews(Main *UNUSED(bmain),
static void rna_MaterialGpencil_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Material *ma = (Material *)ptr->owner_id;
-
rna_Material_update(bmain, scene, ptr);
- WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma);
-}
-static void rna_MaterialGpencil_nopreview_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- Material *ma = (Material *)ptr->owner_id;
+ /* Need set all caches as dirty. */
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ }
+ }
- rna_Material_update(bmain, scene, ptr);
WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma);
}
@@ -411,42 +412,45 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
/* mode type styles */
static EnumPropertyItem gpcolordata_mode_types_items[] = {
- {GP_STYLE_MODE_LINE, "LINE", 0, "Line", "Draw strokes using a continuous line"},
- {GP_STYLE_MODE_DOTS, "DOTS", 0, "Dots", "Draw strokes using separated dots"},
- {GP_STYLE_MODE_BOX, "BOX", 0, "Boxes", "Draw strokes using separated rectangle boxes"},
+ {GP_MATERIAL_MODE_LINE, "LINE", 0, "Line", "Draw strokes using a continuous line"},
+ {GP_MATERIAL_MODE_DOT, "DOTS", 0, "Dots", "Draw strokes using separated dots"},
+ {GP_MATERIAL_MODE_SQUARE, "BOX", 0, "Squares", "Draw strokes using separated squares"},
{0, NULL, 0, NULL, NULL},
};
/* stroke styles */
static EnumPropertyItem stroke_style_items[] = {
- {GP_STYLE_STROKE_STYLE_SOLID, "SOLID", 0, "Solid", "Draw strokes with solid color"},
- {GP_STYLE_STROKE_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Draw strokes using texture"},
+ {GP_MATERIAL_STROKE_STYLE_SOLID, "SOLID", 0, "Solid", "Draw strokes with solid color"},
+ {GP_MATERIAL_STROKE_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Draw strokes using texture"},
{0, NULL, 0, NULL, NULL},
};
/* fill styles */
static EnumPropertyItem fill_style_items[] = {
- {GP_STYLE_FILL_STYLE_SOLID, "SOLID", 0, "Solid", "Fill area with solid color"},
- {GP_STYLE_FILL_STYLE_GRADIENT, "GRADIENT", 0, "Gradient", "Fill area with gradient color"},
- {GP_STYLE_FILL_STYLE_CHECKER,
- "CHECKER",
+ {GP_MATERIAL_FILL_STYLE_SOLID, "SOLID", 0, "Solid", "Fill area with solid color"},
+ {GP_MATERIAL_FILL_STYLE_GRADIENT,
+ "GRADIENT",
0,
- "Checker Board",
- "Fill area with checkerboard pattern"},
- {GP_STYLE_FILL_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Fill area with image texture"},
+ "Gradient",
+ "Fill area with gradient color"},
+ {GP_MATERIAL_FILL_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Fill area with image texture"},
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem fill_gradient_items[] = {
- {GP_STYLE_GRADIENT_LINEAR, "LINEAR", 0, "Linear", "Fill area with gradient color"},
- {GP_STYLE_GRADIENT_RADIAL, "RADIAL", 0, "Radial", "Fill area with radial gradient"},
+ {GP_MATERIAL_GRADIENT_LINEAR, "LINEAR", 0, "Linear", "Fill area with gradient color"},
+ {GP_MATERIAL_GRADIENT_RADIAL, "RADIAL", 0, "Radial", "Fill area with radial gradient"},
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem alignment_draw_items[] = {
- {GP_STYLE_FOLLOW_PATH, "PATH", 0, "Path", "Follow stroke drawing path and object rotation"},
- {GP_STYLE_FOLLOW_OBJ, "OBJECT", 0, "Object", "Follow object rotation only"},
- {GP_STYLE_FOLLOW_FIXED,
+ {GP_MATERIAL_FOLLOW_PATH,
+ "PATH",
+ 0,
+ "Path",
+ "Follow stroke drawing path and object rotation"},
+ {GP_MATERIAL_FOLLOW_OBJ, "OBJECT", 0, "Object", "Follow object rotation only"},
+ {GP_MATERIAL_FOLLOW_FIXED,
"FIXED",
0,
"Fixed",
@@ -459,7 +463,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Grease Pencil Color", "");
RNA_def_struct_path_func(srna, "rna_GpencilColorData_path");
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "stroke_rgba");
RNA_def_property_array(prop, 4);
@@ -467,7 +471,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
/* Fill Drawing Color */
- prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "fill_rgba");
RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -475,7 +479,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
/* Secondary Drawing Color */
- prop = RNA_def_property(srna, "mix_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "mix_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "mix_rgba");
RNA_def_property_array(prop, 4);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -483,51 +487,17 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
/* Mix factor */
- prop = RNA_def_property(srna, "mix_factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "mix_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "mix_factor");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Mix", "Mix Adjustment Factor");
+ RNA_def_property_ui_text(prop, "Mix", "Mix Factor");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
/* Stroke Mix factor */
- prop = RNA_def_property(srna, "mix_stroke_factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "mix_stroke_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "mix_stroke_factor");
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Mix", "Mix Stroke Color");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
- /* Scale factor for uv coordinates */
- prop = RNA_def_property(srna, "pattern_scale", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_float_sdna(prop, NULL, "gradient_scale");
- RNA_def_property_array(prop, 2);
- RNA_def_property_ui_text(prop, "Scale", "Scale Factor for UV coordinates");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
- /* Shift factor to move pattern filling in 2d space */
- prop = RNA_def_property(srna, "pattern_shift", PROP_FLOAT, PROP_COORDS);
- RNA_def_property_float_sdna(prop, NULL, "gradient_shift");
- RNA_def_property_array(prop, 2);
- RNA_def_property_ui_text(prop, "Shift", "Shift filling pattern in 2d space");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
- /* Gradient angle */
- prop = RNA_def_property(srna, "pattern_angle", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_float_sdna(prop, NULL, "gradient_angle");
- RNA_def_property_ui_text(prop, "Angle", "Pattern Orientation Angle");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
- /* Gradient radius */
- prop = RNA_def_property(srna, "pattern_radius", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "gradient_radius");
- RNA_def_property_range(prop, 0.0001f, 10.0f);
- RNA_def_property_ui_text(prop, "Radius", "Pattern Radius");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
- /* Box size */
- prop = RNA_def_property(srna, "pattern_gridsize", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "pattern_gridsize");
- RNA_def_property_range(prop, 0.0001f, 10.0f);
- RNA_def_property_ui_text(prop, "Size", "Box Size");
+ RNA_def_property_ui_text(prop, "Mix", "Mix Stroke Factor");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
/* Texture angle */
@@ -566,68 +536,48 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_HIDE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_HIDE);
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
RNA_def_property_ui_text(prop, "Hide", "Set color Visibility");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_LOCKED);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_LOCKED);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
RNA_def_property_ui_text(
prop, "Locked", "Protect color from further editing and/or frame changes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_ONIONSKIN);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_ONIONSKIN);
RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0);
RNA_def_property_ui_text(
prop, "Show in Ghosts", "Display strokes using this color when showing onion skins");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
prop = RNA_def_property(srna, "texture_clamp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_TEX_CLAMP);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_TEX_CLAMP);
RNA_def_property_ui_text(prop, "Clamp", "Do not repeat texture and clamp to one instance only");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
- prop = RNA_def_property(srna, "use_fill_texture_mix", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_TEX_MIX);
- RNA_def_property_ui_text(prop, "Mix Texture", "Mix texture image with filling color");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
- prop = RNA_def_property(srna, "use_stroke_texture_mix", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_TEX_MIX);
- RNA_def_property_ui_text(prop, "Mix Texture", "Mix texture image with stroke color");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
prop = RNA_def_property(srna, "flip", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_FLIP_FILL);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_FLIP_FILL);
RNA_def_property_ui_text(prop, "Flip", "Flip filling colors");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
- prop = RNA_def_property(srna, "use_stroke_pattern", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_PATTERN);
- RNA_def_property_ui_text(prop, "Pattern", "Use Stroke Texture as a pattern to apply color");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
- prop = RNA_def_property(srna, "use_fill_pattern", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_PATTERN);
- RNA_def_property_ui_text(prop, "Pattern", "Use Fill Texture as a pattern to apply color");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
prop = RNA_def_property(srna, "use_overlap_strokes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_DISABLE_STENCIL);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_DISABLE_STENCIL);
RNA_def_property_ui_text(
prop, "Self Overlap", "Disable stencil and overlap self intersections with alpha materials");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
prop = RNA_def_property(srna, "show_stroke", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_SHOW);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_STROKE_SHOW);
RNA_def_property_ui_text(prop, "Show Stroke", "Show stroke lines of this material");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
prop = RNA_def_property(srna, "show_fill", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_SHOW);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_FILL_SHOW);
RNA_def_property_ui_text(prop, "Show Fill", "Show stroke fills of this material");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
@@ -637,13 +587,13 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
RNA_def_property_enum_items(prop, alignment_draw_items);
RNA_def_property_ui_text(
prop, "Alignment", "Defines how align Dots and Boxes with drawing path and object rotation");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
/* pass index for future compositing and editing tools */
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Color Index\" pass");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
/* mode type */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 9980051c112..78f5cfb60b2 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -85,6 +85,11 @@ const EnumPropertyItem rna_enum_object_mode_items[] = {
ICON_GREASEPENCIL,
"Draw",
"Paint Grease Pencil Strokes"},
+ {OB_MODE_VERTEX_GPENCIL,
+ "VERTEX_GPENCIL",
+ ICON_VPAINT_HLT,
+ "Vertex Paint",
+ "Grease Pencil Vertex Paint Strokes"},
{OB_MODE_WEIGHT_GPENCIL,
"WEIGHT_GPENCIL",
ICON_WPAINT_HLT,
@@ -118,6 +123,11 @@ const EnumPropertyItem rna_enum_workspace_object_mode_items[] = {
ICON_GREASEPENCIL,
"Grease Pencil Draw",
"Paint Grease Pencil Strokes"},
+ {OB_MODE_VERTEX_GPENCIL,
+ "VERTEX_GPENCIL",
+ ICON_VPAINT_HLT,
+ "Grease Pencil Vertex Paint",
+ "Grease Pencil Vertex Paint Strokes"},
{OB_MODE_WEIGHT_GPENCIL,
"WEIGHT_GPENCIL",
ICON_WPAINT_HLT,
@@ -343,6 +353,16 @@ static void rna_MaterialIndex_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
}
}
+static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ if (ob && ob->type == OB_GPENCIL) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ }
+}
+
static void rna_Object_matrix_local_get(PointerRNA *ptr, float values[16])
{
Object *ob = (Object *)ptr->owner_id;
@@ -3067,6 +3087,13 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display All Edges", "Display all edges for mesh objects");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "use_grease_pencil_lights", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_USE_GPENCIL_LIGHTS);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Use Lights", "Lights affect to grease pencil object");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "show_transparent", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWTRANSP);
RNA_def_property_ui_text(
@@ -3076,7 +3103,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_in_front", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWXRAY);
RNA_def_property_ui_text(prop, "In Front", "Make the object draw in front of others");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update");
/* pose */
prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index a427267926d..0ead133b3a8 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -733,14 +733,8 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value)
}
}
-static void rna_Gpencil_selectmode_update(bContext *C, PointerRNA *ptr)
+static void rna_Gpencil_extend_selection(bContext *C, PointerRNA *UNUSED(ptr))
{
- ToolSettings *ts = (ToolSettings *)ptr->data;
- /* If the mode is not Stroke, don't extend selection. */
- if ((ts->gpencil_selectmode_edit & GP_SELECTMODE_STROKE) == 0) {
- return;
- }
-
/* Extend selection to all points in all selected strokes. */
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
@@ -762,9 +756,18 @@ static void rna_Gpencil_selectmode_update(bContext *C, PointerRNA *ptr)
}
}
-static void rna_Gpencil_mask_point_update(Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- PointerRNA *ptr)
+static void rna_Gpencil_selectmode_update(bContext *C, PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+ /* If the mode is not Stroke, don't extend selection. */
+ if ((ts->gpencil_selectmode_edit & GP_SELECTMODE_STROKE) == 0) {
+ return;
+ }
+
+ rna_Gpencil_extend_selection(C, ptr);
+}
+
+static void rna_Gpencil_mask_point_update(bContext *UNUSED(C), PointerRNA *ptr)
{
ToolSettings *ts = (ToolSettings *)ptr->data;
@@ -772,19 +775,17 @@ static void rna_Gpencil_mask_point_update(Main *UNUSED(bmain),
ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_SEGMENT;
}
-static void rna_Gpencil_mask_stroke_update(Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- PointerRNA *ptr)
+static void rna_Gpencil_mask_stroke_update(bContext *C, PointerRNA *ptr)
{
ToolSettings *ts = (ToolSettings *)ptr->data;
ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_POINT;
ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_SEGMENT;
+
+ rna_Gpencil_extend_selection(C, ptr);
}
-static void rna_Gpencil_mask_segment_update(Main *UNUSED(bmain),
- Scene *UNUSED(scene),
- PointerRNA *ptr)
+static void rna_Gpencil_mask_segment_update(bContext *UNUSED(C), PointerRNA *ptr)
{
ToolSettings *ts = (ToolSettings *)ptr->data;
@@ -792,6 +793,38 @@ static void rna_Gpencil_mask_segment_update(Main *UNUSED(bmain),
ts->gpencil_selectmode_sculpt &= ~GP_SCULPT_MASK_SELECTMODE_STROKE;
}
+static void rna_Gpencil_vertex_mask_point_update(bContext *C, PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+
+ ts->gpencil_selectmode_vertex &= ~GP_VERTEX_MASK_SELECTMODE_STROKE;
+ ts->gpencil_selectmode_vertex &= ~GP_VERTEX_MASK_SELECTMODE_SEGMENT;
+
+ ED_gpencil_tag_scene_gpencil(CTX_data_scene(C));
+}
+
+static void rna_Gpencil_vertex_mask_stroke_update(bContext *C, PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+
+ ts->gpencil_selectmode_vertex &= ~GP_VERTEX_MASK_SELECTMODE_POINT;
+ ts->gpencil_selectmode_vertex &= ~GP_VERTEX_MASK_SELECTMODE_SEGMENT;
+
+ rna_Gpencil_extend_selection(C, ptr);
+
+ ED_gpencil_tag_scene_gpencil(CTX_data_scene(C));
+}
+
+static void rna_Gpencil_vertex_mask_segment_update(bContext *C, PointerRNA *ptr)
+{
+ ToolSettings *ts = (ToolSettings *)ptr->data;
+
+ ts->gpencil_selectmode_vertex &= ~GP_VERTEX_MASK_SELECTMODE_POINT;
+ ts->gpencil_selectmode_vertex &= ~GP_VERTEX_MASK_SELECTMODE_STROKE;
+
+ ED_gpencil_tag_scene_gpencil(CTX_data_scene(C));
+}
+
/* Read-only Iterator of all the scene objects. */
static void rna_Scene_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -2873,6 +2906,18 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "gp_paint");
RNA_def_property_ui_text(prop, "Grease Pencil Paint", "");
+ prop = RNA_def_property(srna, "gpencil_vertex_paint", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_vertexpaint");
+ RNA_def_property_ui_text(prop, "Grease Pencil Vertex Paint", "");
+
+ prop = RNA_def_property(srna, "gpencil_sculpt_paint", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_sculptpaint");
+ RNA_def_property_ui_text(prop, "Grease Pencil Sculpt Paint", "");
+
+ prop = RNA_def_property(srna, "gpencil_weight_paint", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_weightpaint");
+ RNA_def_property_ui_text(prop, "Grease Pencil Weight Paint", "");
+
prop = RNA_def_property(srna, "particle_edit", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "particle");
RNA_def_property_ui_text(prop, "Particle Edit", "");
@@ -3190,6 +3235,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke points");
RNA_def_property_ui_icon(prop, ICON_GP_SELECT_POINTS, 0);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_mask_point_update");
prop = RNA_def_property(srna, "use_gpencil_select_mask_stroke", PROP_BOOLEAN, PROP_NONE);
@@ -3198,6 +3244,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke");
RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_mask_stroke_update");
prop = RNA_def_property(srna, "use_gpencil_select_mask_segment", PROP_BOOLEAN, PROP_NONE);
@@ -3207,8 +3254,41 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop, "Selection Mask", "Only sculpt selected stroke points between other strokes");
RNA_def_property_ui_icon(prop, ICON_GP_SELECT_BETWEEN_STROKES, 0);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_mask_segment_update");
+ /* Grease Pencil - Select mode Vertex Paint */
+ prop = RNA_def_property(srna, "use_gpencil_vertex_select_mask_point", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "gpencil_selectmode_vertex", GP_VERTEX_MASK_SELECTMODE_POINT);
+ RNA_def_property_ui_text(prop, "Selection Mask", "Only paint selected stroke points");
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_POINTS, 0);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(
+ prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_vertex_mask_point_update");
+
+ prop = RNA_def_property(srna, "use_gpencil_vertex_select_mask_stroke", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "gpencil_selectmode_vertex", GP_VERTEX_MASK_SELECTMODE_STROKE);
+ RNA_def_property_ui_text(prop, "Selection Mask", "Only paint selected stroke");
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(
+ prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_vertex_mask_stroke_update");
+
+ prop = RNA_def_property(srna, "use_gpencil_vertex_select_mask_segment", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "gpencil_selectmode_vertex", GP_VERTEX_MASK_SELECTMODE_SEGMENT);
+ RNA_def_property_ui_text(
+ prop, "Selection Mask", "Only paint selected stroke points between other strokes");
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_BETWEEN_STROKES, 0);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(
+ prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Gpencil_vertex_mask_segment_update");
+
/* Annotations - 2D Views Stroke Placement */
prop = RNA_def_property(srna, "annotation_stroke_placement_view2d", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v2d_align");
@@ -6288,7 +6368,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "simplify_gpencil_onplay", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ON_PLAY);
RNA_def_property_ui_text(
- prop, "Simplify Playback", "Simplify Grease Pencil only during animation playback");
+ prop, "Playback Only", "Simplify Grease Pencil only during animation playback");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "simplify_gpencil_antialiasing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_AA);
+ RNA_def_property_ui_text(prop, "Antialiasing", "Use Antialiasing to smooth stroke edges");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_view_fill", PROP_BOOLEAN, PROP_NONE);
@@ -6296,26 +6381,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Fill", "Display fill strokes in the viewport");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
- prop = RNA_def_property(srna, "simplify_gpencil_remove_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(
- prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE);
- RNA_def_property_ui_text(prop, "Disable Lines", "Display external lines of fill strokes");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "simplify_gpencil_view_modifier", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "simplify_gpencil_modifier", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER);
- RNA_def_property_ui_text(prop, "Disable Modifiers", "Display modifiers in the viewport");
+ RNA_def_property_ui_text(prop, "Modifiers", "Display modifiers");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_shader_fx", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FX);
- RNA_def_property_ui_text(prop, "Simplify Shaders", "Display Shader FX");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "simplify_gpencil_blend", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_BLEND);
- RNA_def_property_ui_text(prop, "Layers Blending", "Display blend layers");
+ RNA_def_property_ui_text(prop, "ShadersFX", "Display Shader FX");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_tint", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 14cfe9d29ab..743c47f4f48 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -57,59 +57,6 @@ const EnumPropertyItem rna_enum_particle_edit_hair_brush_items[] = {
{0, NULL, 0, NULL, NULL},
};
-const EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
- {GP_SCULPT_TYPE_SMOOTH, "SMOOTH", ICON_GPBRUSH_SMOOTH, "Smooth", "Smooth stroke points"},
- {GP_SCULPT_TYPE_THICKNESS,
- "THICKNESS",
- ICON_GPBRUSH_THICKNESS,
- "Thickness",
- "Adjust thickness of strokes"},
- {GP_SCULPT_TYPE_STRENGTH,
- "STRENGTH",
- ICON_GPBRUSH_STRENGTH,
- "Strength",
- "Adjust color strength of strokes"},
- {GP_SCULPT_TYPE_RANDOMIZE,
- "RANDOMIZE",
- ICON_GPBRUSH_RANDOMIZE,
- "Randomize",
- "Introduce jitter/randomness into strokes"},
- {GP_SCULPT_TYPE_GRAB,
- "GRAB",
- ICON_GPBRUSH_GRAB,
- "Grab",
- "Translate the set of points initially within the brush circle"},
- {GP_SCULPT_TYPE_PUSH,
- "PUSH",
- ICON_GPBRUSH_PUSH,
- "Push",
- "Move points out of the way, as if combing them"},
- {GP_SCULPT_TYPE_TWIST,
- "TWIST",
- ICON_GPBRUSH_TWIST,
- "Twist",
- "Rotate points around the midpoint of the brush"},
- {GP_SCULPT_TYPE_PINCH,
- "PINCH",
- ICON_GPBRUSH_PINCH,
- "Pinch",
- "Pull points towards the midpoint of the brush"},
- {GP_SCULPT_TYPE_CLONE,
- "CLONE",
- ICON_GPBRUSH_CLONE,
- "Clone",
- "Paste copies of the strokes stored on the clipboard"},
- {0, NULL, 0, NULL, NULL}};
-
-const EnumPropertyItem rna_enum_gpencil_weight_brush_items[] = {
- {GP_SCULPT_TYPE_WEIGHT,
- "WEIGHT",
- ICON_GPBRUSH_WEIGHT,
- "Weight",
- "Weight Paint for Vertex Groups"},
- {0, NULL, 0, NULL, NULL},
-};
-
#ifndef RNA_RUNTIME
static const EnumPropertyItem rna_enum_gpencil_lock_axis_items[] = {
{GP_LOCKAXIS_VIEW,
@@ -135,6 +82,20 @@ static const EnumPropertyItem rna_enum_gpencil_lock_axis_items[] = {
"Align strokes to current 3D cursor orientation"},
{0, NULL, 0, NULL, NULL},
};
+
+static const EnumPropertyItem rna_enum_gpencil_paint_mode[] = {
+ {GPPAINT_FLAG_USE_MATERIAL,
+ "MATERIAL",
+ 0,
+ "Material",
+ "Paint using the active material base color"},
+ {GPPAINT_FLAG_USE_VERTEXCOLOR,
+ "VERTEXCOLOR",
+ 0,
+ "Vertex Color",
+ "Paint the material with custom vertex color"},
+ {0, NULL, 0, NULL, NULL},
+};
#endif
const EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
@@ -384,6 +345,24 @@ static bool rna_Brush_mode_with_tool_poll(PointerRNA *ptr, PointerRNA value)
}
mode = OB_MODE_PAINT_GPENCIL;
}
+ else if (paint_contains_brush_slot(&ts->gp_vertexpaint->paint, tslot, &slot_index)) {
+ if (slot_index != brush->gpencil_vertex_tool) {
+ return false;
+ }
+ mode = OB_MODE_VERTEX_GPENCIL;
+ }
+ else if (paint_contains_brush_slot(&ts->gp_sculptpaint->paint, tslot, &slot_index)) {
+ if (slot_index != brush->gpencil_sculpt_tool) {
+ return false;
+ }
+ mode = OB_MODE_SCULPT_GPENCIL;
+ }
+ else if (paint_contains_brush_slot(&ts->gp_weightpaint->paint, tslot, &slot_index)) {
+ if (slot_index != brush->gpencil_weight_tool) {
+ return false;
+ }
+ mode = OB_MODE_WEIGHT_GPENCIL;
+ }
return brush->ob_mode & mode;
}
@@ -454,6 +433,21 @@ static char *rna_GpPaint_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings.gpencil_paint");
}
+static char *rna_GpVertexPaint_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_vertex_paint");
+}
+
+static char *rna_GpSculptPaint_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_sculpt_paint");
+}
+
+static char *rna_GpWeightPaint_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_weight_paint");
+}
+
static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.particle_edit.brush");
@@ -543,34 +537,11 @@ static bool rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
return imapaint->missing_data == 0;
}
-static PointerRNA rna_GPencilSculptSettings_brush_get(PointerRNA *ptr)
-{
- GP_Sculpt_Settings *gset = (GP_Sculpt_Settings *)ptr->data;
- GP_Sculpt_Data *brush = NULL;
-
- if ((gset) && (gset->flag & GP_SCULPT_SETT_FLAG_WEIGHT_MODE)) {
- if ((gset->weighttype >= GP_SCULPT_TYPE_WEIGHT) && (gset->weighttype < GP_SCULPT_TYPE_MAX)) {
- brush = &gset->brush[gset->weighttype];
- }
- }
- else {
- if ((gset->brushtype >= 0) && (gset->brushtype < GP_SCULPT_TYPE_WEIGHT)) {
- brush = &gset->brush[gset->brushtype];
- }
- }
- return rna_pointer_inherit_refine(ptr, &RNA_GPencilSculptBrush, brush);
-}
-
static char *rna_GPencilSculptSettings_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt");
}
-static char *rna_GPencilSculptBrush_path(PointerRNA *UNUSED(ptr))
-{
- return BLI_strdup("tool_settings.gpencil_sculpt.brush");
-}
-
static char *rna_GPencilSculptGuide_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("tool_settings.gpencil_sculpt.guide");
@@ -888,10 +859,46 @@ static void rna_def_uv_sculpt(BlenderRNA *brna)
static void rna_def_gp_paint(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
srna = RNA_def_struct(brna, "GpPaint", "Paint");
RNA_def_struct_path_func(srna, "rna_GpPaint_path");
RNA_def_struct_ui_text(srna, "Grease Pencil Paint", "");
+
+ /* Use vertex color (main swith). */
+ prop = RNA_def_property(srna, "color_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_paint_mode);
+ RNA_def_property_ui_text(prop, "Mode", "Paint Mode");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+}
+
+static void rna_def_gp_vertexpaint(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "GpVertexPaint", "Paint");
+ RNA_def_struct_path_func(srna, "rna_GpVertexPaint_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Vertex Paint", "");
+}
+
+static void rna_def_gp_sculptpaint(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "GpSculptPaint", "Paint");
+ RNA_def_struct_path_func(srna, "rna_GpSculptPaint_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Sculpt Paint", "");
+}
+
+static void rna_def_gp_weightpaint(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "GpWeightPaint", "Paint");
+ RNA_def_struct_path_func(srna, "rna_GpWeightPaint_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Weight Paint", "");
}
/* use for weight paint too */
@@ -1383,6 +1390,8 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ UNUSED_VARS(prop_direction_items);
+
StructRNA *srna;
PropertyRNA *prop;
@@ -1390,60 +1399,15 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
srna = RNA_def_struct(brna, "GPencilSculptSettings", NULL);
RNA_def_struct_sdna(srna, "GP_Sculpt_Settings");
RNA_def_struct_path_func(srna, "rna_GPencilSculptSettings_path");
- RNA_def_struct_ui_text(
- srna, "GPencil Sculpt Settings", "Properties for Grease Pencil stroke sculpting tool");
-
- prop = RNA_def_property(srna, "sculpt_tool", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "brushtype");
- RNA_def_property_enum_items(prop, rna_enum_gpencil_sculpt_brush_items);
- RNA_def_property_ui_text(prop, "Tool", "");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "weight_tool", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "weighttype");
- RNA_def_property_enum_items(prop, rna_enum_gpencil_weight_brush_items);
- RNA_def_property_ui_text(prop, "Tool", "Tool for weight painting");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
-
- prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GPencilSculptBrush");
- RNA_def_property_pointer_funcs(prop, "rna_GPencilSculptSettings_brush_get", NULL, NULL, NULL);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Brush", "");
+ RNA_def_struct_ui_text(srna,
+ "GPencil Sculpt Settings",
+ "General properties for Grease Pencil stroke sculpting tools");
prop = RNA_def_property(srna, "guide", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "GPencilSculptGuide");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Guide", "");
- prop = RNA_def_property(srna, "use_edit_position", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_POSITION);
- RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_edit_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_STRENGTH);
- RNA_def_property_ui_text(
- prop, "Affect Strength", "The brush affects the color strength of the point");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_edit_thickness", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_THICKNESS);
- RNA_def_property_ui_text(
- prop, "Affect Thickness", "The brush affects the thickness of the point");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_edit_uv", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_APPLY_UV);
- RNA_def_property_ui_text(prop, "Affect UV", "The brush affects the UV rotation of the point");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
prop = RNA_def_property(srna, "use_multiframe_falloff", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_FRAME_FALLOFF);
RNA_def_property_ui_text(
@@ -1459,6 +1423,13 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_scale_thickness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_SETT_FLAG_SCALE_THICKNESS);
+ RNA_def_property_ui_text(
+ prop, "Scale Stroke Thickness", "Scale the stroke thickness when transforming strokes");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
/* custom falloff curve */
prop = RNA_def_property(srna, "multiframe_falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cur_falloff");
@@ -1491,97 +1462,6 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_float_default(prop, 0.1f);
RNA_def_property_ui_text(prop, "Threshold", "Threshold for stroke intersections");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- /* brush */
- srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
- RNA_def_struct_sdna(srna, "GP_Sculpt_Data");
- RNA_def_struct_path_func(srna, "rna_GPencilSculptBrush_path");
- RNA_def_struct_ui_text(srna, "GPencil Sculpt Brush", "Stroke editing brush");
-
- prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
- RNA_def_property_range(prop, 1, GP_MAX_BRUSH_PIXEL_RADIUS);
- RNA_def_property_ui_range(prop, 1, 500, 10, 3);
- RNA_def_property_ui_text(prop, "Radius", "Radius of the brush in pixels");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0.001, 1.0);
- RNA_def_property_ui_text(prop, "Strength", "Brush strength");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_range(prop, 0.0, 1.0);
- RNA_def_property_ui_text(prop,
- "Weight",
- "Target weight (define a maximum range limit for the weight. Any value "
- "above will be clamped)");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_USE_PRESSURE);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(
- prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_pressure_radius", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_PRESSURE_RADIUS);
- RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
- RNA_def_property_ui_text(
- prop, "Radius Pressure", "Enable tablet pressure sensitivity for radius");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_falloff", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_USE_FALLOFF);
- RNA_def_property_ui_text(
- prop, "Use Falloff", "Strength of brush decays with distance from cursor");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "use_edit_pressure", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_SMOOTH_PRESSURE);
- RNA_def_property_ui_text(
- prop, "Affect Pressure", "Affect pressure values as well when smoothing strokes");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, prop_direction_items);
- RNA_def_property_ui_text(prop, "Direction", "");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- /* Cursor Color */
- static float default_1[3] = {1.0f, 0.6f, 0.6f};
- static float default_2[3] = {0.6f, 0.6f, 1.0f};
-
- prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "curcolor_add");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_array_default(prop, default_1);
- RNA_def_property_ui_text(prop, "Cursor Add", "Color for the cursor for addition");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "cursor_color_sub", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "curcolor_sub");
- RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_float_array_default(prop, default_2);
- RNA_def_property_ui_text(prop, "Cursor Sub", "Color for the cursor for subtraction");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-
- prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SCULPT_FLAG_ENABLE_CURSOR);
- RNA_def_property_boolean_default(prop, true);
- RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen");
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
}
void RNA_def_sculpt_paint(BlenderRNA *brna)
@@ -1594,6 +1474,9 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
rna_def_sculpt(brna);
rna_def_uv_sculpt(brna);
rna_def_gp_paint(brna);
+ rna_def_gp_vertexpaint(brna);
+ rna_def_gp_sculptpaint(brna);
+ rna_def_gp_weightpaint(brna);
rna_def_vertex_paint(brna);
rna_def_image_paint(brna);
rna_def_particle_edit(brna);
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index cd4e027ce7c..f7f68d535ec 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -22,9 +22,10 @@
#include <limits.h>
#include <stdlib.h>
-#include "DNA_shader_fx_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_shader_fx_types.h"
#include "MEM_guardedalloc.h"
@@ -52,7 +53,6 @@ const EnumPropertyItem rna_enum_object_shaderfx_type_items[] = {
"Apply different tint effects"},
{eShaderFxType_Flip, "FX_FLIP", ICON_SHADERFX, "Flip", "Flip image"},
{eShaderFxType_Glow, "FX_GLOW", ICON_SHADERFX, "Glow", "Create a glow effect"},
- {eShaderFxType_Light, "FX_LIGHT", ICON_SHADERFX, "Light", "Simulate illumination"},
{eShaderFxType_Pixel, "FX_PIXEL", ICON_SHADERFX, "Pixelate", "Pixelate image"},
{eShaderFxType_Rim, "FX_RIM", ICON_SHADERFX, "Rim", "Add a rim to the image"},
{eShaderFxType_Shadow, "FX_SHADOW", ICON_SHADERFX, "Shadow", "Create a shadow effect"},
@@ -87,6 +87,14 @@ static const EnumPropertyItem rna_enum_shaderfx_colorize_modes_items[] = {
{eShaderFxColorizeMode_Custom, "CUSTOM", 0, "Custom", ""},
{0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem rna_enum_glow_blend_modes_items[] = {
+ {eGplBlendMode_Regular, "REGULAR", 0, "Regular", ""},
+ {eGplBlendMode_Add, "ADD", 0, "Add", ""},
+ {eGplBlendMode_Subtract, "SUBTRACT", 0, "Subtract", ""},
+ {eGplBlendMode_Multiply, "MULTIPLY", 0, "Multiply", ""},
+ {eGplBlendMode_Divide, "DIVIDE", 0, "Divide", ""},
+ {0, NULL, 0, NULL, NULL}};
+
#ifdef RNA_RUNTIME
# include "BKE_shader_fx.h"
@@ -117,11 +125,10 @@ static StructRNA *rna_ShaderFx_refine(struct PointerRNA *ptr)
return &RNA_ShaderFxFlip;
case eShaderFxType_Glow:
return &RNA_ShaderFxGlow;
- case eShaderFxType_Light:
- return &RNA_ShaderFxLight;
/* Default */
case eShaderFxType_None:
case NUM_SHADER_FX_TYPES:
+ default:
return &RNA_ShaderFx;
}
@@ -192,7 +199,6 @@ static void shaderfx_object_set(Object *self, Object **ob_p, int type, PointerRN
shaderfx_object_set((Object *)ptr->owner_id, &tmd->_prop, _obtype, value); \
}
-RNA_FX_OBJECT_SET(Light, object, OB_EMPTY);
RNA_FX_OBJECT_SET(Shadow, object, OB_EMPTY);
RNA_FX_OBJECT_SET(Swirl, object, OB_EMPTY);
@@ -210,10 +216,10 @@ static void rna_def_shader_fx_blur(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "BlurShaderFxData");
RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
- prop = RNA_def_property(srna, "factor", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "radius");
- RNA_def_property_range(prop, 0, SHRT_MAX);
- RNA_def_property_ui_text(prop, "Factor", "Factor of Blur");
+ prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "radius");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Size", "Factor of Blur");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
@@ -224,19 +230,15 @@ static void rna_def_shader_fx_blur(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "coc", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "coc");
- RNA_def_property_range(prop, 0.001f, 1.0f);
- RNA_def_property_float_default(prop, 0.025f);
- RNA_def_property_ui_text(prop, "Precision", "Define circle of confusion for depth of field");
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation of the effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "use_dof_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_BLUR_DOF_MODE);
- RNA_def_property_ui_text(prop,
- "Lock Focal Plane",
- "Blur using focal plane distance as factor to simulate depth of field "
- "effect (only in camera view)");
+ RNA_def_property_ui_text(prop, "Use as Depth Of Field", "Blur using camera depth of field");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
}
@@ -256,14 +258,14 @@ static void rna_def_shader_fx_colorize(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Factor", "Mix factor");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "low_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "low_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "low_color");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Low Color", "First color used for effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "high_color");
RNA_def_property_array(prop, 4);
@@ -334,17 +336,12 @@ static void rna_def_shader_fx_pixel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Size", "Pixel size");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rgba");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Color", "Color used for lines");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
-
- prop = RNA_def_property(srna, "use_lines", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_PIXEL_USE_LINES);
- RNA_def_property_ui_text(prop, "Lines", "Display lines between pixels");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
}
static void rna_def_shader_fx_rim(BlenderRNA *brna)
@@ -363,14 +360,14 @@ static void rna_def_shader_fx_rim(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Offset", "Offset of the rim");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "rim_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "rim_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "rim_rgb");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Rim Color", "Color used for Rim");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "mask_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "mask_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "mask_rgb");
RNA_def_property_array(prop, 3);
@@ -433,7 +430,7 @@ static void rna_def_shader_fx_shadow(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Scale", "Offset of the shadow");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "shadow_rgba");
RNA_def_property_array(prop, 4);
@@ -507,14 +504,21 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "GlowShaderFxData");
RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
- prop = RNA_def_property(srna, "glow_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "glow_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "glow_color");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Glow Color", "Color used for generated glow");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "select_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "glow_color[3]");
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Opacity", "Effect Opacity");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "select_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_float_sdna(prop, NULL, "select_color");
RNA_def_property_array(prop, 3);
@@ -534,13 +538,11 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Threshold", "Limit to select color for glow effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- /* Use blur fields to make compatible with blur filter,
- * but only makes public first array element. */
- prop = RNA_def_property(srna, "radius", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "blur[0]");
- RNA_def_property_range(prop, 0, SHRT_MAX);
- RNA_def_property_ui_text(
- prop, "Radius", "Number of pixels for blurring glow (set to 0 to disable)");
+ /* Use blur fields to make compatible with blur filter */
+ prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "blur");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Size", "Size of th effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
@@ -551,9 +553,23 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
- prop = RNA_def_property(srna, "use_alpha_mode", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_glow_under", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_GLOW_USE_ALPHA);
- RNA_def_property_ui_text(prop, "Use Alpha", "Glow only areas with alpha");
+ RNA_def_property_ui_text(
+ prop, "Glow Under", "Glow only areas with alpha (not supported with Regular blend mode)");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation of the effect");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
+
+ /* blend mode */
+ prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
+ RNA_def_property_enum_items(prop, rna_enum_glow_blend_modes_items);
+ RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
}
@@ -614,38 +630,6 @@ static void rna_def_shader_fx_flip(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
}
-static void rna_def_shader_fx_light(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "ShaderFxLight", "ShaderFx");
- RNA_def_struct_ui_text(srna, "Light Effect", "Light effect");
- RNA_def_struct_sdna(srna, "LightShaderFxData");
- RNA_def_struct_ui_icon(srna, ICON_SHADERFX);
-
- prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "energy");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 1, FLT_MAX, 1, 2);
- RNA_def_property_ui_text(prop, "Energy", "Strength of light source");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
-
- prop = RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "ambient");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, 2);
- RNA_def_property_ui_text(prop, "Ambient", "Strength of ambient light source");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
-
- prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "Object", "Object to determine light source location");
- RNA_def_property_pointer_funcs(prop, NULL, "rna_LightShaderFx_object_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update");
-}
-
void RNA_def_shader_fx(BlenderRNA *brna)
{
StructRNA *srna;
@@ -712,7 +696,6 @@ void RNA_def_shader_fx(BlenderRNA *brna)
rna_def_shader_fx_glow(brna);
rna_def_shader_fx_swirl(brna);
rna_def_shader_fx_flip(brna);
- rna_def_shader_fx_light(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 8123d02714a..02dd625c7e3 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1013,6 +1013,9 @@ static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA
}
}
+ /* Update Gpencil. */
+ rna_GPencil_update(bmain, scene, ptr);
+
bScreen *screen = (bScreen *)ptr->owner_id;
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
@@ -3289,7 +3292,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_View3DShading_color_type_itemf");
RNA_def_property_ui_text(prop, "Color", "Color Type");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
prop = RNA_def_property(srna, "wireframe_color_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "wire_color_type");
@@ -3782,8 +3785,8 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Annotation", "Show annotations for this view");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "use_gpencil_paper", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_PAPER);
+ prop = RNA_def_property(srna, "use_gpencil_fade_objects", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_FADE_OBJECTS);
RNA_def_property_ui_text(
prop,
"Fade Objects",
@@ -3801,12 +3804,26 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Fade Layers", "Toggle fading of Grease Pencil layers except the active one");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
- prop = RNA_def_property(srna, "use_gpencil_fade_objects", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_gpencil_fade_gp_objects", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_FADE_NOACTIVE_GPENCIL);
RNA_def_property_ui_text(
prop, "Fade Grease Pencil Objects", "Fade Grease Pencil Objects, except the active one");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_gpencil_show_directions", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_STROKE_DIRECTION);
+ RNA_def_property_ui_text(prop,
+ "Stroke Direction",
+ "Show stroke drawing direction with a bigger green dot (start) "
+ "and smaller red dot (end) points");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
+ prop = RNA_def_property(srna, "use_gpencil_show_material_name", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_MATERIAL_NAME);
+ RNA_def_property_ui_text(
+ prop, "Stroke Material Name", "Show material name assigned to each stroke");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "gpencil_grid_opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_opacity");
RNA_def_property_range(prop, 0.1f, 1.0f);
@@ -3814,7 +3831,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* Paper opacity factor */
- prop = RNA_def_property(srna, "gpencil_paper_opacity", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "gpencil_fade_objects", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_paper_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Fade factor");
@@ -3832,12 +3849,12 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
/* show edit lines */
prop = RNA_def_property(srna, "use_gpencil_edit_lines", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_EDIT_LINES);
- RNA_def_property_ui_text(prop, "Show Edit Lines", "Show edit lines when editing strokes");
+ RNA_def_property_ui_text(prop, "Show Edit Lines", "Show Edit Lines when editing strokes");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_gpencil_multiedit_line_only", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_MULTIEDIT_LINES);
- RNA_def_property_ui_text(prop, "Lines Only", "Only show edit lines for additional frames");
+ RNA_def_property_ui_text(prop, "Lines Only", "Show Edit Lines only in multiframe");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
/* main grease pencil onion switch */
@@ -3848,12 +3865,20 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
/* vertex opacity */
- prop = RNA_def_property(srna, "vertex_opacity", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "vertex_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "vertex_opacity");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Vertex Opacity", "Opacity for edit vertices");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update");
+
+ /* Vertex Paint opacity factor */
+ prop = RNA_def_property(srna, "gpencil_vertex_paint_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_vertex_paint_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Opacity", "Vertex Paint mix factor");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
}
static void rna_def_space_view3d(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 527df695f5b..8b112031ada 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -152,8 +152,10 @@ static void rna_uiItemR_with_popover(uiLayout *layout,
RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
}
- if (RNA_property_type(prop) != PROP_ENUM) {
- RNA_warning("property is not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ if ((RNA_property_type(prop) != PROP_ENUM) &&
+ !ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA)) {
+ RNA_warning(
+ "property is not an enum or color: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
}
int flag = 0;
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 566305ad1c7..7250f8a2d59 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -5082,15 +5082,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem multi_sample_levels[] = {
- {USER_MULTISAMPLE_NONE, "NONE", 0, "No MultiSample", "Do not use OpenGL MultiSample"},
- {USER_MULTISAMPLE_2, "2", 0, "MultiSample: 2", "Use 2x OpenGL MultiSample"},
- {USER_MULTISAMPLE_4, "4", 0, "MultiSample: 4", "Use 4x OpenGL MultiSample"},
- {USER_MULTISAMPLE_8, "8", 0, "MultiSample: 8", "Use 8x OpenGL MultiSample"},
- {USER_MULTISAMPLE_16, "16", 0, "MultiSample: 16", "Use 16x OpenGL MultiSample"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem image_draw_methods[] = {
{IMAGE_DRAW_METHOD_AUTO,
"AUTO",
@@ -5175,16 +5166,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Enable Edit-Mode edge smoothing, reducing aliasing, requires restart");
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
- /* grease pencil anti-aliasing */
- prop = RNA_def_property(srna, "gpencil_multi_sample", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_multisamples");
- RNA_def_property_enum_items(prop, multi_sample_levels);
- RNA_def_property_ui_text(
- prop,
- "Gpencil MultiSample",
- "Enable Grease Pencil OpenGL multi-sampling, only for systems that support it");
- RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP);
RNA_def_property_ui_text(
diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt
index 6d918763996..9835c5c0588 100644
--- a/source/blender/shader_fx/CMakeLists.txt
+++ b/source/blender/shader_fx/CMakeLists.txt
@@ -45,7 +45,6 @@ set(SRC
intern/FX_shader_colorize.c
intern/FX_shader_flip.c
intern/FX_shader_glow.c
- intern/FX_shader_light.c
intern/FX_shader_pixel.c
intern/FX_shader_rim.c
intern/FX_shader_shadow.c
diff --git a/source/blender/shader_fx/FX_shader_types.h b/source/blender/shader_fx/FX_shader_types.h
index 7a87c77f313..f338f9bcc2a 100644
--- a/source/blender/shader_fx/FX_shader_types.h
+++ b/source/blender/shader_fx/FX_shader_types.h
@@ -30,7 +30,6 @@ extern ShaderFxTypeInfo shaderfx_Type_Blur;
extern ShaderFxTypeInfo shaderfx_Type_Colorize;
extern ShaderFxTypeInfo shaderfx_Type_Flip;
extern ShaderFxTypeInfo shaderfx_Type_Glow;
-extern ShaderFxTypeInfo shaderfx_Type_Light;
extern ShaderFxTypeInfo shaderfx_Type_Pixel;
extern ShaderFxTypeInfo shaderfx_Type_Rim;
extern ShaderFxTypeInfo shaderfx_Type_Shadow;
diff --git a/source/blender/shader_fx/intern/FX_shader_blur.c b/source/blender/shader_fx/intern/FX_shader_blur.c
index 72d2a61dafd..e98205897aa 100644
--- a/source/blender/shader_fx/intern/FX_shader_blur.c
+++ b/source/blender/shader_fx/intern/FX_shader_blur.c
@@ -23,6 +23,7 @@
#include <stdio.h>
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "FX_shader_types.h"
@@ -30,9 +31,9 @@
static void initData(ShaderFxData *fx)
{
BlurShaderFxData *gpfx = (BlurShaderFxData *)fx;
- ARRAY_SET_ITEMS(gpfx->radius, 1, 1);
- gpfx->samples = 4;
- gpfx->coc = 0.025f;
+ copy_v2_fl(gpfx->radius, 50.0f);
+ gpfx->samples = 8;
+ gpfx->rotation = 0.0f;
}
static void copyData(const ShaderFxData *md, ShaderFxData *target)
@@ -45,7 +46,7 @@ ShaderFxTypeInfo shaderfx_Type_Blur = {
/* structName */ "BlurShaderFxData",
/* structSize */ sizeof(BlurShaderFxData),
/* type */ eShaderFxType_GpencilType,
- /* flags */ eShaderFxTypeFlag_Single,
+ /* flags */ 0,
/* copyData */ copyData,
diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c
index 804b194ed68..41ca903ee08 100644
--- a/source/blender/shader_fx/intern/FX_shader_flip.c
+++ b/source/blender/shader_fx/intern/FX_shader_flip.c
@@ -47,7 +47,7 @@ ShaderFxTypeInfo shaderfx_Type_Flip = {
/* structName */ "FlipShaderFxData",
/* structSize */ sizeof(FlipShaderFxData),
/* type */ eShaderFxType_GpencilType,
- /* flags */ eShaderFxTypeFlag_Single,
+ /* flags */ 0,
/* copyData */ copyData,
diff --git a/source/blender/shader_fx/intern/FX_shader_glow.c b/source/blender/shader_fx/intern/FX_shader_glow.c
index 1b1e4dc9d94..8924a1ab8b9 100644
--- a/source/blender/shader_fx/intern/FX_shader_glow.c
+++ b/source/blender/shader_fx/intern/FX_shader_glow.c
@@ -27,6 +27,7 @@
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_modifier.h"
@@ -37,12 +38,11 @@
static void initData(ShaderFxData *md)
{
GlowShaderFxData *gpfx = (GlowShaderFxData *)md;
- ARRAY_SET_ITEMS(gpfx->glow_color, 0.75f, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gpfx->glow_color, 0.75f, 1.0f, 1.0f, 1.0f);
ARRAY_SET_ITEMS(gpfx->select_color, 0.0f, 0.0f, 0.0f);
+ copy_v2_fl(gpfx->blur, 50.0f);
gpfx->threshold = 0.1f;
-
- ARRAY_SET_ITEMS(gpfx->blur, 50, 0);
- gpfx->samples = 16;
+ gpfx->samples = 8;
}
static void copyData(const ShaderFxData *md, ShaderFxData *target)
diff --git a/source/blender/shader_fx/intern/FX_shader_pixel.c b/source/blender/shader_fx/intern/FX_shader_pixel.c
index e0ea111d121..f39649bba07 100644
--- a/source/blender/shader_fx/intern/FX_shader_pixel.c
+++ b/source/blender/shader_fx/intern/FX_shader_pixel.c
@@ -44,7 +44,7 @@ ShaderFxTypeInfo shaderfx_Type_Pixel = {
/* structName */ "PixelShaderFxData",
/* structSize */ sizeof(PixelShaderFxData),
/* type */ eShaderFxType_GpencilType,
- /* flags */ eShaderFxTypeFlag_Single,
+ /* flags */ 0,
/* copyData */ copyData,
diff --git a/source/blender/shader_fx/intern/FX_shader_rim.c b/source/blender/shader_fx/intern/FX_shader_rim.c
index d16210918fc..a81d2ff2a09 100644
--- a/source/blender/shader_fx/intern/FX_shader_rim.c
+++ b/source/blender/shader_fx/intern/FX_shader_rim.c
@@ -35,7 +35,7 @@ static void initData(ShaderFxData *fx)
ARRAY_SET_ITEMS(gpfx->offset, 50, -100);
ARRAY_SET_ITEMS(gpfx->rim_rgb, 1.0f, 1.0f, 0.5f);
ARRAY_SET_ITEMS(gpfx->mask_rgb, 0.0f, 0.0f, 0.0f);
- gpfx->mode = eShaderFxRimMode_Multiply;
+ gpfx->mode = eShaderFxRimMode_Overlay;
ARRAY_SET_ITEMS(gpfx->blur, 0, 0);
gpfx->samples = 2;
diff --git a/source/blender/shader_fx/intern/FX_shader_shadow.c b/source/blender/shader_fx/intern/FX_shader_shadow.c
index 0ee45a0bd51..aa9da5ae9f1 100644
--- a/source/blender/shader_fx/intern/FX_shader_shadow.c
+++ b/source/blender/shader_fx/intern/FX_shader_shadow.c
@@ -44,7 +44,7 @@ static void initData(ShaderFxData *md)
gpfx->rotation = 0.0f;
ARRAY_SET_ITEMS(gpfx->offset, 15, 20);
ARRAY_SET_ITEMS(gpfx->scale, 1.0f, 1.0f);
- ARRAY_SET_ITEMS(gpfx->shadow_rgba, 0.54f, 0.62f, 1.0f, 0.9f);
+ ARRAY_SET_ITEMS(gpfx->shadow_rgba, 0.0f, 0.0f, 0.0f, 0.8f);
gpfx->amplitude = 10.0f;
gpfx->period = 20.0f;
diff --git a/source/blender/shader_fx/intern/FX_shader_util.c b/source/blender/shader_fx/intern/FX_shader_util.c
index 908a2b249b8..c2dcae04b85 100644
--- a/source/blender/shader_fx/intern/FX_shader_util.c
+++ b/source/blender/shader_fx/intern/FX_shader_util.c
@@ -39,7 +39,6 @@ void shaderfx_type_init(ShaderFxTypeInfo *types[])
INIT_FX_TYPE(Colorize);
INIT_FX_TYPE(Flip);
INIT_FX_TYPE(Glow);
- INIT_FX_TYPE(Light);
INIT_FX_TYPE(Pixel);
INIT_FX_TYPE(Rim);
INIT_FX_TYPE(Shadow);
diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c
index 334024bbd3f..35d2e515f76 100644
--- a/source/blender/shader_fx/intern/FX_shader_wave.c
+++ b/source/blender/shader_fx/intern/FX_shader_wave.c
@@ -50,7 +50,7 @@ ShaderFxTypeInfo shaderfx_Type_Wave = {
/* structName */ "WaveShaderFxData",
/* structSize */ sizeof(WaveShaderFxData),
/* type */ eShaderFxType_GpencilType,
- /* flags */ eShaderFxTypeFlag_Single,
+ /* flags */ 0,
/* copyData */ copyData,
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 6e494280820..307ad444ffd 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -170,6 +170,9 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
case CTX_MODE_WEIGHT_GPENCIL:
km_id = "Grease Pencil Stroke Weight Mode";
break;
+ case CTX_MODE_VERTEX_GPENCIL:
+ km_id = "Grease Pencil Stroke Vertex Mode";
+ break;
}
}
else if (sl->spacetype == SPACE_IMAGE) {
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index e335800636c..e721fd21b88 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -172,37 +172,7 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre
if (tref_rt->data_block[0]) {
Main *bmain = CTX_data_main(C);
- if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_SCULPT_GPENCIL)) {
- const EnumPropertyItem *items = rna_enum_gpencil_sculpt_brush_items;
- const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
- if (i != -1) {
- const int value = items[i].value;
- wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- if (workspace == WM_window_get_active_workspace(win)) {
- Scene *scene = WM_window_get_active_scene(win);
- ToolSettings *ts = scene->toolsettings;
- ts->gp_sculpt.brushtype = value;
- }
- }
- }
- }
- else if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_WEIGHT_GPENCIL)) {
- const EnumPropertyItem *items = rna_enum_gpencil_weight_brush_items;
- const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
- if (i != -1) {
- const int value = items[i].value;
- wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- if (workspace == WM_window_get_active_workspace(win)) {
- Scene *scene = WM_window_get_active_scene(win);
- ToolSettings *ts = scene->toolsettings;
- ts->gp_sculpt.weighttype = value;
- }
- }
- }
- }
- else if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE)) {
+ if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE)) {
const EnumPropertyItem *items = rna_enum_particle_edit_hair_brush_items;
const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
if (i != -1) {
@@ -414,29 +384,7 @@ void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToo
if (ob == NULL) {
/* pass */
}
- else if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_SCULPT_GPENCIL)) {
- if (ob->mode & OB_MODE_SCULPT_GPENCIL) {
- const EnumPropertyItem *items = rna_enum_gpencil_sculpt_brush_items;
- const int i = RNA_enum_from_value(items, ts->gp_sculpt.brushtype);
- const EnumPropertyItem *item = &items[i];
- if (!STREQ(tref_rt->data_block, item->identifier)) {
- STRNCPY(tref_rt->data_block, item->identifier);
- SNPRINTF(tref->idname, "builtin_brush.%s", item->name);
- }
- }
- }
- else if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_WEIGHT_GPENCIL)) {
- if (ob->mode & OB_MODE_WEIGHT_GPENCIL) {
- const EnumPropertyItem *items = rna_enum_gpencil_weight_brush_items;
- const int i = RNA_enum_from_value(items, ts->gp_sculpt.weighttype);
- const EnumPropertyItem *item = &items[i];
- if (!STREQ(tref_rt->data_block, item->identifier)) {
- STRNCPY(tref_rt->data_block, item->identifier);
- SNPRINTF(tref->idname, "builtin_brush.%s", item->name);
- }
- }
- }
- else if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE)) {
+ if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE)) {
if (ob->mode & OB_MODE_PARTICLE_EDIT) {
const EnumPropertyItem *items = rna_enum_particle_edit_hair_brush_items;
const int i = RNA_enum_from_value(items, ts->particle.brushtype);
@@ -735,6 +683,8 @@ static const char *toolsystem_default_tool(const bToolKey *tkey)
return "builtin_brush.Push";
case CTX_MODE_WEIGHT_GPENCIL:
return "builtin_brush.Weight";
+ case CTX_MODE_VERTEX_GPENCIL:
+ return "builtin_brush.Draw";
/* end temporary hack. */
case CTX_MODE_PARTICLE: